diff --git a/cmd/rpcdaemon/commands/daemon.go b/cmd/rpcdaemon/commands/daemon.go index ad62b32d3..7345aeeac 100644 --- a/cmd/rpcdaemon/commands/daemon.go +++ b/cmd/rpcdaemon/commands/daemon.go @@ -2,11 +2,16 @@ package commands import ( "context" + "encoding/binary" "fmt" + "net" "os" "os/signal" "strings" + "github.com/ledgerwatch/turbo-geth/common" + "github.com/ledgerwatch/turbo-geth/common/dbutils" + "github.com/ledgerwatch/turbo-geth/ethdb/remote" "github.com/ledgerwatch/turbo-geth/log" "github.com/ledgerwatch/turbo-geth/rpc" ) @@ -26,14 +31,62 @@ type EthAPI interface { BlockNumber(ctx context.Context) (uint64, error) } -// EthAPIImpl is implementation of the EthAPI interface based on remote Db access -type EthAPIImpl struct { +// APIImpl is implementation of the EthAPI interface based on remote Db access +type APIImpl struct { remoteDbAdddress string + db *remote.DB +} + +func (api *APIImpl) ensureConnected() error { + if api.db == nil { + conn, err := net.Dial("tcp", api.remoteDbAdddress) + if err != nil { + return err + } + api.db, err = remote.NewDB(conn, conn, conn) + if err != nil { + return err + } + } + return nil +} + +// ConnectAPIImpl connects to the remote DB and returns APIImpl instance +func ConnectAPIImpl(remoteDbAdddress string) (*APIImpl, error) { + return &APIImpl{remoteDbAdddress: remoteDbAdddress}, nil } // BlockNumber returns the currently highest block number available in the remote db -func (api *EthAPIImpl) BlockNumber(ctx context.Context) (uint64, error) { - return 0, nil +func (api *APIImpl) BlockNumber(ctx context.Context) (uint64, error) { + if err := api.ensureConnected(); err != nil { + return 0, err + } + var blockNumber uint64 + if err := api.db.View(func(tx *remote.Tx) error { + b := tx.Bucket(dbutils.HeadHeaderKey) + if b == nil { + return fmt.Errorf("bucket %s not found", dbutils.HeadHeaderKey) + } + blockHashData := b.Get(dbutils.HeadHeaderKey) + if len(blockHashData) != common.HashLength { + return fmt.Errorf("head header hash not found or wrong size: %x", blockHashData) + } + b1 := tx.Bucket(dbutils.HeaderNumberPrefix) + if b1 == nil { + return fmt.Errorf("bucket %s not found", dbutils.HeaderNumberPrefix) + } + blockNumberData := b1.Get(blockHashData) + if len(blockNumberData) != 8 { + return fmt.Errorf("head block number not found or wrong size: %x", blockNumberData) + } + blockNumber = binary.BigEndian.Uint64(blockNumberData) + return nil + }); err != nil { + api.db.Close() + api.db = nil + return 0, err + } + return blockNumber, nil } func daemon(cfg Config) { @@ -41,14 +94,20 @@ func daemon(cfg Config) { cors := splitAndTrim(cfg.rpcCORSDomain) enabledApis := splitAndTrim(cfg.rpcAPI) var rpcAPI = []rpc.API{} + apiImpl, err := ConnectAPIImpl(cfg.remoteDbAdddress) + if err != nil { + log.Error("Could not connect to remoteDb", "error", err) + return + } for _, enabledAPI := range enabledApis { switch enabledAPI { case "eth": - var ethAPI EthAPI = &EthAPIImpl{remoteDbAdddress: cfg.remoteDbAdddress} + var api EthAPI + api = apiImpl rpcAPI = append(rpcAPI, rpc.API{ Namespace: "eth", Public: true, - Service: ethAPI, + Service: api, Version: "1.0", }) default: @@ -56,7 +115,7 @@ func daemon(cfg Config) { } } httpEndpoint := fmt.Sprintf("%s:%d", cfg.rpcListenAddress, cfg.rpcPort) - listener, _, err := rpc.StartHTTPEndpoint(httpEndpoint, rpcAPI, []string{"test", "eth", "debug", "web3"}, cors, vhosts, rpc.DefaultHTTPTimeouts) + listener, _, err := rpc.StartHTTPEndpoint(httpEndpoint, rpcAPI, enabledApis, cors, vhosts, rpc.DefaultHTTPTimeouts) if err != nil { log.Error("Could not start RPC api", "error", err) return