From 140989cbf73eb360373a5f378b791beafc356879 Mon Sep 17 00:00:00 2001 From: i-norden Date: Mon, 27 Dec 2021 12:25:54 -0600 Subject: [PATCH] option to immediately forward eth_calls to proxy node --- pkg/eth/api.go | 17 +++++++++-- pkg/eth/helpers.go | 3 +- pkg/serve/config.go | 64 ++++++++++++++++++++++------------------- pkg/serve/env.go | 42 +++++++++++++-------------- pkg/serve/service.go | 9 +++++- pkg/shared/functions.go | 4 +-- 6 files changed, 81 insertions(+), 58 deletions(-) diff --git a/pkg/eth/api.go b/pkg/eth/api.go index 15d6ea17..0a83f518 100644 --- a/pkg/eth/api.go +++ b/pkg/eth/api.go @@ -57,13 +57,17 @@ type PublicEthAPI struct { B *Backend // Proxy node for forwarding cache misses - supportsStateDiff bool // Whether or not the remote node supports the statediff_writeStateDiffAt endpoint, if it does we can fill the local cache when we hit a miss + 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 } // NewPublicEthAPI creates a new PublicEthAPI with the provided underlying Backend -func NewPublicEthAPI(b *Backend, client *rpc.Client, supportsStateDiff bool) *PublicEthAPI { +func NewPublicEthAPI(b *Backend, client *rpc.Client, supportsStateDiff, forwardEthCalls 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") + } var ethClient *ethclient.Client if client != nil { ethClient = ethclient.NewClient(client) @@ -73,7 +77,8 @@ func NewPublicEthAPI(b *Backend, client *rpc.Client, supportsStateDiff bool) *Pu supportsStateDiff: supportsStateDiff, rpc: client, ethClient: ethClient, - } + forwardEthCalls: forwardEthCalls, + }, nil } /* @@ -910,6 +915,12 @@ func (diff *StateOverride) Apply(state *state.StateDB) error { // Note, this function doesn't make and changes in the state/blockchain and is // useful to execute and retrieve values. func (pea *PublicEthAPI) Call(ctx context.Context, args CallArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *StateOverride) (hexutil.Bytes, error) { + if pea.forwardEthCalls { + var hex hexutil.Bytes + err := pea.rpc.CallContext(ctx, &hex, "eth_call", args, blockNrOrHash, overrides) + return hex, err + } + result, err := DoCall(ctx, pea.B, args, blockNrOrHash, overrides, 5*time.Second, pea.B.Config.RPCGasCap.Uint64()) // If the result contains a revert reason, try to unpack and return it. diff --git a/pkg/eth/helpers.go b/pkg/eth/helpers.go index fc09d13c..b4d4f679 100644 --- a/pkg/eth/helpers.go +++ b/pkg/eth/helpers.go @@ -19,9 +19,10 @@ package eth import ( "encoding/json" "fmt" + "os" + "github.com/ethereum/go-ethereum/cmd/utils" log "github.com/sirupsen/logrus" - "os" sdtypes "github.com/ethereum/go-ethereum/statediff/types" diff --git a/pkg/serve/config.go b/pkg/serve/config.go index 6fb31039..3fb0e900 100644 --- a/pkg/serve/config.go +++ b/pkg/serve/config.go @@ -36,21 +36,22 @@ import ( // Env variables const ( - serverWsPath = "SERVER_WS_PATH" - serverIpcPath = "SERVER_IPC_PATH" - serverHTTPPath = "SERVER_HTTP_PATH" + SERVER_WS_PATH = "SERVER_WS_PATH" + SERVER_IPC_PATH = "SERVER_IPC_PATH" + SERVER_HTTP_PATH = "SERVER_HTTP_PATH" - serverMaxIdleConnections = "SERVER_MAX_IDLE_CONNECTIONS" - serverMaxOpenConnections = "SERVER_MAX_OPEN_CONNECTIONS" - serverMaxConnLifetime = "SERVER_MAX_CONN_LIFETIME" + SERVER_MAX_IDLE_CONNECTIONS = "SERVER_MAX_IDLE_CONNECTIONS" + SERVER_MAX_OPEN_CONNECTIONS = "SERVER_MAX_OPEN_CONNECTIONS" + SERVER_MAX_CONN_LIFETIME = "SERVER_MAX_CONN_LIFETIME" - ethDefaultSenderAddr = "ETH_DEFAULT_SENDER_ADDR" - ethRPCGasCap = "ETH_RPC_GAS_CAP" - ethChainConfig = "ETH_CHAIN_CONFIG" - ethSupportsStatediff = "ETH_SUPPORTS_STATEDIFF" + 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" - ValidatorEnabled = "VALIDATOR_ENABLED" - ValidatorEveryNthBlock = "VALIDATOR_EVERY_NTH_BLOCK" + VALIDATOR_ENABLED = "VALIDATOR_ENABLED" + VALIDATOR_EVERY_NTH_BLOCK = "VALIDATOR_EVERY_NTH_BLOCK" ) // Config struct @@ -83,6 +84,7 @@ type Config struct { EthHttpEndpoint string Client *rpc.Client SupportStateDiff bool + ForwardEthCalls bool // Cache configuration. GroupCache *ethServerShared.GroupCacheConfig @@ -96,11 +98,12 @@ type Config struct { func NewConfig() (*Config, error) { c := new(Config) - viper.BindEnv("ethereum.httpPath", ethHTTPPath) - viper.BindEnv("ethereum.defaultSender", ethDefaultSenderAddr) - viper.BindEnv("ethereum.rpcGasCap", ethRPCGasCap) - viper.BindEnv("ethereum.chainConfig", ethChainConfig) - viper.BindEnv("ethereum.supportsStateDiff", ethSupportsStatediff) + viper.BindEnv("ethereum.httpPath", ETH_HTTP_PATH) + viper.BindEnv("ethereum.defaultSender", ETH_DEFAULT_SENDER_ADDR) + viper.BindEnv("ethereum.rpcGasCap", ETH_RPC_GAS_CAP) + viper.BindEnv("ethereum.chainConfig", ETH_CHAIN_CONFIG) + viper.BindEnv("ethereum.supportsStateDiff", ETH_SUPPORTS_STATEDIFF) + viper.BindEnv("ethereum.forwardEthCalls", ETH_FORWARD_ETH_CALLS) c.dbInit() ethHTTP := viper.GetString("ethereum.httpPath") @@ -111,6 +114,7 @@ func NewConfig() (*Config, error) { } c.Client = cli c.SupportStateDiff = viper.GetBool("ethereum.supportsStateDiff") + c.ForwardEthCalls = viper.GetBool("ethereum.forwardEthCalls") c.EthHttpEndpoint = ethHTTPEndpoint // websocket server @@ -224,23 +228,23 @@ func NewConfig() (*Config, error) { } func overrideDBConnConfig(con *postgres.ConnectionConfig) { - viper.BindEnv("database.server.maxIdle", serverMaxIdleConnections) - viper.BindEnv("database.server.maxOpen", serverMaxOpenConnections) - viper.BindEnv("database.server.maxLifetime", serverMaxConnLifetime) + viper.BindEnv("database.server.maxIdle", SERVER_MAX_IDLE_CONNECTIONS) + viper.BindEnv("database.server.maxOpen", SERVER_MAX_OPEN_CONNECTIONS) + viper.BindEnv("database.server.maxLifetime", SERVER_MAX_CONN_LIFETIME) con.MaxIdle = viper.GetInt("database.server.maxIdle") con.MaxOpen = viper.GetInt("database.server.maxOpen") con.MaxLifetime = viper.GetInt("database.server.maxLifetime") } func (c *Config) dbInit() { - viper.BindEnv("database.name", databaseName) - viper.BindEnv("database.hostname", databaseHostname) - viper.BindEnv("database.port", databasePort) - viper.BindEnv("database.user", databaseUser) - viper.BindEnv("database.password", databasePassword) - viper.BindEnv("database.maxIdle", databaseMaxIdleConnections) - viper.BindEnv("database.maxOpen", databaseMaxOpenConnections) - viper.BindEnv("database.maxLifetime", databaseMaxOpenConnLifetime) + viper.BindEnv("database.name", DATABASE_NAME) + viper.BindEnv("database.hostname", DATABASE_HOSTNAME) + viper.BindEnv("database.port", DATABASE_PORT) + viper.BindEnv("database.user", DATABASE_USER) + viper.BindEnv("database.password", DATABASE_PASSWORD) + viper.BindEnv("database.maxIdle", DATABASE_MAX_IDLE_CONNECTIONS) + viper.BindEnv("database.maxOpen", DATABASE_MAX_OPEN_CONNECTIONS) + viper.BindEnv("database.maxLifetime", DATABASE_MAX_CONN_LIFETIME) c.DBParams.Name = viper.GetString("database.name") c.DBParams.Hostname = viper.GetString("database.hostname") @@ -276,8 +280,8 @@ func (c *Config) loadGroupCacheConfig() { } func (c *Config) loadValidatorConfig() { - viper.BindEnv("validator.enabled", ValidatorEnabled) - viper.BindEnv("validator.everyNthBlock", ValidatorEveryNthBlock) + viper.BindEnv("validator.enabled", VALIDATOR_ENABLED) + viper.BindEnv("validator.everyNthBlock", VALIDATOR_EVERY_NTH_BLOCK) c.StateValidationEnabled = viper.GetBool("validator.enabled") c.StateValidationEveryNthBlock = viper.GetUint64("validator.everyNthBlock") diff --git a/pkg/serve/env.go b/pkg/serve/env.go index ebcce07a..ec9bc4d1 100644 --- a/pkg/serve/env.go +++ b/pkg/serve/env.go @@ -8,33 +8,33 @@ import ( // Env variables const ( - HTTPTimeout = "HTTP_TIMEOUT" + HTTP_TIMEOUT = "HTTP_TIMEOUT" - EthWsPath = "ETH_WS_PATH" - ethHTTPPath = "ETH_HTTP_PATH" - ethNodeID = "ETH_NODE_ID" - ethClientName = "ETH_CLIENT_NAME" - ethGenesisBlock = "ETH_GENESIS_BLOCK" - ethNetworkID = "ETH_NETWORK_ID" - ethChainID = "ETH_CHAIN_ID" + ETH_WS_PATH = "ETH_WS_PATH" + ETH_HTTP_PATH = "ETH_HTTP_PATH" + ETH_NODE_ID = "ETH_NODE_ID" + ETH_CLIENT_NAME = "ETH_CLIENT_NAME" + ETH_GENESIS_BLOCK = "ETH_GENESIS_BLOCK" + ETH_NETWORK_ID = "ETH_NETWORK_ID" + ETH_CHAIN_ID = "ETH_CHAIN_ID" - databaseName = "DATABASE_NAME" - databaseHostname = "DATABASE_HOSTNAME" - databasePort = "DATABASE_PORT" - databaseUser = "DATABASE_USER" - databasePassword = "DATABASE_PASSWORD" - databaseMaxIdleConnections = "DATABASE_MAX_IDLE_CONNECTIONS" - databaseMaxOpenConnections = "DATABASE_MAX_OPEN_CONNECTIONS" - databaseMaxOpenConnLifetime = "DATABASE_MAX_CONN_LIFETIME" + DATABASE_NAME = "DATABASE_NAME" + DATABASE_HOSTNAME = "DATABASE_HOSTNAME" + DATABASE_PORT = "DATABASE_PORT" + DATABASE_USER = "DATABASE_USER" + DATABASE_PASSWORD = "DATABASE_PASSWORD" + DATABASE_MAX_IDLE_CONNECTIONS = "DATABASE_MAX_IDLE_CONNECTIONS" + DATABASE_MAX_OPEN_CONNECTIONS = "DATABASE_MAX_OPEN_CONNECTIONS" + DATABASE_MAX_CONN_LIFETIME = "DATABASE_MAX_CONN_LIFETIME" ) // GetEthNodeAndClient returns eth node info and client from path url func getEthNodeAndClient(path string) (node.Info, *rpc.Client, error) { - viper.BindEnv("ethereum.nodeID", ethNodeID) - viper.BindEnv("ethereum.clientName", ethClientName) - viper.BindEnv("ethereum.genesisBlock", ethGenesisBlock) - viper.BindEnv("ethereum.networkID", ethNetworkID) - viper.BindEnv("ethereum.chainID", ethChainID) + viper.BindEnv("ethereum.nodeID", ETH_NODE_ID) + viper.BindEnv("ethereum.clientName", ETH_CLIENT_NAME) + viper.BindEnv("ethereum.genesisBlock", ETH_GENESIS_BLOCK) + viper.BindEnv("ethereum.networkID", ETH_NETWORK_ID) + viper.BindEnv("ethereum.chainID", ETH_CHAIN_ID) rpcClient, err := rpc.Dial(path) if err != nil { diff --git a/pkg/serve/service.go b/pkg/serve/service.go index 82ab4bf1..ada685f8 100644 --- a/pkg/serve/service.go +++ b/pkg/serve/service.go @@ -83,6 +83,8 @@ type Service struct { supportsStateDiffing bool // backend for the server backend *eth.Backend + // whether to forward eth_calls directly to proxy node + forwardEthCalls bool } // NewServer creates a new Server using an underlying Service struct @@ -97,6 +99,7 @@ func NewServer(settings *Config) (Server, error) { sap.SubscriptionTypes = make(map[common.Hash]eth.SubscriptionSettings) sap.client = settings.Client sap.supportsStateDiffing = settings.SupportStateDiff + sap.forwardEthCalls = settings.ForwardEthCalls var err error sap.backend, err = eth.NewEthBackend(sap.db, ð.Config{ ChainConfig: settings.ChainConfig, @@ -130,10 +133,14 @@ func (sap *Service) APIs() []rpc.API { Public: true, }, } + ethAPI, err := eth.NewPublicEthAPI(sap.backend, sap.client, sap.supportsStateDiffing, sap.forwardEthCalls) + if err != nil { + log.Fatalf("unable to create public eth api: %v", err) + } return append(apis, rpc.API{ Namespace: eth.APIName, Version: eth.APIVersion, - Service: eth.NewPublicEthAPI(sap.backend, sap.client, sap.supportsStateDiffing), + Service: ethAPI, Public: true, }) } diff --git a/pkg/shared/functions.go b/pkg/shared/functions.go index aa9c4bd9..aaa72234 100644 --- a/pkg/shared/functions.go +++ b/pkg/shared/functions.go @@ -20,8 +20,8 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/statediff/indexer/ipfs/ipld" "github.com/ipfs/go-cid" - "github.com/ipfs/go-ipfs-blockstore" - "github.com/ipfs/go-ipfs-ds-help" + blockstore "github.com/ipfs/go-ipfs-blockstore" + dshelp "github.com/ipfs/go-ipfs-ds-help" node "github.com/ipfs/go-ipld-format" "github.com/jmoiron/sqlx" "github.com/sirupsen/logrus"