From 2092132dd62be0fb63d001b926692e0a689c55da Mon Sep 17 00:00:00 2001 From: Lucas ALLOIN Date: Sat, 19 Oct 2024 01:30:24 +0200 Subject: [PATCH] rpc, ethclient: Add rpc.ClientInterface and use it in ethclient to allow custom rpc client implementation --- ethclient/ethclient.go | 6 +++--- ethclient/ethclient_test.go | 20 ++++++++++---------- ethclient/gethclient/gethclient.go | 4 ++-- ethclient/gethclient/gethclient_test.go | 24 ++++++++++++------------ rpc/client.go | 14 ++++++++++++++ 5 files changed, 41 insertions(+), 27 deletions(-) diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index 0972644d80..b895528d7b 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -33,7 +33,7 @@ import ( // Client defines typed wrappers for the Ethereum RPC API. type Client struct { - c *rpc.Client + c rpc.ClientInterface } // Dial connects a client to the given URL. @@ -51,7 +51,7 @@ func DialContext(ctx context.Context, rawurl string) (*Client, error) { } // NewClient creates a client that uses the given RPC client. -func NewClient(c *rpc.Client) *Client { +func NewClient(c rpc.ClientInterface) *Client { return &Client{c} } @@ -61,7 +61,7 @@ func (ec *Client) Close() { } // Client gets the underlying RPC client. -func (ec *Client) Client() *rpc.Client { +func (ec *Client) Client() rpc.ClientInterface { return ec.c } diff --git a/ethclient/ethclient_test.go b/ethclient/ethclient_test.go index 1b7e26fb74..99617eb976 100644 --- a/ethclient/ethclient_test.go +++ b/ethclient/ethclient_test.go @@ -302,7 +302,7 @@ func TestEthClient(t *testing.T) { } } -func testHeader(t *testing.T, chain []*types.Block, client *rpc.Client) { +func testHeader(t *testing.T, chain []*types.Block, client rpc.ClientInterface) { tests := map[string]struct { block *big.Int want *types.Header @@ -342,7 +342,7 @@ func testHeader(t *testing.T, chain []*types.Block, client *rpc.Client) { } } -func testBalanceAt(t *testing.T, client *rpc.Client) { +func testBalanceAt(t *testing.T, client rpc.ClientInterface) { tests := map[string]struct { account common.Address block *big.Int @@ -388,7 +388,7 @@ func testBalanceAt(t *testing.T, client *rpc.Client) { } } -func testTransactionInBlock(t *testing.T, client *rpc.Client) { +func testTransactionInBlock(t *testing.T, client rpc.ClientInterface) { ec := NewClient(client) // Get current block by number. @@ -420,7 +420,7 @@ func testTransactionInBlock(t *testing.T, client *rpc.Client) { } } -func testChainID(t *testing.T, client *rpc.Client) { +func testChainID(t *testing.T, client rpc.ClientInterface) { ec := NewClient(client) id, err := ec.ChainID(context.Background()) if err != nil { @@ -431,7 +431,7 @@ func testChainID(t *testing.T, client *rpc.Client) { } } -func testGetBlock(t *testing.T, client *rpc.Client) { +func testGetBlock(t *testing.T, client rpc.ClientInterface) { ec := NewClient(client) // Get current block number @@ -476,7 +476,7 @@ func testGetBlock(t *testing.T, client *rpc.Client) { } } -func testStatusFunctions(t *testing.T, client *rpc.Client) { +func testStatusFunctions(t *testing.T, client rpc.ClientInterface) { ec := NewClient(client) // Sync progress @@ -539,7 +539,7 @@ func testStatusFunctions(t *testing.T, client *rpc.Client) { } } -func testCallContractAtHash(t *testing.T, client *rpc.Client) { +func testCallContractAtHash(t *testing.T, client rpc.ClientInterface) { ec := NewClient(client) // EstimateGas @@ -566,7 +566,7 @@ func testCallContractAtHash(t *testing.T, client *rpc.Client) { } } -func testCallContract(t *testing.T, client *rpc.Client) { +func testCallContract(t *testing.T, client rpc.ClientInterface) { ec := NewClient(client) // EstimateGas @@ -593,7 +593,7 @@ func testCallContract(t *testing.T, client *rpc.Client) { } } -func testAtFunctions(t *testing.T, client *rpc.Client) { +func testAtFunctions(t *testing.T, client rpc.ClientInterface) { ec := NewClient(client) block, err := ec.HeaderByNumber(context.Background(), big.NewInt(1)) @@ -696,7 +696,7 @@ func testAtFunctions(t *testing.T, client *rpc.Client) { } } -func testTransactionSender(t *testing.T, client *rpc.Client) { +func testTransactionSender(t *testing.T, client rpc.ClientInterface) { ec := NewClient(client) ctx := context.Background() diff --git a/ethclient/gethclient/gethclient.go b/ethclient/gethclient/gethclient.go index 02b2598b37..8e04bac5ec 100644 --- a/ethclient/gethclient/gethclient.go +++ b/ethclient/gethclient/gethclient.go @@ -37,11 +37,11 @@ import ( // // If you want to use the standardized Ethereum RPC functionality, use ethclient.Client instead. type Client struct { - c *rpc.Client + c rpc.ClientInterface } // New creates a client that uses the given RPC client. -func New(c *rpc.Client) *Client { +func New(c rpc.ClientInterface) *Client { return &Client{c} } diff --git a/ethclient/gethclient/gethclient_test.go b/ethclient/gethclient/gethclient_test.go index 36ea290a85..4311ea1394 100644 --- a/ethclient/gethclient/gethclient_test.go +++ b/ethclient/gethclient/gethclient_test.go @@ -162,7 +162,7 @@ func TestGethClient(t *testing.T) { } } -func testAccessList(t *testing.T, client *rpc.Client) { +func testAccessList(t *testing.T, client rpc.ClientInterface) { ec := New(client) // Test transfer msg := ethereum.CallMsg{ @@ -216,7 +216,7 @@ func testAccessList(t *testing.T, client *rpc.Client) { } } -func testGetProof(t *testing.T, client *rpc.Client, addr common.Address) { +func testGetProof(t *testing.T, client rpc.ClientInterface, addr common.Address) { ec := New(client) ethcl := ethclient.NewClient(client) result, err := ec.GetProof(context.Background(), addr, []string{testSlot.String()}, nil) @@ -254,7 +254,7 @@ func testGetProof(t *testing.T, client *rpc.Client, addr common.Address) { } } -func testGetProofCanonicalizeKeys(t *testing.T, client *rpc.Client) { +func testGetProofCanonicalizeKeys(t *testing.T, client rpc.ClientInterface) { ec := New(client) // Tests with non-canon input for storage keys. @@ -284,7 +284,7 @@ func testGetProofCanonicalizeKeys(t *testing.T, client *rpc.Client) { } } -func testGetProofNonExistent(t *testing.T, client *rpc.Client) { +func testGetProofNonExistent(t *testing.T, client rpc.ClientInterface) { addr := common.HexToAddress("0x0001") ec := New(client) result, err := ec.GetProof(context.Background(), addr, nil, nil) @@ -316,7 +316,7 @@ func testGetProofNonExistent(t *testing.T, client *rpc.Client) { } } -func testGCStats(t *testing.T, client *rpc.Client) { +func testGCStats(t *testing.T, client rpc.ClientInterface) { ec := New(client) _, err := ec.GCStats(context.Background()) if err != nil { @@ -324,7 +324,7 @@ func testGCStats(t *testing.T, client *rpc.Client) { } } -func testMemStats(t *testing.T, client *rpc.Client) { +func testMemStats(t *testing.T, client rpc.ClientInterface) { ec := New(client) stats, err := ec.MemStats(context.Background()) if err != nil { @@ -335,7 +335,7 @@ func testMemStats(t *testing.T, client *rpc.Client) { } } -func testGetNodeInfo(t *testing.T, client *rpc.Client) { +func testGetNodeInfo(t *testing.T, client rpc.ClientInterface) { ec := New(client) info, err := ec.GetNodeInfo(context.Background()) if err != nil { @@ -347,7 +347,7 @@ func testGetNodeInfo(t *testing.T, client *rpc.Client) { } } -func testSetHead(t *testing.T, client *rpc.Client) { +func testSetHead(t *testing.T, client rpc.ClientInterface) { ec := New(client) err := ec.SetHead(context.Background(), big.NewInt(0)) if err != nil { @@ -355,7 +355,7 @@ func testSetHead(t *testing.T, client *rpc.Client) { } } -func testSubscribePendingTransactions(t *testing.T, client *rpc.Client) { +func testSubscribePendingTransactions(t *testing.T, client rpc.ClientInterface) { ec := New(client) ethcl := ethclient.NewClient(client) // Subscribe to Transactions @@ -389,7 +389,7 @@ func testSubscribePendingTransactions(t *testing.T, client *rpc.Client) { } } -func testSubscribeFullPendingTransactions(t *testing.T, client *rpc.Client) { +func testSubscribeFullPendingTransactions(t *testing.T, client rpc.ClientInterface) { ec := New(client) ethcl := ethclient.NewClient(client) // Subscribe to Transactions @@ -423,7 +423,7 @@ func testSubscribeFullPendingTransactions(t *testing.T, client *rpc.Client) { } } -func testCallContract(t *testing.T, client *rpc.Client) { +func testCallContract(t *testing.T, client rpc.ClientInterface) { ec := New(client) msg := ethereum.CallMsg{ From: testAddr, @@ -533,7 +533,7 @@ func TestBlockOverridesMarshal(t *testing.T) { } } -func testCallContractWithBlockOverrides(t *testing.T, client *rpc.Client) { +func testCallContractWithBlockOverrides(t *testing.T, client rpc.ClientInterface) { ec := New(client) msg := ethereum.CallMsg{ From: testAddr, diff --git a/rpc/client.go b/rpc/client.go index f9a8f1116b..75e79d0954 100644 --- a/rpc/client.go +++ b/rpc/client.go @@ -75,6 +75,20 @@ type BatchElem struct { Error error } +// ClientInterface is the interface that an EVM rpc client must implement. +type ClientInterface interface { + Call(result interface{}, method string, args ...interface{}) error + CallContext(ctx context.Context, result interface{}, method string, args ...interface{}) error + BatchCall(b []BatchElem) error + BatchCallContext(ctx context.Context, b []BatchElem) error + Notify(ctx context.Context, method string, args ...interface{}) error + EthSubscribe(ctx context.Context, channel interface{}, args ...interface{}) (*ClientSubscription, error) + ShhSubscribe(ctx context.Context, channel interface{}, args ...interface{}) (*ClientSubscription, error) + Subscribe(ctx context.Context, namespace string, channel interface{}, args ...interface{}) (*ClientSubscription, error) + SupportsSubscriptions() bool + Close() +} + // Client represents a connection to an RPC server. type Client struct { idgen func() ID // for subscriptions