From bbe9ed764e00029f54baec9e7c51664ee36c489b Mon Sep 17 00:00:00 2001 From: maskpp Date: Mon, 22 Jan 2024 16:50:52 +0800 Subject: [PATCH] feat(rpc): simplify RPC clients (#521) --- .golangci.yml | 1 - cmd/utils/sub_command.go | 2 +- .../anchor_tx_constructor.go | 2 +- driver/chain_syncer/chain_syncer_test.go | 6 +- driver/driver_test.go | 12 +- go.mod | 5 + go.sum | 2 + internal/testutils/suite.go | 10 +- pkg/rpc/client.go | 90 ++++----------- pkg/rpc/dial.go | 52 +-------- pkg/rpc/dial_test.go | 6 +- pkg/rpc/engine.go | 20 +++- pkg/rpc/ethclient.go | 105 ++++++++++-------- pkg/rpc/methods.go | 11 +- pkg/rpc/methods_test.go | 2 +- pkg/rpc/utils.go | 13 +-- pkg/rpc/utils_test.go | 4 +- prover/proof_submitter/proof_contester.go | 2 +- prover/proof_submitter/proof_submitter.go | 2 +- prover/prover.go | 2 +- prover/prover_test.go | 8 +- 21 files changed, 151 insertions(+), 206 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index a3a1da31f..df2b8fa37 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -39,7 +39,6 @@ linters: - gofmt - ineffassign - importas - - lll - makezero - misspell - misspell diff --git a/cmd/utils/sub_command.go b/cmd/utils/sub_command.go index b9845eb7c..d4149a19e 100644 --- a/cmd/utils/sub_command.go +++ b/cmd/utils/sub_command.go @@ -25,7 +25,7 @@ func SubcommandAction(app SubcommandApplication) cli.ActionFunc { logger.InitLogger(c) ctx, ctxClose := context.WithCancel(context.Background()) - defer func() { ctxClose() }() + defer ctxClose() if err := app.InitFromCli(ctx, c); err != nil { return err diff --git a/driver/anchor_tx_constructor/anchor_tx_constructor.go b/driver/anchor_tx_constructor/anchor_tx_constructor.go index 309ec4641..2c19c4153 100644 --- a/driver/anchor_tx_constructor/anchor_tx_constructor.go +++ b/driver/anchor_tx_constructor/anchor_tx_constructor.go @@ -68,7 +68,7 @@ func (c *AnchorTxConstructor) AssembleAnchorTx( return nil, err } - signalRoot, err := c.rpc.GetStorageRoot(ctx, c.rpc.L1GethClient, c.signalServiceAddress, l1Height) + signalRoot, err := c.rpc.GetStorageRoot(ctx, c.rpc.L1, c.signalServiceAddress, l1Height) if err != nil { return nil, err } diff --git a/driver/chain_syncer/chain_syncer_test.go b/driver/chain_syncer/chain_syncer_test.go index beba6b918..196803813 100644 --- a/driver/chain_syncer/chain_syncer_test.go +++ b/driver/chain_syncer/chain_syncer_test.go @@ -136,15 +136,15 @@ func TestChainSyncerTestSuite(t *testing.T) { func (s *ChainSyncerTestSuite) TakeSnapshot() { // record snapshot state to revert to before changes - s.Nil(s.RPCClient.L1RawRPC.CallContext(context.Background(), &s.snapshotID, "evm_snapshot")) + s.Nil(s.RPCClient.L1.CallContext(context.Background(), &s.snapshotID, "evm_snapshot")) } func (s *ChainSyncerTestSuite) RevertSnapshot() { // revert to the snapshot state so protocol configs are unaffected var revertRes bool - s.Nil(s.RPCClient.L1RawRPC.CallContext(context.Background(), &revertRes, "evm_revert", s.snapshotID)) + s.Nil(s.RPCClient.L1.CallContext(context.Background(), &revertRes, "evm_revert", s.snapshotID)) s.True(revertRes) - s.Nil(rpc.SetHead(context.Background(), s.RPCClient.L2RawRPC, common.Big0)) + s.Nil(rpc.SetHead(context.Background(), s.RPCClient.L2, common.Big0)) } func (s *ChainSyncerTestSuite) TestAheadOfProtocolVerifiedHead() { diff --git a/driver/driver_test.go b/driver/driver_test.go index 7c465f3f7..ae63953ef 100644 --- a/driver/driver_test.go +++ b/driver/driver_test.go @@ -128,7 +128,7 @@ func (s *DriverTestSuite) TestProcessL1Blocks() { func (s *DriverTestSuite) TestCheckL1ReorgToHigherFork() { var testnetL1SnapshotID string - s.Nil(s.RPCClient.L1RawRPC.CallContext(context.Background(), &testnetL1SnapshotID, "evm_snapshot")) + s.Nil(s.RPCClient.L1.CallContext(context.Background(), &testnetL1SnapshotID, "evm_snapshot")) s.NotEmpty(testnetL1SnapshotID) l1Head1, err := s.d.rpc.L1.HeaderByNumber(context.Background(), nil) @@ -158,7 +158,7 @@ func (s *DriverTestSuite) TestCheckL1ReorgToHigherFork() { // Reorg back to l2Head1 var revertRes bool - s.Nil(s.RPCClient.L1RawRPC.CallContext(context.Background(), &revertRes, "evm_revert", testnetL1SnapshotID)) + s.Nil(s.RPCClient.L1.CallContext(context.Background(), &revertRes, "evm_revert", testnetL1SnapshotID)) s.True(revertRes) l1Head3, err := s.d.rpc.L1.HeaderByNumber(context.Background(), nil) @@ -191,7 +191,7 @@ func (s *DriverTestSuite) TestCheckL1ReorgToHigherFork() { func (s *DriverTestSuite) TestCheckL1ReorgToLowerFork() { var testnetL1SnapshotID string - s.Nil(s.RPCClient.L1RawRPC.CallContext(context.Background(), &testnetL1SnapshotID, "evm_snapshot")) + s.Nil(s.RPCClient.L1.CallContext(context.Background(), &testnetL1SnapshotID, "evm_snapshot")) s.NotEmpty(testnetL1SnapshotID) l1Head1, err := s.d.rpc.L1.HeaderByNumber(context.Background(), nil) @@ -221,7 +221,7 @@ func (s *DriverTestSuite) TestCheckL1ReorgToLowerFork() { // Reorg back to l2Head1 var revertRes bool - s.Nil(s.RPCClient.L1RawRPC.CallContext(context.Background(), &revertRes, "evm_revert", testnetL1SnapshotID)) + s.Nil(s.RPCClient.L1.CallContext(context.Background(), &revertRes, "evm_revert", testnetL1SnapshotID)) s.True(revertRes) l1Head3, err := s.d.rpc.L1.HeaderByNumber(context.Background(), nil) @@ -251,7 +251,7 @@ func (s *DriverTestSuite) TestCheckL1ReorgToLowerFork() { func (s *DriverTestSuite) TestCheckL1ReorgToSameHeightFork() { var testnetL1SnapshotID string - s.Nil(s.RPCClient.L1RawRPC.CallContext(context.Background(), &testnetL1SnapshotID, "evm_snapshot")) + s.Nil(s.RPCClient.L1.CallContext(context.Background(), &testnetL1SnapshotID, "evm_snapshot")) s.NotEmpty(testnetL1SnapshotID) l1Head1, err := s.d.rpc.L1.HeaderByNumber(context.Background(), nil) @@ -281,7 +281,7 @@ func (s *DriverTestSuite) TestCheckL1ReorgToSameHeightFork() { // Reorg back to l2Head1 var revertRes bool - s.Nil(s.RPCClient.L1RawRPC.CallContext(context.Background(), &revertRes, "evm_revert", testnetL1SnapshotID)) + s.Nil(s.RPCClient.L1.CallContext(context.Background(), &revertRes, "evm_revert", testnetL1SnapshotID)) s.True(revertRes) l1Head3, err := s.d.rpc.L1.HeaderByNumber(context.Background(), nil) diff --git a/go.mod b/go.mod index 27d77c0ea..f1cd54e84 100644 --- a/go.mod +++ b/go.mod @@ -40,6 +40,7 @@ require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/deckarep/golang-set/v2 v2.1.0 // indirect github.com/ethereum/c-kzg-4844 v0.4.0 // indirect + github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 // indirect github.com/getsentry/sentry-go v0.18.0 // indirect @@ -56,6 +57,7 @@ require ( github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect github.com/google/uuid v1.3.0 // indirect github.com/gorilla/websocket v1.5.0 // indirect + github.com/hashicorp/go-bexpr v0.1.10 // indirect github.com/holiman/bloomfilter/v2 v2.0.3 // indirect github.com/holiman/uint256 v1.2.4 // indirect github.com/huin/goupnp v1.3.0 // indirect @@ -73,6 +75,7 @@ require ( github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/minio/sha256-simd v1.0.0 // indirect github.com/mitchellh/mapstructure v1.4.1 // indirect + github.com/mitchellh/pointerstructure v1.2.0 // indirect github.com/mmcloughlin/addchain v0.4.0 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect @@ -86,6 +89,7 @@ require ( github.com/prysmaticlabs/gohashtree v0.0.3-alpha // indirect github.com/rivo/uniseg v0.4.3 // indirect github.com/rogpeppe/go-internal v1.9.0 // indirect + github.com/rs/cors v1.7.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect github.com/sirupsen/logrus v1.9.0 // indirect @@ -107,6 +111,7 @@ require ( golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.15.0 // indirect google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect rsc.io/tmplfunc v0.0.3 // indirect diff --git a/go.sum b/go.sum index 70b907c40..02257499d 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,8 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= +github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno= github.com/CloudyKit/jet/v3 v3.0.0/go.mod h1:HKQPgSJmdK8hdoAbKUUWajkHyHo4RaU5rMdUywE7VMo= github.com/DataDog/zstd v1.5.2 h1:vUG4lAyuPCXO0TLbXvPv7EB7cNK1QV/luu55UHLrrn8= diff --git a/internal/testutils/suite.go b/internal/testutils/suite.go index 709f563d7..f51216307 100644 --- a/internal/testutils/suite.go +++ b/internal/testutils/suite.go @@ -121,7 +121,7 @@ func (s *ClientTestSuite) SetupTest() { _, err = rpc.WaitReceipt(context.Background(), rpcCli.L1, tx) s.Nil(err) } - s.Nil(rpcCli.L1RawRPC.CallContext(context.Background(), &s.testnetL1SnapshotID, "evm_snapshot")) + s.Nil(rpcCli.L1.CallContext(context.Background(), &s.testnetL1SnapshotID, "evm_snapshot")) s.NotEmpty(s.testnetL1SnapshotID) } @@ -175,19 +175,19 @@ func (s *ClientTestSuite) setAddress(ownerPrivKey *ecdsa.PrivateKey, name [32]by func (s *ClientTestSuite) TearDownTest() { var revertRes bool - s.Nil(s.RPCClient.L1RawRPC.CallContext(context.Background(), &revertRes, "evm_revert", s.testnetL1SnapshotID)) + s.Nil(s.RPCClient.L1.CallContext(context.Background(), &revertRes, "evm_revert", s.testnetL1SnapshotID)) s.True(revertRes) - s.Nil(rpc.SetHead(context.Background(), s.RPCClient.L2RawRPC, common.Big0)) + s.Nil(rpc.SetHead(context.Background(), s.RPCClient.L2, common.Big0)) s.Nil(s.proverServer.Shutdown(context.Background())) } func (s *ClientTestSuite) SetL1Automine(automine bool) { - s.Nil(s.RPCClient.L1RawRPC.CallContext(context.Background(), nil, "evm_setAutomine", automine)) + s.Nil(s.RPCClient.L1.CallContext(context.Background(), nil, "evm_setAutomine", automine)) } func (s *ClientTestSuite) IncreaseTime(time uint64) { var result uint64 - s.Nil(s.RPCClient.L1RawRPC.CallContext(context.Background(), &result, "evm_increaseTime", time)) + s.Nil(s.RPCClient.L1.CallContext(context.Background(), &result, "evm_increaseTime", time)) s.NotNil(result) } diff --git a/pkg/rpc/client.go b/pkg/rpc/client.go index fcdae30f0..52a2187fe 100644 --- a/pkg/rpc/client.go +++ b/pkg/rpc/client.go @@ -8,9 +8,6 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethclient/gethclient" - "github.com/ethereum/go-ethereum/rpc" - "github.com/taikoxyz/taiko-client/bindings" ) @@ -24,12 +21,6 @@ type Client struct { L1 *EthClient L2 *EthClient L2CheckPoint *EthClient - // Geth gethclient clients - L1GethClient *gethclient.Client - L2GethClient *gethclient.Client - // Geth raw RPC clients - L1RawRPC *rpc.Client - L2RawRPC *rpc.Client // Geth Engine API clients L2Engine *EngineClient // Protocol contracts clients @@ -65,33 +56,32 @@ func NewClient(ctx context.Context, cfg *ClientConfig) (*Client, error) { ctxWithTimeout, cancel := ctxWithTimeoutOrDefault(ctx, defaultTimeout) defer cancel() - if cfg.BackOffMaxRetries == 0 { - cfg.BackOffMaxRetries = 10 + l1Client, err := NewEthClient(ctxWithTimeout, cfg.L1Endpoint, cfg.Timeout) + if err != nil { + return nil, err } - l1EthClient, err := DialClientWithBackoff(ctxWithTimeout, cfg.L1Endpoint, cfg.RetryInterval, cfg.BackOffMaxRetries) + l2Client, err := NewEthClient(ctxWithTimeout, cfg.L2Endpoint, cfg.Timeout) if err != nil { return nil, err } - l2EthClient, err := DialClientWithBackoff(ctxWithTimeout, cfg.L2Endpoint, cfg.RetryInterval, cfg.BackOffMaxRetries) + l1ChainID, err := l1Client.ChainID(ctxWithTimeout) if err != nil { return nil, err } - var ( - l1RPC *EthClient - l2RPC *EthClient - ) - l1RPC = NewEthClientWithTimeout(l1EthClient, cfg.Timeout) - l2RPC = NewEthClientWithTimeout(l2EthClient, cfg.Timeout) + l2ChainID, err := l2Client.ChainID(ctxWithTimeout) + if err != nil { + return nil, err + } - taikoL1, err := bindings.NewTaikoL1Client(cfg.TaikoL1Address, l1RPC) + taikoL1, err := bindings.NewTaikoL1Client(cfg.TaikoL1Address, l1Client) if err != nil { return nil, err } - taikoL2, err := bindings.NewTaikoL2Client(cfg.TaikoL2Address, l2RPC) + taikoL2, err := bindings.NewTaikoL2Client(cfg.TaikoL2Address, l2Client) if err != nil { return nil, err } @@ -101,12 +91,12 @@ func NewClient(ctx context.Context, cfg *ClientConfig) (*Client, error) { guardianProver *bindings.GuardianProver ) if cfg.TaikoTokenAddress.Hex() != ZeroAddress.Hex() { - if taikoToken, err = bindings.NewTaikoToken(cfg.TaikoTokenAddress, l1RPC); err != nil { + if taikoToken, err = bindings.NewTaikoToken(cfg.TaikoTokenAddress, l1Client); err != nil { return nil, err } } if cfg.GuardianProverAddress.Hex() != ZeroAddress.Hex() { - if guardianProver, err = bindings.NewGuardianProver(cfg.GuardianProverAddress, l1RPC); err != nil { + if guardianProver, err = bindings.NewGuardianProver(cfg.GuardianProverAddress, l1Client); err != nil { return nil, err } } @@ -115,73 +105,37 @@ func NewClient(ctx context.Context, cfg *ClientConfig) (*Client, error) { if err != nil { return nil, err } - - isArchive, err := IsArchiveNode(ctxWithTimeout, l1RPC, stateVars.A.GenesisHeight) + isArchive, err := IsArchiveNode(ctxWithTimeout, l1Client, stateVars.A.GenesisHeight) if err != nil { return nil, err } - if !isArchive { return nil, fmt.Errorf("error with RPC endpoint: node (%s) must be archive node", cfg.L1Endpoint) } - l1RawRPC, err := rpc.Dial(cfg.L1Endpoint) - if err != nil { - return nil, err - } - - l2RawRPC, err := rpc.Dial(cfg.L2Endpoint) - if err != nil { - return nil, err - } - - l1ChainID, err := l1RPC.ChainID(ctxWithTimeout) - if err != nil { - return nil, err - } - - l2ChainID, err := l2RPC.ChainID(ctxWithTimeout) - if err != nil { - return nil, err - } - // If not providing L2EngineEndpoint or JwtSecret, then the L2Engine client // won't be initialized. - var l2AuthRPC *EngineClient + var l2AuthClient *EngineClient if len(cfg.L2EngineEndpoint) != 0 && len(cfg.JwtSecret) != 0 { - if l2AuthRPC, err = DialEngineClientWithBackoff( - ctxWithTimeout, - cfg.L2EngineEndpoint, - cfg.JwtSecret, - cfg.RetryInterval, - cfg.BackOffMaxRetries, - ); err != nil { + l2AuthClient, err = NewJWTEngineClient(cfg.L2EngineEndpoint, cfg.JwtSecret) + if err != nil { return nil, err } } var l2CheckPoint *EthClient - if len(cfg.L2CheckPoint) != 0 { - l2CheckPointEthClient, err := DialClientWithBackoff( - ctxWithTimeout, - cfg.L2CheckPoint, - cfg.RetryInterval, - cfg.BackOffMaxRetries) + if cfg.L2CheckPoint != "" { + l2CheckPoint, err = NewEthClient(ctxWithTimeout, cfg.L2CheckPoint, cfg.Timeout) if err != nil { return nil, err } - l2CheckPoint = NewEthClientWithTimeout(l2CheckPointEthClient, cfg.Timeout) } client := &Client{ - L1: l1RPC, - L2: l2RPC, + L1: l1Client, + L2: l2Client, L2CheckPoint: l2CheckPoint, - L1RawRPC: l1RawRPC, - L2RawRPC: l2RawRPC, - L1GethClient: gethclient.New(l1RawRPC), - L2GethClient: gethclient.New(l2RawRPC), - L2Engine: l2AuthRPC, + L2Engine: l2AuthClient, TaikoL1: taikoL1, TaikoL2: taikoL2, TaikoToken: taikoToken, diff --git a/pkg/rpc/dial.go b/pkg/rpc/dial.go index 6d7fee94f..985ec0db5 100644 --- a/pkg/rpc/dial.go +++ b/pkg/rpc/dial.go @@ -2,16 +2,13 @@ package rpc import ( "context" - "fmt" - "net/url" "time" "github.com/cenkalti/backoff/v4" "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/rpc" - "github.com/prysmaticlabs/prysm/v4/network" - "github.com/prysmaticlabs/prysm/v4/network/authorization" ) // DialClientWithBackoff connects a ethereum RPC client at the given URL with @@ -58,7 +55,8 @@ func DialEngineClientWithBackoff( ctxWithTimeout, cancel := ctxWithTimeoutOrDefault(ctx, defaultTimeout) defer cancel() - client, err := DialEngineClient(ctxWithTimeout, url, jwtSecret) + jwtAuth := node.NewJWTAuth(StringToBytes32(jwtSecret)) + client, err := rpc.DialOptions(ctxWithTimeout, url, rpc.WithHTTPAuth(jwtAuth)) if err != nil { log.Error("Dial engine client error", "url", url, "error", err) return err @@ -74,47 +72,3 @@ func DialEngineClientWithBackoff( return engineClient, nil } - -// DialEngineClient initializes an RPC connection with authentication headers. -// Taken from https://github.com/prysmaticlabs/prysm/blob/v2.1.4/beacon-chain/execution/rpc_connection.go#L151 -func DialEngineClient(ctx context.Context, endpointURL string, jwtSecret string) (*rpc.Client, error) { - ctxWithTimeout, cancel := ctxWithTimeoutOrDefault(ctx, defaultTimeout) - defer cancel() - - endpoint := network.Endpoint{ - Url: endpointURL, - Auth: network.AuthorizationData{ - Method: authorization.Bearer, - Value: jwtSecret, - }, - } - - // Need to handle ipc and http - var client *rpc.Client - u, err := url.Parse(endpoint.Url) - if err != nil { - return nil, err - } - switch u.Scheme { - case "http", "https": - client, err = rpc.DialOptions(ctxWithTimeout, endpoint.Url, rpc.WithHTTPClient(endpoint.HttpClient())) - if err != nil { - return nil, err - } - case "": - client, err = rpc.DialIPC(ctxWithTimeout, endpoint.Url) - if err != nil { - return nil, err - } - default: - return nil, fmt.Errorf("no known transport for URL scheme %q", u.Scheme) - } - if endpoint.Auth.Method != authorization.None { - header, err := endpoint.Auth.ToHeaderValue() - if err != nil { - return nil, err - } - client.SetHeader("Authorization", header) - } - return client, nil -} diff --git a/pkg/rpc/dial_test.go b/pkg/rpc/dial_test.go index f01ccd4cc..94630bb6c 100644 --- a/pkg/rpc/dial_test.go +++ b/pkg/rpc/dial_test.go @@ -9,6 +9,7 @@ import ( "github.com/ethereum/go-ethereum/beacon/engine" "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" + "github.com/taikoxyz/taiko-client/pkg/jwt" ) @@ -78,8 +79,3 @@ func TestDialEngineClientWithBackoff_CtxError(t *testing.T) { ) require.NotNil(t, err2) } - -func TestDialEngineClient_UrlError(t *testing.T) { - _, err := DialEngineClient(context.Background(), "invalid", "invalid") - require.NotNil(t, err) -} diff --git a/pkg/rpc/engine.go b/pkg/rpc/engine.go index 293e37c4b..bee6eef0a 100644 --- a/pkg/rpc/engine.go +++ b/pkg/rpc/engine.go @@ -2,8 +2,11 @@ package rpc import ( "context" + "fmt" "github.com/ethereum/go-ethereum/beacon/engine" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/rpc" ) @@ -14,6 +17,21 @@ type EngineClient struct { *rpc.Client } +func NewJWTEngineClient(url, jwtSecret string) (*EngineClient, error) { + var jwt = StringToBytes32(jwtSecret) + if jwt == (common.Hash{}) || url == "" { + return nil, fmt.Errorf("url is empty or jwt secret is illegal") + } + authClient, err := rpc.DialOptions(context.Background(), url, rpc.WithHTTPAuth(node.NewJWTAuth(jwt))) + if err != nil { + return nil, err + } + + return &EngineClient{ + Client: authClient, + }, nil +} + // ForkchoiceUpdate updates the forkchoice on the execution client. func (c *EngineClient) ForkchoiceUpdate( ctx context.Context, @@ -31,7 +49,7 @@ func (c *EngineClient) ForkchoiceUpdate( return result, nil } -// ExecutePayload executes a built block on the execution engine. +// NewPayload executes a built block on the execution engine. func (c *EngineClient) NewPayload( ctx context.Context, payload *engine.ExecutableData, diff --git a/pkg/rpc/ethclient.go b/pkg/rpc/ethclient.go index e2dfe41e1..9c51ab810 100644 --- a/pkg/rpc/ethclient.go +++ b/pkg/rpc/ethclient.go @@ -5,31 +5,48 @@ import ( "math/big" "time" - ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient" + "github.com/ethereum/go-ethereum/ethclient/gethclient" + "github.com/ethereum/go-ethereum/rpc" ) -// EthClient is a wrapper for go-ethereum ethclient with a timeout attached. -type EthClient struct { +type gethClient struct { + *gethclient.Client +} + +type ethClient struct { *ethclient.Client +} + +// EthClient is a wrapper for go-ethereum eth client with a timeout attached. +type EthClient struct { + *rpc.Client + *gethClient + *ethClient + timeout time.Duration } -// NewEthClientWithTimeout creates a new EthClient instance with the given -// request timeout. -func NewEthClientWithTimeout( - ethclient *ethclient.Client, - timeout time.Duration, -) *EthClient { - if ethclient == nil { - return nil +func NewEthClient(ctx context.Context, url string, timeout time.Duration) (*EthClient, error) { + var timeoutVal = defaultTimeout + if timeout != 0 { + timeoutVal = timeout } - if timeout == 0 { - timeout = defaultTimeout + + client, err := rpc.DialContext(ctx, url) + if err != nil { + return nil, err } - return &EthClient{Client: ethclient, timeout: timeout} + + return &EthClient{ + Client: client, + gethClient: &gethClient{gethclient.New(client)}, + ethClient: ðClient{ethclient.NewClient(client)}, + timeout: timeoutVal, + }, nil } // ChainID retrieves the current chain ID for transaction replay protection. @@ -37,7 +54,7 @@ func (c *EthClient) ChainID(ctx context.Context) (*big.Int, error) { ctxWithTimeout, cancel := ctxWithTimeoutOrDefault(ctx, c.timeout) defer cancel() - return c.Client.ChainID(ctxWithTimeout) + return c.ethClient.ChainID(ctxWithTimeout) } // BlockByHash returns the given full block. @@ -48,7 +65,7 @@ func (c *EthClient) BlockByHash(ctx context.Context, hash common.Hash) (*types.B ctxWithTimeout, cancel := ctxWithTimeoutOrDefault(ctx, c.timeout) defer cancel() - return c.Client.BlockByHash(ctxWithTimeout, hash) + return c.ethClient.BlockByHash(ctxWithTimeout, hash) } // BlockByNumber returns a block from the current canonical chain. If number is nil, the @@ -60,7 +77,7 @@ func (c *EthClient) BlockByNumber(ctx context.Context, number *big.Int) (*types. ctxWithTimeout, cancel := ctxWithTimeoutOrDefault(ctx, c.timeout) defer cancel() - return c.Client.BlockByNumber(ctxWithTimeout, number) + return c.ethClient.BlockByNumber(ctxWithTimeout, number) } // BlockNumber returns the most recent block number @@ -68,7 +85,7 @@ func (c *EthClient) BlockNumber(ctx context.Context) (uint64, error) { ctxWithTimeout, cancel := ctxWithTimeoutOrDefault(ctx, c.timeout) defer cancel() - return c.Client.BlockNumber(ctxWithTimeout) + return c.ethClient.BlockNumber(ctxWithTimeout) } // PeerCount returns the number of p2p peers as reported by the net_peerCount method. @@ -76,7 +93,7 @@ func (c *EthClient) PeerCount(ctx context.Context) (uint64, error) { ctxWithTimeout, cancel := ctxWithTimeoutOrDefault(ctx, c.timeout) defer cancel() - return c.Client.PeerCount(ctxWithTimeout) + return c.ethClient.PeerCount(ctxWithTimeout) } // HeaderByHash returns the block header with the given hash. @@ -84,7 +101,7 @@ func (c *EthClient) HeaderByHash(ctx context.Context, hash common.Hash) (*types. ctxWithTimeout, cancel := ctxWithTimeoutOrDefault(ctx, c.timeout) defer cancel() - return c.Client.HeaderByHash(ctxWithTimeout, hash) + return c.ethClient.HeaderByHash(ctxWithTimeout, hash) } // HeaderByNumber returns a block header from the current canonical chain. If number is @@ -93,7 +110,7 @@ func (c *EthClient) HeaderByNumber(ctx context.Context, number *big.Int) (*types ctxWithTimeout, cancel := ctxWithTimeoutOrDefault(ctx, c.timeout) defer cancel() - return c.Client.HeaderByNumber(ctxWithTimeout, number) + return c.ethClient.HeaderByNumber(ctxWithTimeout, number) } // TransactionByHash returns the transaction with the given hash. @@ -104,7 +121,7 @@ func (c *EthClient) TransactionByHash( ctxWithTimeout, cancel := ctxWithTimeoutOrDefault(ctx, c.timeout) defer cancel() - return c.Client.TransactionByHash(ctxWithTimeout, hash) + return c.ethClient.TransactionByHash(ctxWithTimeout, hash) } // TransactionSender returns the sender address of the given transaction. The transaction @@ -122,7 +139,7 @@ func (c *EthClient) TransactionSender( ctxWithTimeout, cancel := ctxWithTimeoutOrDefault(ctx, c.timeout) defer cancel() - return c.Client.TransactionSender(ctxWithTimeout, tx, block, index) + return c.ethClient.TransactionSender(ctxWithTimeout, tx, block, index) } // TransactionCount returns the total number of transactions in the given block. @@ -130,7 +147,7 @@ func (c *EthClient) TransactionCount(ctx context.Context, blockHash common.Hash) ctxWithTimeout, cancel := ctxWithTimeoutOrDefault(ctx, c.timeout) defer cancel() - return c.Client.TransactionCount(ctxWithTimeout, blockHash) + return c.ethClient.TransactionCount(ctxWithTimeout, blockHash) } // TransactionInBlock returns a single transaction at index in the given block. @@ -142,7 +159,7 @@ func (c *EthClient) TransactionInBlock( ctxWithTimeout, cancel := ctxWithTimeoutOrDefault(ctx, c.timeout) defer cancel() - return c.Client.TransactionInBlock(ctxWithTimeout, blockHash, index) + return c.ethClient.TransactionInBlock(ctxWithTimeout, blockHash, index) } // SyncProgress retrieves the current progress of the sync algorithm. If there's @@ -151,7 +168,7 @@ func (c *EthClient) SyncProgress(ctx context.Context) (*ethereum.SyncProgress, e ctxWithTimeout, cancel := ctxWithTimeoutOrDefault(ctx, c.timeout) defer cancel() - return c.Client.SyncProgress(ctxWithTimeout) + return c.ethClient.SyncProgress(ctxWithTimeout) } // NetworkID returns the network ID for this client. @@ -159,7 +176,7 @@ func (c *EthClient) NetworkID(ctx context.Context) (*big.Int, error) { ctxWithTimeout, cancel := ctxWithTimeoutOrDefault(ctx, c.timeout) defer cancel() - return c.Client.NetworkID(ctxWithTimeout) + return c.ethClient.NetworkID(ctxWithTimeout) } // BalanceAt returns the wei balance of the given account. @@ -172,7 +189,7 @@ func (c *EthClient) BalanceAt( ctxWithTimeout, cancel := ctxWithTimeoutOrDefault(ctx, c.timeout) defer cancel() - return c.Client.BalanceAt(ctxWithTimeout, account, blockNumber) + return c.ethClient.BalanceAt(ctxWithTimeout, account, blockNumber) } // StorageAt returns the value of key in the contract storage of the given account. @@ -186,7 +203,7 @@ func (c *EthClient) StorageAt( ctxWithTimeout, cancel := ctxWithTimeoutOrDefault(ctx, c.timeout) defer cancel() - return c.Client.StorageAt(ctxWithTimeout, account, key, blockNumber) + return c.ethClient.StorageAt(ctxWithTimeout, account, key, blockNumber) } // CodeAt returns the contract code of the given account. @@ -199,7 +216,7 @@ func (c *EthClient) CodeAt( ctxWithTimeout, cancel := ctxWithTimeoutOrDefault(ctx, c.timeout) defer cancel() - return c.Client.CodeAt(ctxWithTimeout, account, blockNumber) + return c.ethClient.CodeAt(ctxWithTimeout, account, blockNumber) } // NonceAt returns the account nonce of the given account. @@ -212,7 +229,7 @@ func (c *EthClient) NonceAt( ctxWithTimeout, cancel := ctxWithTimeoutOrDefault(ctx, c.timeout) defer cancel() - return c.Client.NonceAt(ctxWithTimeout, account, blockNumber) + return c.ethClient.NonceAt(ctxWithTimeout, account, blockNumber) } // PendingBalanceAt returns the wei balance of the given account in the pending state. @@ -220,7 +237,7 @@ func (c *EthClient) PendingBalanceAt(ctx context.Context, account common.Address ctxWithTimeout, cancel := ctxWithTimeoutOrDefault(ctx, c.timeout) defer cancel() - return c.Client.PendingBalanceAt(ctxWithTimeout, account) + return c.ethClient.PendingBalanceAt(ctxWithTimeout, account) } // PendingStorageAt returns the value of key in the contract storage of the given account in the pending state. @@ -232,7 +249,7 @@ func (c *EthClient) PendingStorageAt( ctxWithTimeout, cancel := ctxWithTimeoutOrDefault(ctx, c.timeout) defer cancel() - return c.Client.PendingStorageAt(ctxWithTimeout, account, key) + return c.ethClient.PendingStorageAt(ctxWithTimeout, account, key) } // PendingCodeAt returns the contract code of the given account in the pending state. @@ -240,7 +257,7 @@ func (c *EthClient) PendingCodeAt(ctx context.Context, account common.Address) ( ctxWithTimeout, cancel := ctxWithTimeoutOrDefault(ctx, c.timeout) defer cancel() - return c.Client.PendingCodeAt(ctxWithTimeout, account) + return c.ethClient.PendingCodeAt(ctxWithTimeout, account) } // PendingNonceAt returns the account nonce of the given account in the pending state. @@ -249,7 +266,7 @@ func (c *EthClient) PendingNonceAt(ctx context.Context, account common.Address) ctxWithTimeout, cancel := ctxWithTimeoutOrDefault(ctx, c.timeout) defer cancel() - return c.Client.PendingNonceAt(ctxWithTimeout, account) + return c.ethClient.PendingNonceAt(ctxWithTimeout, account) } // PendingTransactionCount returns the total number of transactions in the pending state. @@ -257,7 +274,7 @@ func (c *EthClient) PendingTransactionCount(ctx context.Context) (uint, error) { ctxWithTimeout, cancel := ctxWithTimeoutOrDefault(ctx, c.timeout) defer cancel() - return c.Client.PendingTransactionCount(ctxWithTimeout) + return c.ethClient.PendingTransactionCount(ctxWithTimeout) } // CallContract executes a message call transaction, which is directly executed in the VM @@ -274,7 +291,7 @@ func (c *EthClient) CallContract( ctxWithTimeout, cancel := ctxWithTimeoutOrDefault(ctx, c.timeout) defer cancel() - return c.Client.CallContract(ctxWithTimeout, msg, blockNumber) + return c.ethClient.CallContract(ctxWithTimeout, msg, blockNumber) } // CallContractAtHash is almost the same as CallContract except that it selects @@ -287,7 +304,7 @@ func (c *EthClient) CallContractAtHash( ctxWithTimeout, cancel := ctxWithTimeoutOrDefault(ctx, c.timeout) defer cancel() - return c.Client.CallContractAtHash(ctxWithTimeout, msg, blockHash) + return c.ethClient.CallContractAtHash(ctxWithTimeout, msg, blockHash) } // PendingCallContract executes a message call transaction using the EVM. @@ -296,7 +313,7 @@ func (c *EthClient) PendingCallContract(ctx context.Context, msg ethereum.CallMs ctxWithTimeout, cancel := ctxWithTimeoutOrDefault(ctx, c.timeout) defer cancel() - return c.Client.PendingCallContract(ctxWithTimeout, msg) + return c.ethClient.PendingCallContract(ctxWithTimeout, msg) } // SuggestGasPrice retrieves the currently suggested gas price to allow a timely @@ -305,7 +322,7 @@ func (c *EthClient) SuggestGasPrice(ctx context.Context) (*big.Int, error) { ctxWithTimeout, cancel := ctxWithTimeoutOrDefault(ctx, c.timeout) defer cancel() - return c.Client.SuggestGasPrice(ctxWithTimeout) + return c.ethClient.SuggestGasPrice(ctxWithTimeout) } // SuggestGasTipCap retrieves the currently suggested gas tip cap after 1559 to @@ -314,7 +331,7 @@ func (c *EthClient) SuggestGasTipCap(ctx context.Context) (*big.Int, error) { ctxWithTimeout, cancel := ctxWithTimeoutOrDefault(ctx, c.timeout) defer cancel() - return c.Client.SuggestGasTipCap(ctxWithTimeout) + return c.ethClient.SuggestGasTipCap(ctxWithTimeout) } // FeeHistory retrieves the fee market history. @@ -327,7 +344,7 @@ func (c *EthClient) FeeHistory( ctxWithTimeout, cancel := ctxWithTimeoutOrDefault(ctx, c.timeout) defer cancel() - return c.Client.FeeHistory(ctxWithTimeout, blockCount, lastBlock, rewardPercentiles) + return c.ethClient.FeeHistory(ctxWithTimeout, blockCount, lastBlock, rewardPercentiles) } // EstimateGas tries to estimate the gas needed to execute a specific transaction based on @@ -338,7 +355,7 @@ func (c *EthClient) EstimateGas(ctx context.Context, msg ethereum.CallMsg) (uint ctxWithTimeout, cancel := ctxWithTimeoutOrDefault(ctx, c.timeout) defer cancel() - return c.Client.EstimateGas(ctxWithTimeout, msg) + return c.ethClient.EstimateGas(ctxWithTimeout, msg) } // SendTransaction injects a signed transaction into the pending pool for execution. @@ -349,5 +366,5 @@ func (c *EthClient) SendTransaction(ctx context.Context, tx *types.Transaction) ctxWithTimeout, cancel := ctxWithTimeoutOrDefault(ctx, c.timeout) defer cancel() - return c.Client.SendTransaction(ctxWithTimeout, tx) + return c.ethClient.SendTransaction(ctxWithTimeout, tx) } diff --git a/pkg/rpc/methods.go b/pkg/rpc/methods.go index 6b67387eb..c5c36906a 100644 --- a/pkg/rpc/methods.go +++ b/pkg/rpc/methods.go @@ -14,7 +14,6 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/ethclient/gethclient" "github.com/ethereum/go-ethereum/log" "golang.org/x/sync/errgroup" @@ -249,7 +248,7 @@ func (c *Client) GetPoolContent( } var result []types.Transactions - err := c.L2RawRPC.CallContext( + err := c.L2.CallContext( ctxWithTimeout, &result, "taiko_txPoolContent", @@ -275,7 +274,7 @@ func (c *Client) L2AccountNonce( defer cancel() var result hexutil.Uint64 - err := c.L2RawRPC.CallContext(ctxWithTimeout, &result, "eth_getTransactionCount", account, hexutil.EncodeBig(height)) + err := c.L2.CallContext(ctxWithTimeout, &result, "eth_getTransactionCount", account, hexutil.EncodeBig(height)) return uint64(result), err } @@ -365,14 +364,14 @@ func (c *Client) GetProtocolStateVariables(opts *bind.CallOpts) (*struct { // GetStorageRoot returns a contract's storage root at the given height. func (c *Client) GetStorageRoot( ctx context.Context, - gethclient *gethclient.Client, + client *EthClient, contract common.Address, height *big.Int, ) (common.Hash, error) { ctxWithTimeout, cancel := ctxWithTimeoutOrDefault(ctx, defaultTimeout) defer cancel() - proof, err := gethclient.GetProof( + proof, err := client.GetProof( ctxWithTimeout, contract, []string{"0x0000000000000000000000000000000000000000000000000000000000000000"}, @@ -562,7 +561,7 @@ func (c *Client) checkSyncedL1SnippetFromAnchor( return true, nil } - currentRoot, err := c.GetStorageRoot(ctx, c.L1GethClient, l1SignalService, l1Header.Number) + currentRoot, err := c.GetStorageRoot(ctx, c.L1, l1SignalService, l1Header.Number) if err != nil { return false, err } diff --git a/pkg/rpc/methods_test.go b/pkg/rpc/methods_test.go index 4705f8242..b35549afe 100644 --- a/pkg/rpc/methods_test.go +++ b/pkg/rpc/methods_test.go @@ -185,7 +185,7 @@ func TestGetStorageRootNewestBlock(t *testing.T) { client := newTestClient(t) _, err := client.GetStorageRoot( context.Background(), - client.L1GethClient, + client.L1, common.HexToAddress(os.Getenv("L1_SIGNAL_SERVICE_CONTRACT_ADDRESS")), nil) require.Nil(t, err) diff --git a/pkg/rpc/utils.go b/pkg/rpc/utils.go index 70fe07178..002328e48 100644 --- a/pkg/rpc/utils.go +++ b/pkg/rpc/utils.go @@ -13,10 +13,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/ethclient/gethclient" "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/rpc" - "github.com/taikoxyz/taiko-client/bindings" "github.com/taikoxyz/taiko-client/bindings/encoding" "github.com/taikoxyz/taiko-client/internal/utils" @@ -201,7 +198,7 @@ func GetBlockProofStatus( return nil, err } - root, err := cli.GetStorageRoot(ctx, cli.L2GethClient, l2SignalService, id) + root, err := cli.GetStorageRoot(ctx, cli.L2, l2SignalService, id) if err != nil { return nil, err } @@ -264,7 +261,7 @@ type AccountPoolContent map[string]map[string]*types.Transaction // ContentFrom fetches a given account's transactions list from a node's transactions pool. func ContentFrom( ctx context.Context, - rawRPC *rpc.Client, + rawRPC *EthClient, address common.Address, ) (AccountPoolContent, error) { ctxWithTimeout, cancel := ctxWithTimeoutOrDefault(ctx, defaultTimeout) @@ -338,7 +335,7 @@ func GetPendingTxByNonce( ctxWithTimeout, cancel := ctxWithTimeoutOrDefault(ctx, defaultTimeout) defer cancel() - content, err := ContentFrom(ctxWithTimeout, cli.L1RawRPC, address) + content, err := ContentFrom(ctxWithTimeout, cli.L1, address) if err != nil { return nil, err } @@ -356,11 +353,11 @@ func GetPendingTxByNonce( // SetHead makes a `debug_setHead` RPC call to set the chain's head, should only be used // for testing purpose. -func SetHead(ctx context.Context, rpc *rpc.Client, headNum *big.Int) error { +func SetHead(ctx context.Context, client *EthClient, headNum *big.Int) error { ctxWithTimeout, cancel := ctxWithTimeoutOrDefault(ctx, defaultTimeout) defer cancel() - return gethclient.New(rpc).SetHead(ctxWithTimeout, headNum) + return client.SetHead(ctxWithTimeout, headNum) } // StringToBytes32 converts the given string to [32]byte. diff --git a/pkg/rpc/utils_test.go b/pkg/rpc/utils_test.go index c548208cf..91a16908c 100644 --- a/pkg/rpc/utils_test.go +++ b/pkg/rpc/utils_test.go @@ -27,7 +27,7 @@ func TestWaitReceiptTimeout(t *testing.T) { } func TestSetHead(t *testing.T) { - require.Nil(t, SetHead(context.Background(), newTestClient(t).L2RawRPC, common.Big0)) + require.Nil(t, SetHead(context.Background(), newTestClient(t).L2, common.Big0)) } func TestStringToBytes32(t *testing.T) { @@ -63,7 +63,7 @@ func TestL1ContentFrom(t *testing.T) { require.Nil(t, err) require.Nil(t, client.L2.SendTransaction(context.Background(), signedTx)) - content, err := ContentFrom(context.Background(), client.L2RawRPC, testAddr) + content, err := ContentFrom(context.Background(), client.L2, testAddr) require.Nil(t, err) require.NotZero(t, len(content["pending"])) diff --git a/prover/proof_submitter/proof_contester.go b/prover/proof_submitter/proof_contester.go index a581125b8..c9a2c1ef1 100644 --- a/prover/proof_submitter/proof_contester.go +++ b/prover/proof_submitter/proof_contester.go @@ -114,7 +114,7 @@ func (c *ProofContester) SubmitContest( return err } - signalRoot, err := c.rpc.GetStorageRoot(ctx, c.rpc.L2GethClient, c.l2SignalService, blockID) + signalRoot, err := c.rpc.GetStorageRoot(ctx, c.rpc.L2, c.l2SignalService, blockID) if err != nil { return fmt.Errorf("failed to get L2 signal service storage root: %w", err) } diff --git a/prover/proof_submitter/proof_submitter.go b/prover/proof_submitter/proof_submitter.go index 0cc3e13cb..6e333e4d4 100644 --- a/prover/proof_submitter/proof_submitter.go +++ b/prover/proof_submitter/proof_submitter.go @@ -133,7 +133,7 @@ func (s *ProofSubmitter) RequestProof(ctx context.Context, event *bindings.Taiko return err } - signalRoot, err := s.rpc.GetStorageRoot(ctx, s.rpc.L2GethClient, s.l2SignalService, block.Number()) + signalRoot, err := s.rpc.GetStorageRoot(ctx, s.rpc.L2, s.l2SignalService, block.Number()) if err != nil { return fmt.Errorf("failed to get L2 signal service storage root: %w", err) } diff --git a/prover/prover.go b/prover/prover.go index 3d692c64c..65157574e 100644 --- a/prover/prover.go +++ b/prover/prover.go @@ -1099,7 +1099,7 @@ func (p *Prover) isValidProof( } root, err := p.rpc.GetStorageRoot( ctx, - p.rpc.L2GethClient, + p.rpc.L2, l2SignalService, blockID, ) diff --git a/prover/prover_test.go b/prover/prover_test.go index 909744017..d9e2f5031 100644 --- a/prover/prover_test.go +++ b/prover/prover_test.go @@ -53,7 +53,7 @@ func (s *ProverTestSuite) SetupTest() { ctx, cancel := context.WithCancel(context.Background()) p := new(Prover) - s.Nil(InitFromConfig(ctx, p, (&Config{ + s.Nil(InitFromConfig(ctx, p, &Config{ L1WsEndpoint: os.Getenv("L1_NODE_WS_ENDPOINT"), L1HttpEndpoint: os.Getenv("L1_NODE_HTTP_ENDPOINT"), L2WsEndpoint: os.Getenv("L2_EXECUTION_ENGINE_WS_ENDPOINT"), @@ -75,7 +75,9 @@ func (s *ProverTestSuite) SetupTest() { WaitReceiptTimeout: 12 * time.Second, DatabasePath: "", Allowance: allowance, - }))) + RPCTimeout: 3 * time.Second, + BackOffMaxRetrys: 3, + })) p.srv = testutils.NewTestProverServer( &s.ClientTestSuite, l1ProverPrivKey, @@ -168,6 +170,8 @@ func (s *ProverTestSuite) TestInitError() { Dummy: true, ProveUnassignedBlocks: true, ProveBlockTxReplacementMultiplier: 2, + RPCTimeout: 10 * time.Minute, + BackOffMaxRetrys: 3, }), "dial tcp:") }