From 95ee9058614bf147ea04ec979bafe373d266120d Mon Sep 17 00:00:00 2001
From: Pavel Karpy
Date: Tue, 7 Feb 2023 19:35:15 +0300
Subject: [PATCH] [#2244] node: Fix subscriptions lock
Subscribing without async listening could lead to a dead-lock in the
`neo-go` client.
Signed-off-by: Pavel Karpy
---
CHANGELOG.md | 1 +
pkg/morph/client/notifications.go | 23 +++++++++++++++++++++++
2 files changed, 24 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index bb8ad51d8d..289725febf 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -36,6 +36,7 @@ Changelog for FrostFS Node
- Possible deadlock in write-cache (#2239)
- Fix `*_req_count` and `*_req_count_success` metric values (#2241)
- Storage ID update by write-cache (#2244)
+- `neo-go` client deadlock on subscription restoration (#2244)
### Removed
### Updated
diff --git a/pkg/morph/client/notifications.go b/pkg/morph/client/notifications.go
index 63e5a5c8aa..2afeebb832 100644
--- a/pkg/morph/client/notifications.go
+++ b/pkg/morph/client/notifications.go
@@ -211,6 +211,29 @@ func (c *Client) restoreSubscriptions(cli *rpcclient.WSClient, endpoint string)
id string
)
+ stopCh := make(chan struct{})
+ defer close(stopCh)
+
+ // neo-go WS client says to _always_ read notifications
+ // from its channel. Subscribing to any notification
+ // while not reading them in another goroutine may
+ // lead to a dead-lock, thus that async side notification
+ // listening while restoring subscriptions
+ go func() {
+ for {
+ select {
+ case <-stopCh:
+ return
+ case n, ok := <-cli.Notifications:
+ if !ok {
+ return
+ }
+
+ c.notifications <- n
+ }
+ }
+ }()
+
// new block events restoration
if c.subscribedToNewBlocks {
_, err = cli.SubscribeForNewBlocks(nil)