Use the same endpoint for notifications and RPC requests #394

Closed
opened 2025-12-28 17:19:19 +00:00 by sami · 1 comment
Owner

Originally created by @alexvanin on GitHub (Dec 24, 2021).

Originally assigned to: @carpawell on GitHub.

NeoFS nodes have two separate pools of endpoint addresses:

  • to listen side chain events,
  • to send side chain RPC requests.
    Node might listen events from one endpoint but send RPC request to another. There is an issue with that approach.

Sidechain blocks are not distributed uniformly among RPC nodes. There is a case when NeoFS node receives notification from block which is not processed by other RPC node, where NeoFS sends requests.

Example: nspcc-dev/neofs-node@96efe0f294/cmd/neofs-node/netmap.go (L144-L157)

In this example NeoFS node tries to fetch new network map on NewEpoch event. If RPC node did not process block with new epoch yet, then fetch invocation will fail and new network map will not be processed by the node.

error   neofs-node/netmap.go:156        could not update node state on new epoch        {"epoch": 2529, "error": "could not perform test invocation (snapshotByEpoch): chain/client: contract execution finished with state FAULT; exception: at instruction 3593 (THROW): unhandled exception: \"incorrect diff\""}

To avoid such cases I propose to use single endpoint for listening and sending events. In case of errors, switch to another endpoint both in listener and in the client.

  1. Merge endpoint pools into single pool
morph:
  endpoint:
    - wss://rpc1.morph.fs.neo.org:40341/ws
    - wss://rpc2.morph.fs.neo.org:40341/ws
  1. Use web socket neo-go client to send requests

WSClient encapsulates ordinary client that we use in morph package.

  1. Drop multiclient component from RPC

  2. Provide seamless switch from one endpoint to another in runtime

In case of network errors during RPC requests or closed channel in subscriber, switch to another endpoint.

Originally created by @alexvanin on GitHub (Dec 24, 2021). Originally assigned to: @carpawell on GitHub. NeoFS nodes have two separate pools of endpoint addresses: - to listen side chain events, - to send side chain RPC requests. Node might listen events from one endpoint but send RPC request to another. There is an issue with that approach. Sidechain blocks are not distributed uniformly among RPC nodes. There is a case when NeoFS node receives notification from block which is not processed by other RPC node, where NeoFS sends requests. Example: https://github.com/nspcc-dev/neofs-node/blob/96efe0f2941244c298f43053c52adf040cce1f54/cmd/neofs-node/netmap.go#L144-L157 In this example NeoFS node tries to fetch new network map on `NewEpoch` event. If RPC node did not process block with new epoch yet, then fetch invocation will fail and new network map will not be processed by the node. ``` error neofs-node/netmap.go:156 could not update node state on new epoch {"epoch": 2529, "error": "could not perform test invocation (snapshotByEpoch): chain/client: contract execution finished with state FAULT; exception: at instruction 3593 (THROW): unhandled exception: \"incorrect diff\""} ``` --- To avoid such cases I propose to use single endpoint for listening and sending events. In case of errors, switch to another endpoint both in listener and in the client. 1. Merge endpoint pools into single pool ```yaml morph: endpoint: - wss://rpc1.morph.fs.neo.org:40341/ws - wss://rpc2.morph.fs.neo.org:40341/ws ``` 2. Use web socket neo-go client to send requests [WSClient](https://github.com/nspcc-dev/neo-go/blob/501ca0dedba41bb23de24987e16f1890b47fc914/pkg/rpc/client/wsclient.go#L23) encapsulates ordinary client that we use in morph package. 3. Drop multiclient component from RPC 4. Provide seamless switch from one endpoint to another in runtime In case of network errors during RPC requests or closed channel in subscriber, switch to another endpoint.
sami 2025-12-28 17:19:19 +00:00
  • closed this issue
  • added the
    bug
    label
Author
Owner

@alexvanin commented on GitHub (Jan 18, 2022):

I propose to do it in two steps.

  1. Use single pool of endpoints in config to fetch one web socket address for one client and one listener. In case of failures, do not anything. This kinda reverts https://github.com/nspcc-dev/neofs-node/issues/746

  2. Define components that will implement both Listener interface and necessary neo-go client functions. This component will use monitor routine to check health of nodes and switch between endpoints in case of failures like https://github.com/nspcc-dev/neofs-node/issues/746.

@alexvanin commented on GitHub (Jan 18, 2022): I propose to do it in two steps. 1. Use single pool of endpoints in config to fetch one web socket address for _one_ client and _one_ listener. In case of failures, do not anything. This kinda reverts https://github.com/nspcc-dev/neofs-node/issues/746 2. Define components that will implement both `Listener` interface and necessary neo-go client functions. This component will use monitor routine to check health of nodes and switch between endpoints in case of failures like https://github.com/nspcc-dev/neofs-node/issues/746.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
nspcc-dev/neofs-node#394
No description provided.