From 808c931feda6d6ad7948f617987b4b1440892059 Mon Sep 17 00:00:00 2001 From: zhiqiangxu <652732310@qq.com> Date: Thu, 6 Oct 2022 21:47:30 +0800 Subject: [PATCH 1/9] add IsHTTP method to ethclient.Client and rpc.Client --- ethclient/ethclient.go | 4 ++++ rpc/client.go | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index 4508027fa47b0..26ad9a817e70b 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -588,6 +588,10 @@ func (ec *Client) SendTransaction(ctx context.Context, tx *types.Transaction) er return ec.c.CallContext(ctx, nil, "eth_sendRawTransaction", hexutil.Encode(data)) } +func (ec *Client) IsHTTP() bool { + return ec.c.IsHTTP() +} + func toBlockNumArg(number *big.Int) string { if number == nil { return "latest" diff --git a/rpc/client.go b/rpc/client.go index c3114ef1d20f6..c0b0443e3129e 100644 --- a/rpc/client.go +++ b/rpc/client.go @@ -716,3 +716,7 @@ func (c *Client) read(codec ServerCodec) { c.readOp <- readOp{msgs, batch} } } + +func (c *Client) IsHTTP() bool { + return c.isHTTP +} From 0b856fbe5d8584691bd03306647bb7dbba493eae Mon Sep 17 00:00:00 2001 From: zhiqiangxu <652732310@qq.com> Date: Fri, 7 Oct 2022 14:34:59 +0800 Subject: [PATCH 2/9] expose SupportsSubscription instead --- ethclient/ethclient.go | 4 ++-- rpc/client.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index 26ad9a817e70b..3d151a7dae7c7 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -588,8 +588,8 @@ func (ec *Client) SendTransaction(ctx context.Context, tx *types.Transaction) er return ec.c.CallContext(ctx, nil, "eth_sendRawTransaction", hexutil.Encode(data)) } -func (ec *Client) IsHTTP() bool { - return ec.c.IsHTTP() +func (ec *Client) SupportsSubscription() bool { + return ec.c.SupportsSubscription() } func toBlockNumArg(number *big.Int) string { diff --git a/rpc/client.go b/rpc/client.go index c0b0443e3129e..a225efbeeac80 100644 --- a/rpc/client.go +++ b/rpc/client.go @@ -717,6 +717,6 @@ func (c *Client) read(codec ServerCodec) { } } -func (c *Client) IsHTTP() bool { - return c.isHTTP +func (c *Client) SupportsSubscription() bool { + return !c.isHTTP } From 82f4dc41569e3f9d8ba7be107f37b59077ea0d75 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 30 Nov 2022 15:00:58 +0100 Subject: [PATCH 3/9] rpc: add comment on SupportsSubscriptions --- rpc/client.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/rpc/client.go b/rpc/client.go index a225efbeeac80..5e5067bd5de48 100644 --- a/rpc/client.go +++ b/rpc/client.go @@ -538,6 +538,13 @@ func (c *Client) Subscribe(ctx context.Context, namespace string, channel interf return op.sub, nil } +// SupportsSubscriptions reports whether subscriptions are supported by the client +// transport. When this returns false, Subscribe and related methods will return +// ErrNotificationsUnsupported. +func (c *Client) SupportsSubscription() bool { + return !c.isHTTP +} + func (c *Client) newMessage(method string, paramsIn ...interface{}) (*jsonrpcMessage, error) { msg := &jsonrpcMessage{Version: vsn, ID: c.nextID(), Method: method} if paramsIn != nil { // prevent sending "params":null @@ -716,7 +723,3 @@ func (c *Client) read(codec ServerCodec) { c.readOp <- readOp{msgs, batch} } } - -func (c *Client) SupportsSubscription() bool { - return !c.isHTTP -} From f1390ad1a9ce7e8fda848017c1c23c453d94de4e Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 30 Nov 2022 15:01:28 +0100 Subject: [PATCH 4/9] ethclient: remove SupportsSubscriptions --- ethclient/ethclient.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index 3d151a7dae7c7..509e8ab6f7739 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -588,8 +588,13 @@ func (ec *Client) SendTransaction(ctx context.Context, tx *types.Transaction) er return ec.c.CallContext(ctx, nil, "eth_sendRawTransaction", hexutil.Encode(data)) } -func (ec *Client) SupportsSubscription() bool { - return ec.c.SupportsSubscription() +// SupportSubscriptions reports whether the client transport supports publish/subscribe +// APIs. +// +// Note that calls to SubscribeNewHeads and other subscription-based methods can still +// fail even when this returns true, because the server might not support the mechanism. +func (ec *Client) SupportsSubscriptions() bool { + return ec.c.SupportsSubscriptions() } func toBlockNumArg(number *big.Int) string { From 3872a75bede71a947c8b6e539398556f9d1f4f55 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 30 Nov 2022 15:06:04 +0100 Subject: [PATCH 5/9] rpc: rename to SupportsSubscriptions --- rpc/client.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rpc/client.go b/rpc/client.go index 5e5067bd5de48..2b0016db8f4ec 100644 --- a/rpc/client.go +++ b/rpc/client.go @@ -541,7 +541,7 @@ func (c *Client) Subscribe(ctx context.Context, namespace string, channel interf // SupportsSubscriptions reports whether subscriptions are supported by the client // transport. When this returns false, Subscribe and related methods will return // ErrNotificationsUnsupported. -func (c *Client) SupportsSubscription() bool { +func (c *Client) SupportsSubscriptions() bool { return !c.isHTTP } From e76a477abaae3a57c3e02b560c07005afa16c3cb Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 8 Dec 2022 15:50:14 +0100 Subject: [PATCH 6/9] rpc: redefine ErrNotificationsUnsupported with error code -32601 --- rpc/errors.go | 25 ++++++++++++++++++++++++- rpc/handler.go | 5 +---- rpc/subscription.go | 3 ++- 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/rpc/errors.go b/rpc/errors.go index abb698af75c13..84b30aab971b5 100644 --- a/rpc/errors.go +++ b/rpc/errors.go @@ -59,7 +59,6 @@ var ( const ( errcodeDefault = -32000 - errcodeNotificationsUnsupported = -32001 errcodeTimeout = -32002 errcodeResponseTooLarge = -32003 errcodePanic = -32603 @@ -80,6 +79,30 @@ func (e *methodNotFoundError) Error() string { return fmt.Sprintf("the method %s does not exist/is not available", e.method) } +type notificationsUnsupportedError struct{} + +func (e notificationsUnsupportedError) Error() string { + return "notifications not supported" +} + +func (e notificationsUnsupportedError) ErrorCode() int { return -32601 } + +// Is checks for equivalence to another error. Here we define that all errors with code +// -32601 (method not found) are equivalent to notificationsUnsupportedError. This is +// done to enable the following pattern: +// +// sub, err := client.Subscribe(...) +// if errors.Is(err, rpc.ErrNotificationsUnsupported) { +// // server doesn't support subscriptions +// } +func (e notificationsUnsupportedError) Is(other error) bool { + if other == (notificationsUnsupportedError{}) { + return true + } + rpcErr, ok := other.(Error) + return ok && rpcErr.ErrorCode() == -32601 +} + type subscriptionNotFoundError struct{ namespace, subscription string } func (e *subscriptionNotFoundError) ErrorCode() int { return -32601 } diff --git a/rpc/handler.go b/rpc/handler.go index 4f48c7931c651..f44e4d7b01d89 100644 --- a/rpc/handler.go +++ b/rpc/handler.go @@ -530,10 +530,7 @@ func (h *handler) handleCall(cp *callProc, msg *jsonrpcMessage) *jsonrpcMessage // handleSubscribe processes *_subscribe method calls. func (h *handler) handleSubscribe(cp *callProc, msg *jsonrpcMessage) *jsonrpcMessage { if !h.allowSubscribe { - return msg.errorResponse(&internalServerError{ - code: errcodeNotificationsUnsupported, - message: ErrNotificationsUnsupported.Error(), - }) + return msg.errorResponse(ErrNotificationsUnsupported) } // Subscription method name is first argument. diff --git a/rpc/subscription.go b/rpc/subscription.go index 334ead3ace4d4..e10dfe8169ccc 100644 --- a/rpc/subscription.go +++ b/rpc/subscription.go @@ -33,7 +33,8 @@ import ( var ( // ErrNotificationsUnsupported is returned when the connection doesn't support notifications - ErrNotificationsUnsupported = errors.New("notifications not supported") + ErrNotificationsUnsupported = notificationsUnsupportedError{} + // ErrSubscriptionNotFound is returned when the notification for the given id is not found ErrSubscriptionNotFound = errors.New("subscription not found") ) From 91787db50f827b848059b0c8b55bb0f5004c35fa Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 8 Dec 2022 15:56:56 +0100 Subject: [PATCH 7/9] rpc: recognize previous error code for ErrNotificationsUnsupported --- rpc/errors.go | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/rpc/errors.go b/rpc/errors.go index 84b30aab971b5..438aff218c2e3 100644 --- a/rpc/errors.go +++ b/rpc/errors.go @@ -58,11 +58,13 @@ var ( ) const ( - errcodeDefault = -32000 - errcodeTimeout = -32002 - errcodeResponseTooLarge = -32003 - errcodePanic = -32603 - errcodeMarshalError = -32603 + errcodeDefault = -32000 + errcodeTimeout = -32002 + errcodeResponseTooLarge = -32003 + errcodePanic = -32603 + errcodeMarshalError = -32603 + + legacyErrcodeNotificationsUnsupported = -32001 ) const ( @@ -100,7 +102,11 @@ func (e notificationsUnsupportedError) Is(other error) bool { return true } rpcErr, ok := other.(Error) - return ok && rpcErr.ErrorCode() == -32601 + if ok { + code := rpcErr.ErrorCode() + return code == -32601 || code == legacyErrcodeNotificationsUnsupported + } + return false } type subscriptionNotFoundError struct{ namespace, subscription string } From 7146379b349cea51e2f4f49204b1cae8ab9fb3a1 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Tue, 13 Jun 2023 14:03:33 +0200 Subject: [PATCH 8/9] Update ethclient.go --- ethclient/ethclient.go | 9 --------- 1 file changed, 9 deletions(-) diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index 509e8ab6f7739..4508027fa47b0 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -588,15 +588,6 @@ func (ec *Client) SendTransaction(ctx context.Context, tx *types.Transaction) er return ec.c.CallContext(ctx, nil, "eth_sendRawTransaction", hexutil.Encode(data)) } -// SupportSubscriptions reports whether the client transport supports publish/subscribe -// APIs. -// -// Note that calls to SubscribeNewHeads and other subscription-based methods can still -// fail even when this returns true, because the server might not support the mechanism. -func (ec *Client) SupportsSubscriptions() bool { - return ec.c.SupportsSubscriptions() -} - func toBlockNumArg(number *big.Int) string { if number == nil { return "latest" From 406506c63ee1b0932939aadf4481ebab58fb8bb4 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 14 Jun 2023 12:29:15 +0200 Subject: [PATCH 9/9] rpc: document errors.Is(..., ErrNotificationsUnsupported) better --- rpc/subscription.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/rpc/subscription.go b/rpc/subscription.go index e10dfe8169ccc..3231c2ceec9b5 100644 --- a/rpc/subscription.go +++ b/rpc/subscription.go @@ -32,7 +32,15 @@ import ( ) var ( - // ErrNotificationsUnsupported is returned when the connection doesn't support notifications + // ErrNotificationsUnsupported is returned by the client when the connection doesn't + // support notifications. You can use this error value to check for subscription + // support like this: + // + // sub, err := client.EthSubscribe(ctx, channel, "newHeads", true) + // if errors.Is(err, rpc.ErrNotificationsUnsupported) { + // // Server does not support subscriptions, fall back to polling. + // } + // ErrNotificationsUnsupported = notificationsUnsupportedError{} // ErrSubscriptionNotFound is returned when the notification for the given id is not found