From 757edf17d6c8afdf757bf3160e4ea8cf5adfbe91 Mon Sep 17 00:00:00 2001 From: Thomas E Lackey Date: Tue, 10 Jan 2023 17:39:21 -0600 Subject: [PATCH] Add option to forward eth_getStorageAt calls. (#221) --- cmd/serve.go | 1 + pkg/eth/api.go | 40 +++++++++++++++++++++++++++------------ pkg/eth/api_test.go | 2 +- pkg/eth/eth_state_test.go | 2 +- pkg/serve/config.go | 34 ++++++++++++++++++--------------- pkg/serve/service.go | 6 ++++-- 6 files changed, 54 insertions(+), 31 deletions(-) diff --git a/cmd/serve.go b/cmd/serve.go index fde02ee7..14c744f8 100644 --- a/cmd/serve.go +++ b/cmd/serve.go @@ -395,6 +395,7 @@ func init() { viper.BindPFlag("ethereum.chainConfig", serveCmd.PersistentFlags().Lookup("eth-chain-config")) viper.BindPFlag("ethereum.supportsStateDiff", serveCmd.PersistentFlags().Lookup("eth-supports-state-diff")) viper.BindPFlag("ethereum.forwardEthCalls", serveCmd.PersistentFlags().Lookup("eth-forward-eth-calls")) + viper.BindPFlag("ethereum.forwardGetStorageAt", serveCmd.PersistentFlags().Lookup("eth-forward-get-storage-at")) viper.BindPFlag("ethereum.proxyOnError", serveCmd.PersistentFlags().Lookup("eth-proxy-on-error")) // groupcache flags diff --git a/pkg/eth/api.go b/pkg/eth/api.go index a3605a4d..5cd26e41 100644 --- a/pkg/eth/api.go +++ b/pkg/eth/api.go @@ -62,21 +62,25 @@ type PublicEthAPI struct { B *Backend // Proxy node for forwarding cache misses - supportsStateDiff bool // Whether the remote node supports the statediff_writeStateDiffAt endpoint, if it does we can fill the local cache when we hit a miss - rpc *rpc.Client - ethClient *ethclient.Client - forwardEthCalls bool // if true, forward eth_call calls directly to the configured proxy node - proxyOnError bool // turn on regular proxy fall-through on errors; needed to test difference between direct and indirect fall-through + supportsStateDiff bool // Whether the remote node supports the statediff_writeStateDiffAt endpoint, if it does we can fill the local cache when we hit a miss + rpc *rpc.Client + ethClient *ethclient.Client + forwardEthCalls bool // if true, forward eth_call calls directly to the configured proxy node + forwardGetStorageAt bool // if true, forward eth_getStorageAt calls directly to the configured proxy node + proxyOnError bool // turn on regular proxy fall-through on errors; needed to test difference between direct and indirect fall-through } // NewPublicEthAPI creates a new PublicEthAPI with the provided underlying Backend -func NewPublicEthAPI(b *Backend, client *rpc.Client, supportsStateDiff, forwardEthCalls, proxyOnError bool) (*PublicEthAPI, error) { +func NewPublicEthAPI(b *Backend, client *rpc.Client, supportsStateDiff, forwardEthCalls, forwardGetStorageAt, proxyOnError bool) (*PublicEthAPI, error) { if b == nil { return nil, errors.New("ipld-eth-server must be configured with an ethereum backend") } if forwardEthCalls && client == nil { return nil, errors.New("ipld-eth-server is configured to forward eth_calls to proxy node but no proxy node is configured") } + if forwardGetStorageAt && client == nil { + return nil, errors.New("ipld-eth-server is configured to forward eth_getStorageAt to proxy node but no proxy node is configured") + } if proxyOnError && client == nil { return nil, errors.New("ipld-eth-server is configured to forward all calls to proxy node on errors but no proxy node is configured") } @@ -85,12 +89,13 @@ func NewPublicEthAPI(b *Backend, client *rpc.Client, supportsStateDiff, forwardE ethClient = ethclient.NewClient(client) } return &PublicEthAPI{ - B: b, - supportsStateDiff: supportsStateDiff, - rpc: client, - ethClient: ethClient, - forwardEthCalls: forwardEthCalls, - proxyOnError: proxyOnError, + B: b, + supportsStateDiff: supportsStateDiff, + rpc: client, + ethClient: ethClient, + forwardEthCalls: forwardEthCalls, + forwardGetStorageAt: forwardGetStorageAt, + proxyOnError: proxyOnError, }, nil } @@ -725,6 +730,13 @@ func (pea *PublicEthAPI) localGetBalance(ctx context.Context, address common.Add // block number. The rpc.LatestBlockNumber and rpc.PendingBlockNumber meta block // numbers are also allowed. func (pea *PublicEthAPI) GetStorageAt(ctx context.Context, address common.Address, key string, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) { + if pea.forwardGetStorageAt { + var res hexutil.Bytes + // If forwarding all getStorageAt calls, don't request statediffing. + err := pea.rpc.CallContext(ctx, &res, "eth_getStorageAt", address, key, blockNrOrHash) + return res, err + } + storageVal, err := pea.B.GetStorageByNumberOrHash(ctx, address, common.HexToHash(key), blockNrOrHash) if storageVal != nil && err == nil { var value common.Hash @@ -740,8 +752,10 @@ func (pea *PublicEthAPI) GetStorageAt(ctx context.Context, address common.Addres return value[:], nil } if pea.proxyOnError { + logrus.Warnf("Missing eth_getStorageAt(%s, %s, %s)", address.Hash().String(), key, blockNrOrHash.String()) var res hexutil.Bytes if err := pea.rpc.CallContext(ctx, &res, "eth_getStorageAt", address, key, blockNrOrHash); res != nil && err == nil { + // If only proxying on error, request statediffing for the missing data. go pea.writeStateDiffAtOrFor(blockNrOrHash) return res, nil } @@ -1080,6 +1094,7 @@ func (pea *PublicEthAPI) writeStateDiffAt(height int64) { IncludeTD: true, IncludeCode: true, } + logrus.Debugf("Calling statediff_writeStateDiffAt(%d)", height) if err := pea.rpc.CallContext(ctx, &data, "statediff_writeStateDiffAt", uint64(height), params); err != nil { logrus.Errorf("writeStateDiffAt %d faild with err %s", height, err.Error()) } @@ -1102,6 +1117,7 @@ func (pea *PublicEthAPI) writeStateDiffFor(blockHash common.Hash) { IncludeTD: true, IncludeCode: true, } + logrus.Debugf("Calling statediff_writeStateDiffFor(%s)", blockHash.Hex()) if err := pea.rpc.CallContext(ctx, &data, "statediff_writeStateDiffFor", blockHash, params); err != nil { logrus.Errorf("writeStateDiffFor %s faild with err %s", blockHash.Hex(), err.Error()) } diff --git a/pkg/eth/api_test.go b/pkg/eth/api_test.go index bbbd1a06..4506d113 100644 --- a/pkg/eth/api_test.go +++ b/pkg/eth/api_test.go @@ -211,7 +211,7 @@ var _ = Describe("API", func() { }, }) Expect(err).ToNot(HaveOccurred()) - api, _ = eth.NewPublicEthAPI(backend, nil, false, false, false) + api, _ = eth.NewPublicEthAPI(backend, nil, false, false, false, false) tx, err = indexAndPublisher.PushBlock(test_helpers.MockBlock, test_helpers.MockReceipts, test_helpers.MockBlock.Difficulty()) Expect(err).ToNot(HaveOccurred()) diff --git a/pkg/eth/eth_state_test.go b/pkg/eth/eth_state_test.go index cd793c83..f05ac028 100644 --- a/pkg/eth/eth_state_test.go +++ b/pkg/eth/eth_state_test.go @@ -125,7 +125,7 @@ var _ = Describe("eth state reading tests", func() { }, }) Expect(err).ToNot(HaveOccurred()) - api, _ = eth.NewPublicEthAPI(backend, nil, false, false, false) + api, _ = eth.NewPublicEthAPI(backend, nil, false, false, false, false) // make the test blockchain (and state) blocks, receipts, chain = test_helpers.MakeChain(chainLength, test_helpers.Genesis, test_helpers.TestChainGen) diff --git a/pkg/serve/config.go b/pkg/serve/config.go index fd345ed2..324874b8 100644 --- a/pkg/serve/config.go +++ b/pkg/serve/config.go @@ -46,12 +46,13 @@ const ( SERVER_MAX_OPEN_CONNECTIONS = "SERVER_MAX_OPEN_CONNECTIONS" SERVER_MAX_CONN_LIFETIME = "SERVER_MAX_CONN_LIFETIME" - ETH_DEFAULT_SENDER_ADDR = "ETH_DEFAULT_SENDER_ADDR" - ETH_RPC_GAS_CAP = "ETH_RPC_GAS_CAP" - ETH_CHAIN_CONFIG = "ETH_CHAIN_CONFIG" - ETH_SUPPORTS_STATEDIFF = "ETH_SUPPORTS_STATEDIFF" - ETH_FORWARD_ETH_CALLS = "ETH_FORWARD_ETH_CALLS" - ETH_PROXY_ON_ERROR = "ETH_PROXY_ON_ERROR" + ETH_DEFAULT_SENDER_ADDR = "ETH_DEFAULT_SENDER_ADDR" + ETH_RPC_GAS_CAP = "ETH_RPC_GAS_CAP" + ETH_CHAIN_CONFIG = "ETH_CHAIN_CONFIG" + ETH_SUPPORTS_STATEDIFF = "ETH_SUPPORTS_STATEDIFF" + ETH_FORWARD_ETH_CALLS = "ETH_FORWARD_ETH_CALLS" + ETH_FORWARD_GET_STORAGE_AT = "ETH_FORWARD_GET_STORAGE_AT" + ETH_PROXY_ON_ERROR = "ETH_PROXY_ON_ERROR" VALIDATOR_ENABLED = "VALIDATOR_ENABLED" VALIDATOR_EVERY_NTH_BLOCK = "VALIDATOR_EVERY_NTH_BLOCK" @@ -80,15 +81,16 @@ type Config struct { TracingHttpEndpoint string TracingPostgraphileEndpoint string - ChainConfig *params.ChainConfig - DefaultSender *common.Address - RPCGasCap *big.Int - EthHttpEndpoint string - Client *rpc.Client - SupportStateDiff bool - ForwardEthCalls bool - ProxyOnError bool - NodeNetworkID string + ChainConfig *params.ChainConfig + DefaultSender *common.Address + RPCGasCap *big.Int + EthHttpEndpoint string + Client *rpc.Client + SupportStateDiff bool + ForwardEthCalls bool + ForwardGetStorageAt bool + ProxyOnError bool + NodeNetworkID string // Cache configuration. GroupCache *ethServerShared.GroupCacheConfig @@ -108,6 +110,7 @@ func NewConfig() (*Config, error) { viper.BindEnv("ethereum.chainConfig", ETH_CHAIN_CONFIG) viper.BindEnv("ethereum.supportsStateDiff", ETH_SUPPORTS_STATEDIFF) viper.BindEnv("ethereum.forwardEthCalls", ETH_FORWARD_ETH_CALLS) + viper.BindEnv("ethereum.forwardGetStorageAt", ETH_FORWARD_GET_STORAGE_AT) viper.BindEnv("ethereum.proxyOnError", ETH_PROXY_ON_ERROR) c.dbInit() @@ -121,6 +124,7 @@ func NewConfig() (*Config, error) { c.Client = cli c.SupportStateDiff = viper.GetBool("ethereum.supportsStateDiff") c.ForwardEthCalls = viper.GetBool("ethereum.forwardEthCalls") + c.ForwardGetStorageAt = viper.GetBool("ethereum.forwardGetStorageAt") c.ProxyOnError = viper.GetBool("ethereum.proxyOnError") c.EthHttpEndpoint = ethHTTPEndpoint diff --git a/pkg/serve/service.go b/pkg/serve/service.go index 297b7183..3e15f75b 100644 --- a/pkg/serve/service.go +++ b/pkg/serve/service.go @@ -87,6 +87,8 @@ type Service struct { backend *eth.Backend // whether to forward eth_calls directly to proxy node forwardEthCalls bool + // whether to forward eth_getStorageAt directly to proxy node + forwardGetStorageAt bool // whether to forward all calls to proxy node if they throw an error locally proxyOnError bool // eth node network id @@ -106,6 +108,7 @@ func NewServer(settings *Config) (Server, error) { sap.client = settings.Client sap.supportsStateDiffing = settings.SupportStateDiff sap.forwardEthCalls = settings.ForwardEthCalls + sap.forwardGetStorageAt = settings.ForwardGetStorageAt sap.proxyOnError = settings.ProxyOnError sap.nodeNetworkId = settings.NodeNetworkID var err error @@ -141,8 +144,7 @@ func (sap *Service) APIs() []rpc.API { Public: true, }, } - - ethAPI, err := eth.NewPublicEthAPI(sap.backend, sap.client, sap.supportsStateDiffing, sap.forwardEthCalls, sap.proxyOnError) + ethAPI, err := eth.NewPublicEthAPI(sap.backend, sap.client, sap.supportsStateDiffing, sap.forwardEthCalls, sap.forwardGetStorageAt, sap.proxyOnError) if err != nil { log.Fatalf("unable to create public eth api: %v", err) }