rpc, ethclient, gethclient: make ethclient.Client take an RPCClient interface

This commit is contained in:
Dario Gabriel Lipicar 2026-01-08 19:16:46 -03:00
parent f51870e40e
commit 816cf344d3
No known key found for this signature in database
GPG key ID: 9625E9494309D203
4 changed files with 23 additions and 9 deletions

View file

@ -32,9 +32,16 @@ import (
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
) )
type RPCClient interface {
CallContext(ctx context.Context, result interface{}, method string, args ...interface{}) error
BatchCallContext(ctx context.Context, b []rpc.BatchElem) error
EthSubscribe(ctx context.Context, channel interface{}, args ...interface{}) (ethereum.Subscription, error)
Close()
}
// Client defines typed wrappers for the Ethereum RPC API. // Client defines typed wrappers for the Ethereum RPC API.
type Client struct { type Client struct {
c *rpc.Client c RPCClient
} }
// Dial connects a client to the given URL. // Dial connects a client to the given URL.
@ -52,7 +59,7 @@ func DialContext(ctx context.Context, rawurl string) (*Client, error) {
} }
// NewClient creates a client that uses the given RPC client. // NewClient creates a client that uses the given RPC client.
func NewClient(c *rpc.Client) *Client { func NewClient(c RPCClient) *Client {
return &Client{c} return &Client{c}
} }
@ -62,7 +69,7 @@ func (ec *Client) Close() {
} }
// Client gets the underlying RPC client. // Client gets the underlying RPC client.
func (ec *Client) Client() *rpc.Client { func (ec *Client) Client() RPCClient {
return ec.c return ec.c
} }

View file

@ -198,12 +198,12 @@ func (ec *Client) GetNodeInfo(ctx context.Context) (*p2p.NodeInfo, error) {
} }
// SubscribeFullPendingTransactions subscribes to new pending transactions. // SubscribeFullPendingTransactions subscribes to new pending transactions.
func (ec *Client) SubscribeFullPendingTransactions(ctx context.Context, ch chan<- *types.Transaction) (*rpc.ClientSubscription, error) { func (ec *Client) SubscribeFullPendingTransactions(ctx context.Context, ch chan<- *types.Transaction) (ethereum.Subscription, error) {
return ec.c.EthSubscribe(ctx, ch, "newPendingTransactions", true) return ec.c.EthSubscribe(ctx, ch, "newPendingTransactions", true)
} }
// SubscribePendingTransactions subscribes to new pending transaction hashes. // SubscribePendingTransactions subscribes to new pending transaction hashes.
func (ec *Client) SubscribePendingTransactions(ctx context.Context, ch chan<- common.Hash) (*rpc.ClientSubscription, error) { func (ec *Client) SubscribePendingTransactions(ctx context.Context, ch chan<- common.Hash) (ethereum.Subscription, error) {
return ec.c.EthSubscribe(ctx, ch, "newPendingTransactions") return ec.c.EthSubscribe(ctx, ch, "newPendingTransactions")
} }

View file

@ -28,6 +28,7 @@ import (
"sync/atomic" "sync/atomic"
"time" "time"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
) )
@ -482,7 +483,7 @@ func (c *Client) Notify(ctx context.Context, method string, args ...interface{})
} }
// EthSubscribe registers a subscription under the "eth" namespace. // EthSubscribe registers a subscription under the "eth" namespace.
func (c *Client) EthSubscribe(ctx context.Context, channel interface{}, args ...interface{}) (*ClientSubscription, error) { func (c *Client) EthSubscribe(ctx context.Context, channel interface{}, args ...interface{}) (ethereum.Subscription, error) {
return c.Subscribe(ctx, "eth", channel, args...) return c.Subscribe(ctx, "eth", channel, args...)
} }
@ -498,7 +499,7 @@ func (c *Client) EthSubscribe(ctx context.Context, channel interface{}, args ...
// before considering the subscriber dead. The subscription Err channel will receive // before considering the subscriber dead. The subscription Err channel will receive
// ErrSubscriptionQueueOverflow. Use a sufficiently large buffer on the channel or ensure // ErrSubscriptionQueueOverflow. Use a sufficiently large buffer on the channel or ensure
// that the channel usually has at least one reader to prevent this issue. // that the channel usually has at least one reader to prevent this issue.
func (c *Client) Subscribe(ctx context.Context, namespace string, channel interface{}, args ...interface{}) (*ClientSubscription, error) { func (c *Client) Subscribe(ctx context.Context, namespace string, channel interface{}, args ...interface{}) (ethereum.Subscription, error) {
// Check type of channel first. // Check type of channel first.
chanVal := reflect.ValueOf(channel) chanVal := reflect.ValueOf(channel)
if chanVal.Kind() != reflect.Chan || chanVal.Type().ChanDir()&reflect.SendDir == 0 { if chanVal.Kind() != reflect.Chan || chanVal.Type().ChanDir()&reflect.SendDir == 0 {

View file

@ -34,6 +34,7 @@ import (
"time" "time"
"github.com/davecgh/go-spew/spew" "github.com/davecgh/go-spew/spew"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
) )
@ -496,7 +497,7 @@ func TestClientSubscribeClose(t *testing.T) {
var ( var (
nc = make(chan int) nc = make(chan int)
errc = make(chan error, 1) errc = make(chan error, 1)
sub *ClientSubscription sub ethereum.Subscription
err error err error
) )
go func() { go func() {
@ -665,7 +666,12 @@ func TestClientSubscriptionUnsubscribeServer(t *testing.T) {
// Unsubscribe and check that unsubscribe was called. // Unsubscribe and check that unsubscribe was called.
sub.Unsubscribe() sub.Unsubscribe()
if !recorder.unsubscribes[sub.subid] {
clientSub, ok := sub.(*ClientSubscription)
if !ok {
t.Fatal("subscription is not a ClientSubscription")
}
if !recorder.unsubscribes[clientSub.subid] {
t.Fatal("client did not call unsubscribe method") t.Fatal("client did not call unsubscribe method")
} }
if _, open := <-sub.Err(); open { if _, open := <-sub.Err(); open {