From d64ac5792c4f30ee90f4688a2b167a8e706a0089 Mon Sep 17 00:00:00 2001 From: Thomas E Lackey Date: Tue, 10 Jan 2023 12:04:28 -0600 Subject: [PATCH] Add forwardGetStorageAt setting. --- cmd/serve.go | 1 + pkg/eth/api.go | 40 +++++++++++++++++++++++++++------------ pkg/eth/api_test.go | 2 +- pkg/eth/eth_state_test.go | 2 +- pkg/eth/ipld_retriever.go | 3 +++ pkg/serve/config.go | 34 ++++++++++++++++++--------------- pkg/serve/service.go | 5 ++++- 7 files changed, 57 insertions(+), 30 deletions(-) diff --git a/cmd/serve.go b/cmd/serve.go index d3fbe243..f4973947 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 34451e95..9757be6e 100644 --- a/pkg/eth/api.go +++ b/pkg/eth/api.go @@ -57,18 +57,22 @@ 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 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") } @@ -77,12 +81,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 } @@ -720,6 +725,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. + if err := pea.rpc.CallContext(ctx, &res, "eth_getStorageAt", address, key, blockNrOrHash); res != nil && err == nil { + return res, nil + } + } storageVal, err := pea.B.GetStorageByNumberOrHash(ctx, address, common.HexToHash(key), blockNrOrHash) if storageVal != nil && err == nil { var value common.Hash @@ -735,8 +747,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 } @@ -1065,6 +1079,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()) } @@ -1087,6 +1102,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 b3ef9d9f..a5b35c7f 100644 --- a/pkg/eth/api_test.go +++ b/pkg/eth/api_test.go @@ -213,7 +213,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 999ee3c9..0d5b2e91 100644 --- a/pkg/eth/eth_state_test.go +++ b/pkg/eth/eth_state_test.go @@ -92,7 +92,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/eth/ipld_retriever.go b/pkg/eth/ipld_retriever.go index 3b6d4073..c1076023 100644 --- a/pkg/eth/ipld_retriever.go +++ b/pkg/eth/ipld_retriever.go @@ -27,6 +27,7 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/rlp" "github.com/lib/pq" + log "github.com/sirupsen/logrus" ) const ( @@ -493,6 +494,8 @@ func (r *IPLDRetriever) RetrieveStorageAtByAddressAndStorageSlotAndBlockHash(add if err := r.db.Get(storageResult, RetrieveStorageLeafByAddressHashAndLeafKeyAndBlockHashPgStr, stateLeafKey.Hex(), storageHash.Hex(), hash.Hex()); err != nil { return "", nil, nil, err } + log.Debugf("getStorageAt: state_leaf_key=%s, storage_hex=%s, storage_leaf_key=%s, block_hash=%s", + stateLeafKey.Hex(), key.Hex(), storageHash.Hex(), hash.Hex()) if storageResult.StateLeafRemoved || storageResult.NodeType == removedNode { return "", EmptyNodeValue, EmptyNodeValue, nil } diff --git a/pkg/serve/config.go b/pkg/serve/config.go index 0746b549..7e4adb7e 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 b22963cc..10d8f708 100644 --- a/pkg/serve/service.go +++ b/pkg/serve/service.go @@ -85,6 +85,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 @@ -104,6 +106,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 @@ -139,7 +142,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) }