Every client's (Un)Subscription call does two things: an RPC call and a
subscription map lock (two of maps currently). If we imagine that there is
one routine that tries to subscribe (A) and one routine that tries to
unsubscribe (B), the following sequence can happen:
0. Current number of subscriptions is X
1. B does an RPC and makes number of subscriptions X-1
2. A does an RPC and makes number of subscriptions X again
3. A holds subscription locks and rewrites client's subscription state
(subscription with ID X now points to a different channel; channel that
was registered by B is lost and is not related to any real subscription
but is still included in the `receivers` map)
4. B holds subscription locks and drops subscription X (first, it is an
error and we have just lost a subscription that we think was made
successfully second, we have lost a channel in the `receivers` map, and
no corresponding subscription points to it)
5. X subscription is received by the WS client (in practice it is a new
block, 100ms, quite often to be sure this issue happens every hour), we
range through the receivers, see no corresponding subscription, and
panic.
Closes#3093.
Signed-off-by: Pavel Karpy <carpawell@nspcc.ru>
Add a note about System.Runtime.GetNotifications refcounting to Domovoi
hardfork. Ref. https://github.com/neo-project/neo/pull/3301 and
https://github.com/nspcc-dev/neo-go/pull/3485.
Although NeoGo doesn't have anything to be updated, there's a
behaviour difference between C# and Go nodes before Domovoi hardfork, it
deserves a comment.
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
It's not correct to use an updated contract state got from Management to
check for the allowed method call. We need to use manifest from the
currently executing context for that. It may be critical for cases when
executing contract is being updated firstly, and after that calls
another contract. So we need an old (executing) contract manifest for
this check.
This change likely does not affect the mainnet's state since it's hard
to meet the trigger criteria, but I'd put it under the hardfork anyway.
Ref. https://github.com/neo-project/neo/pull/3290.
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
This test ensures that NeoGo node doesn't have the DeepCopy problem
described in https://github.com/neo-project/neo/issues/3300 and fixed in
https://github.com/neo-project/neo/pull/3301. This problem leads to the
fact that Notifications items are not being properly refcounted by C#
node which leads to possibility to build an enormously large object on
stack. Go node doesn't have this problem.
The reason (at least, as I understand it) is in the fact that C# node
performs objects refcounting inside the DeepCopy even if the object
itself is not yet on stack. I.e. System.Runtime.Notify handler
immediately adds references to the notification argumetns inside
DeepCopy:
b1d27f0189/src/Neo.VM/Types/Array.cs (L108)b1d27f0189/src/Neo.VM/Types/Array.cs (L75)
Whereas Go node just performs the honest DeepCopy without references counting:
b66cea5ccc/pkg/vm/stackitem/item.go (L1223)
Going further, C# node clears refs for notification arguments (for array
and underlying array items). System.Runtime.GetNotifications pushes the
notificaiton args array back on stack and increments counter only for
the external array, not for its arguments. Which results in negative
refcounter once notificaiton is removed from the stack. The fix itself
(f471c0542d/src/Neo/SmartContract/NotifyEventArgs.cs (L84))
doesn't need to be ported to NeoGo because Go node adds object to the
refcounter only at the moment when it's being pushed to stack by
System.Runtime.GetNotifications handler. This object is treated as new
object since it was deepcopied earlier by System.Runtime.Notify handler:
b66cea5ccc/pkg/vm/stack.go (L178).
Thus, no functoinal changes from the NeoGo side. And we won't
intentionally break our node to follow C# pre-Domovoi invalid behaviour.
Close#3484, close#3482.
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
Prevent the risk of a division by zero error when accessing the
`o.MainCfg.NeoFS.Nodes[index]` array.
Close#3419
Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
Do not use the updated contract state from native Management to perform
permissions checks. We need to use the currently executing state
instead got from the currently executing VM context until context is
unloaded.
Close#3471.
Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>