From 5ace847609560c528de16df3749c2f8b809eb39d Mon Sep 17 00:00:00 2001 From: Miguel Filipe Date: Mon, 22 Jul 2024 16:21:41 -0700 Subject: [PATCH] Scaffolding to support Arbitrum Nitro EVM stacks. preparatory work to support Arbitrum Nitro RPC nodes --- client/jsonrpc/arbitrum_nitro.go | 44 ++++++++++++++++++++++++++++++++ client/jsonrpc/client.go | 13 +++++++++- client/jsonrpc/models.go | 3 +++ client/jsonrpc/opstack.go | 7 ++--- cmd/main.go | 14 ++++------ models/evm.go | 2 +- 6 files changed, 67 insertions(+), 16 deletions(-) create mode 100644 client/jsonrpc/arbitrum_nitro.go diff --git a/client/jsonrpc/arbitrum_nitro.go b/client/jsonrpc/arbitrum_nitro.go new file mode 100644 index 0000000..ad5d257 --- /dev/null +++ b/client/jsonrpc/arbitrum_nitro.go @@ -0,0 +1,44 @@ +package jsonrpc + +import ( + "context" + "errors" + "log/slog" + "time" + + "github.com/duneanalytics/blockchain-ingester/models" +) + +type ArbitrumNitroClient struct { + rpcClient +} + +var _ BlockchainClient = &ArbitrumNitroClient{} + +func NewArbitrumNitroClient(log *slog.Logger, cfg Config) (*ArbitrumNitroClient, error) { + rpcClient, err := newClient(log.With("module", "jsonrpc"), cfg) + if err != nil { + return nil, err + } + return &ArbitrumNitroClient{*rpcClient}, nil +} + +// BlockByNumber returns the block with the given blockNumber. +// it uses 3 different methods to get the block: +// 1. eth_getBlockByNumber +// 2. debug_traceBlockByNumber with tracer "callTracer" +// TODO: this method should be optional +// 2. call to eth_getTransactionReceipt for each Tx present in the Block +// +// We encode the payload in NDJSON, and use a header line to indicate how many Tx are present in the block +func (c *ArbitrumNitroClient) BlockByNumber(_ context.Context, blockNumber int64) (models.RPCBlock, error) { + tStart := time.Now() + defer func() { + c.log.Debug("BlockByNumber", "blockNumber", blockNumber, "duration", time.Since(tStart)) + }() + // TODO: lets not implement this yet + return models.RPCBlock{ + BlockNumber: blockNumber, + Error: errors.New("not implemented"), + }, errors.New("not implemented") +} diff --git a/client/jsonrpc/client.go b/client/jsonrpc/client.go index 37bae2f..2ffc1f1 100644 --- a/client/jsonrpc/client.go +++ b/client/jsonrpc/client.go @@ -34,7 +34,18 @@ type rpcClient struct { httpHeaders map[string]string } -func NewClient(log *slog.Logger, cfg Config) (*rpcClient, error) { // revive:disable-line:unexported-return +func NewClient(logger *slog.Logger, cfg Config) (BlockchainClient, error) { + switch cfg.EVMStack { + case models.OpStack: + return NewOpStackClient(logger, cfg) + case models.ArbitrumNitro: + return NewArbitrumNitroClient(logger, cfg) + default: + return nil, fmt.Errorf("unsupported EVM stack: %s", cfg.EVMStack) + } +} + +func newClient(log *slog.Logger, cfg Config) (*rpcClient, error) { // revive:disable-line:unexported-return client := retryablehttp.NewClient() client.RetryMax = MaxRetries client.Logger = log diff --git a/client/jsonrpc/models.go b/client/jsonrpc/models.go index b46531a..df8f878 100644 --- a/client/jsonrpc/models.go +++ b/client/jsonrpc/models.go @@ -2,10 +2,13 @@ package jsonrpc import ( "time" + + "github.com/duneanalytics/blockchain-ingester/models" ) type Config struct { URL string PollInterval time.Duration HTTPHeaders map[string]string + EVMStack models.EVMStack } diff --git a/client/jsonrpc/opstack.go b/client/jsonrpc/opstack.go index 0029735..9f76655 100644 --- a/client/jsonrpc/opstack.go +++ b/client/jsonrpc/opstack.go @@ -18,7 +18,7 @@ type OpStackClient struct { var _ BlockchainClient = &OpStackClient{} func NewOpStackClient(log *slog.Logger, cfg Config) (*OpStackClient, error) { - rpcClient, err := NewClient(log.With("module", "jsonrpc"), cfg) + rpcClient, err := newClient(log.With("module", "jsonrpc"), cfg) if err != nil { return nil, err } @@ -37,10 +37,7 @@ func NewOpStackClient(log *slog.Logger, cfg Config) (*OpStackClient, error) { func (c *OpStackClient) BlockByNumber(ctx context.Context, blockNumber int64) (models.RPCBlock, error) { tStart := time.Now() defer func() { - c.log.Debug("BlockByNumber", - "blockNumber", blockNumber, - "duration", time.Since(tStart), - ) + c.log.Debug("BlockByNumber", "blockNumber", blockNumber, "duration", time.Since(tStart)) }() blockNumberHex := fmt.Sprintf("0x%x", blockNumber) diff --git a/cmd/main.go b/cmd/main.go index dd15eae..88a20db 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -85,15 +85,11 @@ func main() { logger.Info("Adding extra HTTP header to RPC requests", "key", key, "value", value) rpcHTTPHeaders[key] = value } - switch cfg.RPCStack { - case models.OpStack: - rpcClient, err = jsonrpc.NewOpStackClient(logger, jsonrpc.Config{ - URL: cfg.RPCNode.NodeURL, - HTTPHeaders: rpcHTTPHeaders, - }) - default: - stdlog.Fatalf("unsupported RPC stack: %s", cfg.RPCStack) - } + rpcClient, err = jsonrpc.NewClient(logger, jsonrpc.Config{ + URL: cfg.RPCNode.NodeURL, + HTTPHeaders: rpcHTTPHeaders, + EVMStack: cfg.RPCStack, + }) if err != nil { stdlog.Fatal(err) } diff --git a/models/evm.go b/models/evm.go index 3b2d8d2..a1a2a44 100644 --- a/models/evm.go +++ b/models/evm.go @@ -4,7 +4,7 @@ type EVMStack string const ( OpStack EVMStack = "opstack" - ArbitrumNitro EVMStack = "arbitrumnitro" + ArbitrumNitro EVMStack = "arbitrum-nitro" ) func (e EVMStack) String() string {