Skip to content

Commit

Permalink
Add JSON-RPC logic
Browse files Browse the repository at this point in the history
  • Loading branch information
zivkovicmilos committed Dec 27, 2023
1 parent 974f088 commit 5390d58
Show file tree
Hide file tree
Showing 23 changed files with 961 additions and 38 deletions.
2 changes: 1 addition & 1 deletion cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ func main() {
// Create the root command
cmd := &ffcli.Command{
ShortUsage: "<subcommand> [flags] [<arg>...]",
LongHelp: "The Gno / TM2 faucet service",
LongHelp: "The TM2 indexer service",
FlagSet: fs,
Exec: func(_ context.Context, _ []string) error {
return flag.ErrHelp
Expand Down
2 changes: 1 addition & 1 deletion cmd/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ func newStartCmd() *ffcli.Command {
return &ffcli.Command{
Name: "start",
ShortUsage: "start [flags]",
LongHelp: "Starts the transaction indexer",
LongHelp: "Starts the indexer",
FlagSet: fs,
Exec: cfg.exec,
}
Expand Down
36 changes: 0 additions & 36 deletions events/subscription_test.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
package events

import (
"context"
"errors"
"testing"
"time"

"github.com/stretchr/testify/assert"
)
Expand Down Expand Up @@ -53,36 +50,3 @@ func TestSubscription_EventSupported(t *testing.T) {
})
}
}

// retryUntilTimeout retries the callback until it returns false,
// otherwise it times out when the context is cancelled
func retryUntilTimeout(ctx context.Context, t *testing.T, cb func() bool) error {
t.Helper()

resCh := make(chan error, 1)

go func() {
defer close(resCh)

for {
select {
case <-ctx.Done():
resCh <- errors.New("timeout")

return
default:
retry := cb()

if !retry {
resCh <- nil

return
}
}

time.Sleep(time.Millisecond * 100)
}
}()

return <-resCh
}
1 change: 1 addition & 0 deletions fetch/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ type Storage interface {
// GetLatestSavedHeight returns the latest block height from the storage
GetLatestSavedHeight(ctx context.Context) (int64, error)

// SaveBlock saves the block to the permanent storage
SaveBlock(ctx context.Context, block *types.Block) error

// SaveTx saves the transaction to the permanent storage
Expand Down
5 changes: 5 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@ module github.com/gnolang/tx-indexer
go 1.21

require (
github.com/go-chi/chi/v5 v5.0.11
github.com/google/uuid v1.5.0
github.com/olahol/melody v1.1.4
github.com/peterbourgon/ff/v3 v3.4.0
github.com/stretchr/testify v1.8.4
go.uber.org/zap v1.26.0
)

require (
Expand All @@ -22,6 +25,7 @@ require (
github.com/golang/protobuf v1.5.3 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/flatbuffers v1.12.1 // indirect
github.com/gorilla/websocket v1.5.1 // indirect
github.com/jmhodges/levigo v1.0.0 // indirect
github.com/klauspost/compress v1.12.3 // indirect
github.com/libp2p/go-buffer-pool v0.1.0 // indirect
Expand All @@ -31,6 +35,7 @@ require (
github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect
go.etcd.io/bbolt v1.3.8 // indirect
go.opencensus.io v0.22.5 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/mod v0.14.0 // indirect
golang.org/x/net v0.17.0 // indirect
golang.org/x/sys v0.14.0 // indirect
Expand Down
12 changes: 12 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ github.com/gnolang/goleveldb v0.0.9 h1:Q7rGko9oXMKtQA+Apeeed5a3sjba/mcDhzJGoTVLC
github.com/gnolang/goleveldb v0.0.9/go.mod h1:Dz6p9bmpy/FBESTgduiThZt5mToVDipcHGzj/zUOo8E=
github.com/gnolang/overflow v0.0.0-20170615021017-4d914c927216 h1:GKvsK3oLWG9B1GL7WP/VqwM6C92j5tIvB844oggL9Lk=
github.com/gnolang/overflow v0.0.0-20170615021017-4d914c927216/go.mod h1:xJhtEL7ahjM1WJipt89gel8tHzfIl/LyMY+lCYh38d8=
github.com/go-chi/chi/v5 v5.0.11 h1:BnpYbFZ3T3S1WMpD79r7R5ThWX40TaFB7L31Y8xqSwA=
github.com/go-chi/chi/v5 v5.0.11/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
Expand Down Expand Up @@ -107,6 +109,8 @@ github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU=
github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
Expand Down Expand Up @@ -138,6 +142,8 @@ github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY=
github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc=
github.com/olahol/melody v1.1.4 h1:RQHfKZkQmDxI0+SLZRNBCn4LiXdqxLKRGSkT8Dyoe/E=
github.com/olahol/melody v1.1.4/go.mod h1:GgkTl6Y7yWj/HtfD48Q5vLKPVoZOH+Qqgfa7CvJgJM4=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
Expand Down Expand Up @@ -184,6 +190,12 @@ go.etcd.io/bbolt v1.3.8 h1:xs88BrvEv273UsB79e0hcVrlUWmS0a8upikMFhSyAtA=
go.etcd.io/bbolt v1.3.8/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw=
go.opencensus.io v0.22.5 h1:dntmOdLpSpHlVqbW5Eay97DelsZHe+55D+xC6i0dDS0=
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo=
go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so=
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
Expand Down
25 changes: 25 additions & 0 deletions serve/conns/connection.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package conns

import (
"github.com/olahol/melody"
)

// ConnectionManager defines a connection manager interface
// for active WS connections
type ConnectionManager interface {
// AddWSConnection registers a new WS connection
AddWSConnection(id string, session *melody.Session)

// RemoveWSConnection Removes the WS connection with the supplied ID
RemoveWSConnection(id string)

// GetWSConnection fetches a WS connection, if any, using the supplied ID
GetWSConnection(id string) WSConnection
}

// WSConnection represents a single WS connection
type WSConnection interface {
// WriteData pushes out data to the WS connection.
// Returns an error if the write failed (ex. connection closed)
WriteData(data any) error
}
96 changes: 96 additions & 0 deletions serve/conns/wsconn/ws_conns.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package wsconn

import (
"context"
"fmt"
"sync"

"github.com/gnolang/tx-indexer/serve/conns"
"github.com/gnolang/tx-indexer/serve/writer"
"github.com/gnolang/tx-indexer/serve/writer/ws"
"github.com/olahol/melody"
"go.uber.org/zap"
)

// Conns manages active WS connections
type Conns struct {
logger *zap.Logger
conns map[string]Conn // ws connection ID -> conn

mux sync.RWMutex
}

// NewConns creates a new instance of the WS connection manager
func NewConns(logger *zap.Logger) *Conns {
return &Conns{
logger: logger,
conns: make(map[string]Conn),
}
}

// AddWSConnection registers a new WS connection
func (pw *Conns) AddWSConnection(id string, session *melody.Session) {
pw.mux.Lock()
defer pw.mux.Unlock()

ctx, cancelFn := context.WithCancel(context.Background())

pw.conns[id] = Conn{
ctx: ctx,
cancelFn: cancelFn,
writer: ws.New(
pw.logger.Named(
fmt.Sprintf("ws-%s", id),
),
session,
),
}
}

// RemoveWSConnection removes an existing WS connection
func (pw *Conns) RemoveWSConnection(id string) {
pw.mux.Lock()
defer pw.mux.Unlock()

conn, found := pw.conns[id]
if !found {
return
}

// Cancel the connection context
conn.cancelFn()

delete(pw.conns, id)
}

// GetWSConnection fetches a WS connection, if any
func (pw *Conns) GetWSConnection(id string) conns.WSConnection {
pw.mux.RLock()
defer pw.mux.RUnlock()

conn, found := pw.conns[id]
if !found {
return nil
}

return &conn
}

// Conn is a single WS connection
type Conn struct {
ctx context.Context
cancelFn context.CancelFunc

writer writer.ResponseWriter
}

// WriteData writes arbitrary data to the WS connection
func (c *Conn) WriteData(data any) error {
if c.ctx.Err() != nil {
return c.ctx.Err()
}

c.writer.WriteResponse(data)

return nil
}
27 changes: 27 additions & 0 deletions serve/handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package serve

import (
"github.com/gnolang/tx-indexer/serve/metadata"
"github.com/gnolang/tx-indexer/serve/spec"
)

// Handler executes a method with accompanying
// data such as metadata and params
type Handler func(metadata *metadata.Metadata, params []any) (any, *spec.BaseJSONError)

type handlers map[string]Handler

// newHandlers creates a new map of method handlers
func newHandlers() handlers {
return make(handlers)
}

// addHandler adds a new method handler for the specified method name
func (h handlers) addHandler(method string, handler Handler) {
h[method] = handler
}

// removeHandler removes the method handler for the specified method, if any
func (h handlers) removeHandler(method string) {
delete(h, method)
}
58 changes: 58 additions & 0 deletions serve/handlers/block/block.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package block

import (
"strconv"

"github.com/gnolang/gno/tm2/pkg/bft/types"
"github.com/gnolang/tx-indexer/serve/metadata"
"github.com/gnolang/tx-indexer/serve/spec"
)

type Handler struct {
storage Storage
}

func NewHandler(storage Storage) *Handler {
return &Handler{
storage: storage,
}
}

func (h *Handler) GetBlockHandler(
_ *metadata.Metadata,
params []any,
) (any, *spec.BaseJSONError) {
// Check the params
if len(params) < 1 {
return nil, spec.GenerateInvalidParamCountError()
}

// Extract the params
requestedBlock, ok := params[0].(string)
if !ok {
return nil, spec.GenerateInvalidParamError(1)
}

blockNum, err := strconv.ParseInt(requestedBlock, 10, 64)
if err != nil {
return nil, spec.GenerateInvalidParamError(1)
}

// Run the handler
response, err := h.getBlock(blockNum)
if err != nil {
return nil, spec.GenerateResponseError(err)
}

return response, nil
}

// getBlock fetches the block from storage, if any
func (h *Handler) getBlock(blockNum int64) (*types.Block, error) {
block, err := h.storage.GetBlock(blockNum)
if err != nil {
return nil, err
}

return block, nil
}
10 changes: 10 additions & 0 deletions serve/handlers/block/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package block

import (
"github.com/gnolang/gno/tm2/pkg/bft/types"
)

type Storage interface {
// GetBlock returns specified block from permanent storage
GetBlock(int64) (*types.Block, error)
}
Loading

0 comments on commit 5390d58

Please sign in to comment.