From b2ba410ba54356be1e67bcdafdf6914c1944d7d4 Mon Sep 17 00:00:00 2001 From: Alexey Akhunov Date: Thu, 28 Nov 2019 22:51:09 +0000 Subject: [PATCH 01/11] Add remoteDb listener and RPC daemon CLI --- cmd/state/commands/root.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cmd/state/commands/root.go b/cmd/state/commands/root.go index 7c922a544..ffe0ed3a1 100644 --- a/cmd/state/commands/root.go +++ b/cmd/state/commands/root.go @@ -34,6 +34,10 @@ var rootCmd = &cobra.Command{ PersistentPostRun: func(cmd *cobra.Command, args []string) { stopProfilingIfNeeded() }, + RunE: func(cmd *cobra.Command, args []string) error { + stateless.GasLimits(chaindata) + return nil + }, } func Execute() { From 2026f74f0414409eba10a86f6ae6bc7b0b06b507 Mon Sep 17 00:00:00 2001 From: Alexey Akhunov Date: Fri, 29 Nov 2019 08:13:48 +0000 Subject: [PATCH 02/11] Fix CLI --- cmd/rpcdaemon/commands/daemon.go | 77 ++++---------------------------- cmd/rpcdaemon/commands/root.go | 2 +- cmd/state/commands/root.go | 4 -- 3 files changed, 10 insertions(+), 73 deletions(-) diff --git a/cmd/rpcdaemon/commands/daemon.go b/cmd/rpcdaemon/commands/daemon.go index 746c2a97d..16d2dd8b3 100644 --- a/cmd/rpcdaemon/commands/daemon.go +++ b/cmd/rpcdaemon/commands/daemon.go @@ -2,16 +2,11 @@ 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" ) @@ -31,83 +26,29 @@ type EthAPI interface { BlockNumber(ctx context.Context) (uint64, error) } -// APIImpl is implementation of the EthAPI interface based on remote Db access -type APIImpl struct { +// EthAPIImpl is implementation of the EthAPI interface based on remote Db access +type EthAPIImpl 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 *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 (api *EthAPIImpl) BlockNumber(ctx context.Context) (uint64, error) { + return 0, nil } -func daemon(cfg Config) { +func daemon(config Config) { vhosts := splitAndTrim(cfg.rpcVirtualHost) 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 api EthAPI - api = apiImpl + var ethAPI EthAPI = &EthAPIImpl{remoteDbAdddress: cfg.remoteDbAdddress} rpcAPI = append(rpcAPI, rpc.API{ Namespace: "eth", Public: true, - Service: api, + Service: ethAPI, Version: "1.0", }) default: @@ -115,7 +56,7 @@ func daemon(cfg Config) { } } httpEndpoint := fmt.Sprintf("%s:%d", cfg.rpcListenAddress, cfg.rpcPort) - listener, _, err := rpc.StartHTTPEndpoint(httpEndpoint, rpcAPI, enabledApis, cors, vhosts, rpc.DefaultHTTPTimeouts) + listener, _, err := rpc.StartHTTPEndpoint(httpEndpoint, rpcAPI, []string{"test", "eth", "debug", "web3"}, cors, vhosts, rpc.DefaultHTTPTimeouts) if err != nil { log.Error("Could not start RPC api", "error", err) return @@ -128,7 +69,7 @@ func daemon(cfg Config) { log.Info("HTTP endpoint closed", "url", httpEndpoint) }() - abortChan := make(chan os.Signal, 1) + abortChan := make(chan os.Signal) signal.Notify(abortChan, os.Interrupt) sig := <-abortChan diff --git a/cmd/rpcdaemon/commands/root.go b/cmd/rpcdaemon/commands/root.go index f1cfc7c4e..e0f0378e8 100644 --- a/cmd/rpcdaemon/commands/root.go +++ b/cmd/rpcdaemon/commands/root.go @@ -33,7 +33,7 @@ var ( func init() { rootCmd.PersistentFlags().StringVar(&cpuprofile, "cpuprofile", "", "write cpu profile `file`") - rootCmd.PersistentFlags().StringVar(&memprofile, "memprofile", "", "write memory profile `file`") + rootCmd.PersistentFlags().StringVar(&cpuprofile, "memprofile", "", "write memory profile `file`") rootCmd.Flags().StringVar(&cfg.remoteDbAdddress, "remote-db-addr", "localhost:9999", "address of remote DB listener of a turbo-geth node") rootCmd.Flags().StringVar(&cfg.rpcListenAddress, "rpcaddr", node.DefaultHTTPHost, "HTTP-RPC server listening interface") rootCmd.Flags().IntVar(&cfg.rpcPort, "rpcport", node.DefaultHTTPPort, "HTTP-RPC server listening port") diff --git a/cmd/state/commands/root.go b/cmd/state/commands/root.go index ffe0ed3a1..7c922a544 100644 --- a/cmd/state/commands/root.go +++ b/cmd/state/commands/root.go @@ -34,10 +34,6 @@ var rootCmd = &cobra.Command{ PersistentPostRun: func(cmd *cobra.Command, args []string) { stopProfilingIfNeeded() }, - RunE: func(cmd *cobra.Command, args []string) error { - stateless.GasLimits(chaindata) - return nil - }, } func Execute() { From 95ca76e440367d60dfd93745ced0a016d998f189 Mon Sep 17 00:00:00 2001 From: Alexey Akhunov Date: Fri, 29 Nov 2019 08:29:23 +0000 Subject: [PATCH 03/11] Fix lint --- cmd/rpcdaemon/commands/daemon.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/rpcdaemon/commands/daemon.go b/cmd/rpcdaemon/commands/daemon.go index 16d2dd8b3..ad62b32d3 100644 --- a/cmd/rpcdaemon/commands/daemon.go +++ b/cmd/rpcdaemon/commands/daemon.go @@ -36,7 +36,7 @@ func (api *EthAPIImpl) BlockNumber(ctx context.Context) (uint64, error) { return 0, nil } -func daemon(config Config) { +func daemon(cfg Config) { vhosts := splitAndTrim(cfg.rpcVirtualHost) cors := splitAndTrim(cfg.rpcCORSDomain) enabledApis := splitAndTrim(cfg.rpcAPI) From 335ef77249b34110a7c95b80d6625c068cbd4c5e Mon Sep 17 00:00:00 2001 From: Alexey Akhunov Date: Fri, 29 Nov 2019 12:00:46 +0000 Subject: [PATCH 04/11] First working RPC command eth_blockNumber --- cmd/rpcdaemon/commands/daemon.go | 73 +++++++++++++++++++++++++++++--- 1 file changed, 66 insertions(+), 7 deletions(-) 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 From 1cd328d15203b5006eedd92f52c0c7d2c383f6ac Mon Sep 17 00:00:00 2001 From: Alexey Akhunov Date: Fri, 29 Nov 2019 12:05:52 +0000 Subject: [PATCH 05/11] Fix lint --- cmd/rpcdaemon/commands/daemon.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/rpcdaemon/commands/daemon.go b/cmd/rpcdaemon/commands/daemon.go index 7345aeeac..746c2a97d 100644 --- a/cmd/rpcdaemon/commands/daemon.go +++ b/cmd/rpcdaemon/commands/daemon.go @@ -128,7 +128,7 @@ func daemon(cfg Config) { log.Info("HTTP endpoint closed", "url", httpEndpoint) }() - abortChan := make(chan os.Signal) + abortChan := make(chan os.Signal, 1) signal.Notify(abortChan, os.Interrupt) sig := <-abortChan From f7b6b524fe1f3410519d13f48070cccdf6a3aaad Mon Sep 17 00:00:00 2001 From: Alexey Akhunov Date: Sat, 30 Nov 2019 19:50:14 +0000 Subject: [PATCH 06/11] Fix memprofile/cpuprofile confusion --- cmd/rpcdaemon/commands/root.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/rpcdaemon/commands/root.go b/cmd/rpcdaemon/commands/root.go index e0f0378e8..f1cfc7c4e 100644 --- a/cmd/rpcdaemon/commands/root.go +++ b/cmd/rpcdaemon/commands/root.go @@ -33,7 +33,7 @@ var ( func init() { rootCmd.PersistentFlags().StringVar(&cpuprofile, "cpuprofile", "", "write cpu profile `file`") - rootCmd.PersistentFlags().StringVar(&cpuprofile, "memprofile", "", "write memory profile `file`") + rootCmd.PersistentFlags().StringVar(&memprofile, "memprofile", "", "write memory profile `file`") rootCmd.Flags().StringVar(&cfg.remoteDbAdddress, "remote-db-addr", "localhost:9999", "address of remote DB listener of a turbo-geth node") rootCmd.Flags().StringVar(&cfg.rpcListenAddress, "rpcaddr", node.DefaultHTTPHost, "HTTP-RPC server listening interface") rootCmd.Flags().IntVar(&cfg.rpcPort, "rpcport", node.DefaultHTTPPort, "HTTP-RPC server listening port") From 570d3b79d7bdf5e281dc82001099eb7ebe9a8cc7 Mon Sep 17 00:00:00 2001 From: "alex.sharov" Date: Sun, 1 Dec 2019 16:52:11 +0700 Subject: [PATCH 07/11] initial implementation of eth_GetBlockByNumber, for now I did copy much functions from eth source because we may need max flexibility for benchmarks of rpcdaemon --- cmd/rpcdaemon/commands/daemon.go | 137 +++++++++++++++++++++++++++++++ cmd/rpcdaemon/test.http | 18 ++++ 2 files changed, 155 insertions(+) create mode 100644 cmd/rpcdaemon/test.http diff --git a/cmd/rpcdaemon/commands/daemon.go b/cmd/rpcdaemon/commands/daemon.go index 746c2a97d..fecdc8680 100644 --- a/cmd/rpcdaemon/commands/daemon.go +++ b/cmd/rpcdaemon/commands/daemon.go @@ -1,6 +1,7 @@ package commands import ( + "bytes" "context" "encoding/binary" "fmt" @@ -11,8 +12,11 @@ import ( "github.com/ledgerwatch/turbo-geth/common" "github.com/ledgerwatch/turbo-geth/common/dbutils" + "github.com/ledgerwatch/turbo-geth/core/types" "github.com/ledgerwatch/turbo-geth/ethdb/remote" + "github.com/ledgerwatch/turbo-geth/internal/ethapi" "github.com/ledgerwatch/turbo-geth/log" + "github.com/ledgerwatch/turbo-geth/rlp" "github.com/ledgerwatch/turbo-geth/rpc" ) @@ -29,6 +33,7 @@ func splitAndTrim(input string) []string { // EthAPI is a collection of functions that are exposed in the type EthAPI interface { BlockNumber(ctx context.Context) (uint64, error) + GetBlockByNumber(ctx context.Context, number rpc.BlockNumber, fullTx bool) (map[string]interface{}, error) } // APIImpl is implementation of the EthAPI interface based on remote Db access @@ -89,6 +94,138 @@ func (api *APIImpl) BlockNumber(ctx context.Context) (uint64, error) { return blockNumber, nil } +// GetBlockByNumber see https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getblockbynumber +// see internal/ethapi.PublicBlockChainAPI.GetBlockByNumber +func (api *APIImpl) GetBlockByNumber(ctx context.Context, number rpc.BlockNumber, fullTx bool) (map[string]interface{}, error) { + if err := api.ensureConnected(); err != nil { + return nil, err + } + + var block *types.Block + + if err := api.db.View(func(tx *remote.Tx) error { + block = GetBlockByNumber(tx, uint64(number.Int64())) + return nil + }); err != nil { + api.db.Close() + api.db = nil + return nil, err + } + fmt.Printf("Debug: %#v %#v %#v\n", block.Number(), block.Hash(), block.Size()) + + if block != nil { + response, err := api.rpcMarshalBlock(block, true, fullTx) + if err == nil && number == rpc.PendingBlockNumber { + // Pending blocks need to nil out a few fields + for _, field := range []string{"hash", "nonce", "miner"} { + response[field] = nil + } + } + return response, err + } + return nil, nil +} + +// rpcMarshalBlock reimplementation of ethapi.rpcMarshalBlock +func (api *APIImpl) rpcMarshalBlock(b *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) { + fields, err := ethapi.RPCMarshalBlock(b, inclTx, fullTx) + if err != nil { + return nil, err + } + // TODO: implement .GetTd method and uncomment next line + //fields["totalDifficulty"] = (*hexutil.Big)(s.b.GetTd(b.Hash())) + return fields, err +} + +// ReadCanonicalHash reimplementation of rawdb.ReadCanonicalHash +func ReadCanonicalHash(tx *remote.Tx, number uint64) common.Hash { + bucket := tx.Bucket(dbutils.HeaderPrefix) + if bucket == nil { + return common.Hash{} + //return fmt.Errorf("bucket %s not found", dbutils.HeaderPrefix) + } + + data := bucket.Get(dbutils.HeaderHashKey(number)) + if len(data) == 0 { + return common.Hash{} + } + return common.BytesToHash(data) +} + +// GetBlockByNumber reimplementation of chain.GetBlockByNumber +func GetBlockByNumber(tx *remote.Tx, number uint64) *types.Block { + hash := ReadCanonicalHash(tx, number) + if hash == (common.Hash{}) { + return nil + } + return ReadBlock(tx, hash, number) +} + +// ReadBlock reimplementation of rawdb.ReadBlock +func ReadBlock(tx *remote.Tx, hash common.Hash, number uint64) *types.Block { + header := ReadHeader(tx, hash, number) + if header == nil { + return nil + } + body := ReadBody(tx, hash, number) + if body == nil { + return nil + } + return types.NewBlockWithHeader(header).WithBody(body.Transactions, body.Uncles) +} + +// ReadBlock reimplementation of rawdb.ReadBlock +func ReadHeaderRLP(tx *remote.Tx, hash common.Hash, number uint64) rlp.RawValue { + bucket := tx.Bucket(dbutils.HeaderPrefix) + if bucket == nil { + //return fmt.Errorf("bucket %s not found", dbutils.HeaderPrefix) + log.Error("Bucket not founc", "error", dbutils.HeaderPrefix) + return rlp.RawValue{} + } + return bucket.Get(dbutils.HeaderKey(number, hash)) +} + +// ReadHeader reimplementation of rawdb.ReadHeader +func ReadHeader(tx *remote.Tx, hash common.Hash, number uint64) *types.Header { + data := ReadHeaderRLP(tx, hash, number) + if len(data) == 0 { + return nil + } + header := new(types.Header) + if err := rlp.Decode(bytes.NewReader(data), header); err != nil { + log.Error("Invalid block header RLP", "hash", hash, "err", err) + return nil + } + return header +} + +// ReadBodyRLP retrieves the block body (transactions and uncles) in RLP encoding. +func ReadBodyRLP(tx *remote.Tx, hash common.Hash, number uint64) rlp.RawValue { + bucket := tx.Bucket(dbutils.BlockBodyPrefix) + if bucket == nil { + //return fmt.Errorf("bucket %s not found", dbutils.HeaderPrefix) + log.Error("Bucket not founc", "error", dbutils.BlockBodyPrefix) + return rlp.RawValue{} + } + return bucket.Get(dbutils.BlockBodyKey(number, hash)) +} + +// ReadBody reimplementation of rawdb.ReadBody +func ReadBody(tx *remote.Tx, hash common.Hash, number uint64) *types.Body { + data := ReadBodyRLP(tx, hash, number) + if len(data) == 0 { + return nil + } + body := new(types.Body) + if err := rlp.Decode(bytes.NewReader(data), body); err != nil { + log.Error("Invalid block body RLP", "hash", hash, "err", err) + return nil + } + // Post-processing + body.SendersToTxs() + return body +} + func daemon(cfg Config) { vhosts := splitAndTrim(cfg.rpcVirtualHost) cors := splitAndTrim(cfg.rpcCORSDomain) diff --git a/cmd/rpcdaemon/test.http b/cmd/rpcdaemon/test.http new file mode 100644 index 000000000..16a5ed663 --- /dev/null +++ b/cmd/rpcdaemon/test.http @@ -0,0 +1,18 @@ +### + +# curl -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"eth_getBlockByNumber", "params": ["0x1b4", true], "id":1}' localhost:8545 +POST localhost:8545 +Content-Type: application/json + +{ + "jsonrpc": "2.0", + "method": "eth_getBlockByNumber", + "params": [ + "0x1b4", + true + ], + "id": 1 +} + +### + From 4d8c1a8ec1e9f0deab1d513b3522839f516f7111 Mon Sep 17 00:00:00 2001 From: "alex.sharov" Date: Sun, 1 Dec 2019 19:25:10 +0700 Subject: [PATCH 08/11] remove debug --- cmd/rpcdaemon/commands/daemon.go | 1 - cmd/rpcdaemon/test.http | 18 ------------------ 2 files changed, 19 deletions(-) delete mode 100644 cmd/rpcdaemon/test.http diff --git a/cmd/rpcdaemon/commands/daemon.go b/cmd/rpcdaemon/commands/daemon.go index fecdc8680..210775067 100644 --- a/cmd/rpcdaemon/commands/daemon.go +++ b/cmd/rpcdaemon/commands/daemon.go @@ -111,7 +111,6 @@ func (api *APIImpl) GetBlockByNumber(ctx context.Context, number rpc.BlockNumber api.db = nil return nil, err } - fmt.Printf("Debug: %#v %#v %#v\n", block.Number(), block.Hash(), block.Size()) if block != nil { response, err := api.rpcMarshalBlock(block, true, fullTx) diff --git a/cmd/rpcdaemon/test.http b/cmd/rpcdaemon/test.http deleted file mode 100644 index 16a5ed663..000000000 --- a/cmd/rpcdaemon/test.http +++ /dev/null @@ -1,18 +0,0 @@ -### - -# curl -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"eth_getBlockByNumber", "params": ["0x1b4", true], "id":1}' localhost:8545 -POST localhost:8545 -Content-Type: application/json - -{ - "jsonrpc": "2.0", - "method": "eth_getBlockByNumber", - "params": [ - "0x1b4", - true - ], - "id": 1 -} - -### - From 330060d382f819f04ced532166c6cf535dd897e5 Mon Sep 17 00:00:00 2001 From: "alex.sharov" Date: Sun, 1 Dec 2019 19:26:24 +0700 Subject: [PATCH 09/11] ignore *.http files - I using them to store http requests --- cmd/rpcdaemon/.gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 cmd/rpcdaemon/.gitignore diff --git a/cmd/rpcdaemon/.gitignore b/cmd/rpcdaemon/.gitignore new file mode 100644 index 000000000..bc910ca20 --- /dev/null +++ b/cmd/rpcdaemon/.gitignore @@ -0,0 +1 @@ +*.http \ No newline at end of file From 33c52363ee8121cf59577557a91083bb82b7f16f Mon Sep 17 00:00:00 2001 From: "alex.sharov" Date: Mon, 2 Dec 2019 10:19:02 +0700 Subject: [PATCH 10/11] totalDifficulty - consistent calculation --- cmd/rpcdaemon/commands/daemon.go | 35 ++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/cmd/rpcdaemon/commands/daemon.go b/cmd/rpcdaemon/commands/daemon.go index 210775067..931954d47 100644 --- a/cmd/rpcdaemon/commands/daemon.go +++ b/cmd/rpcdaemon/commands/daemon.go @@ -5,6 +5,7 @@ import ( "context" "encoding/binary" "fmt" + "math/big" "net" "os" "os/signal" @@ -12,6 +13,7 @@ import ( "github.com/ledgerwatch/turbo-geth/common" "github.com/ledgerwatch/turbo-geth/common/dbutils" + "github.com/ledgerwatch/turbo-geth/common/hexutil" "github.com/ledgerwatch/turbo-geth/core/types" "github.com/ledgerwatch/turbo-geth/ethdb/remote" "github.com/ledgerwatch/turbo-geth/internal/ethapi" @@ -102,9 +104,11 @@ func (api *APIImpl) GetBlockByNumber(ctx context.Context, number rpc.BlockNumber } var block *types.Block + additionalFields := make(map[string]interface{}) if err := api.db.View(func(tx *remote.Tx) error { block = GetBlockByNumber(tx, uint64(number.Int64())) + additionalFields["totalDifficulty"] = ReadTd(tx, block.Hash(), uint64(number.Int64())) return nil }); err != nil { api.db.Close() @@ -113,7 +117,8 @@ func (api *APIImpl) GetBlockByNumber(ctx context.Context, number rpc.BlockNumber } if block != nil { - response, err := api.rpcMarshalBlock(block, true, fullTx) + response, err := api.rpcMarshalBlock(block, true, fullTx, additionalFields) + if err == nil && number == rpc.PendingBlockNumber { // Pending blocks need to nil out a few fields for _, field := range []string{"hash", "nonce", "miner"} { @@ -126,16 +131,38 @@ func (api *APIImpl) GetBlockByNumber(ctx context.Context, number rpc.BlockNumber } // rpcMarshalBlock reimplementation of ethapi.rpcMarshalBlock -func (api *APIImpl) rpcMarshalBlock(b *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) { +func (api *APIImpl) rpcMarshalBlock(b *types.Block, inclTx bool, fullTx bool, additional map[string]interface{}) (map[string]interface{}, error) { fields, err := ethapi.RPCMarshalBlock(b, inclTx, fullTx) if err != nil { return nil, err } - // TODO: implement .GetTd method and uncomment next line - //fields["totalDifficulty"] = (*hexutil.Big)(s.b.GetTd(b.Hash())) + + for k, v := range additional { + fields[k] = v + } + return fields, err } +// ReadTd reimplemented rawdb.ReadTd +func ReadTd(tx *remote.Tx, hash common.Hash, number uint64) *hexutil.Big { + bucket := tx.Bucket(dbutils.HeaderPrefix) + if bucket == nil { + return nil + } + + data := bucket.Get(dbutils.HeaderTDKey(number, hash)) + if len(data) == 0 { + return nil + } + td := new(big.Int) + if err := rlp.Decode(bytes.NewReader(data), td); err != nil { + log.Error("Invalid block total difficulty RLP", "hash", hash, "err", err) + return nil + } + return (*hexutil.Big)(td) +} + // ReadCanonicalHash reimplementation of rawdb.ReadCanonicalHash func ReadCanonicalHash(tx *remote.Tx, number uint64) common.Hash { bucket := tx.Bucket(dbutils.HeaderPrefix) From 2f079dcf75541efd9ad174ed24b9f6a3ae53ab19 Mon Sep 17 00:00:00 2001 From: "alex.sharov" Date: Mon, 2 Dec 2019 10:31:27 +0700 Subject: [PATCH 11/11] Readme.md --- cmd/rpcdaemon/Readme.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 cmd/rpcdaemon/Readme.md diff --git a/cmd/rpcdaemon/Readme.md b/cmd/rpcdaemon/Readme.md new file mode 100644 index 000000000..0edc1c191 --- /dev/null +++ b/cmd/rpcdaemon/Readme.md @@ -0,0 +1,31 @@ + +## Getting Started + +In order to build and run turbo-geth node together with RPC daemon, you need to do the following: +1. Clone turbo-geth repo +2. Build it by running `make` +3. Start it (it will start syncing to the mainnet) like this: +```` +./build/bin/geth --remote-db-listen-addr localhost:9999 +```` +4. Look out for this in the console/log file: +```` +INFO [11-30|18:34:12.687] Remote DB interface listening on address=localhost:9999 +```` +5. In another terminal/tab, build RPC daemon: +```` +make rpcdaemon +```` +6. Run it: +```` +./build/bin/rpcdaemon --rpcapi eth +```` +By default, it will connect to the turbo-geth node on the `localhost:9999`, but this can be changed via command line parameters. Note that it does not matter in which order you start these two processes, RPC daemon will only try to connect to turbo-geth node when serving its first RPC request, and then it will reconnect if connection is lost (for example, if you restart turbo-geth) +7. Try `eth_blockNumber` call. In another console/tab, use `curl` to make RPC call: +```` +curl -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"eth_blockNumber", "params": [], "id":1}' localhost:854 +```` +8. It should return something like this (depending on how far your turbo-geth node has synced): +```` +{"jsonrpc":"2.0","id":1,"result":823909} +```` \ No newline at end of file