From cb684994fcc49cabaddc038a12bed27a8e82393e Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Tue, 20 Sep 2022 10:42:36 +0300 Subject: [PATCH] [#269] netmap: Support `Maintenance` node state Signed-off-by: Evgenii Stratonikov --- netmap/netmap_contract.go | 14 ++++++++++++++ tests/netmap_test.go | 30 +++++++++++++++++++++++------- 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/netmap/netmap_contract.go b/netmap/netmap_contract.go index 6b26218..3c873e2 100644 --- a/netmap/netmap_contract.go +++ b/netmap/netmap_contract.go @@ -56,6 +56,7 @@ const ( _ NodeState = iota OnlineState OfflineState + MaintenanceState ) var ( @@ -317,6 +318,9 @@ func UpdateState(state int, publicKey interop.PublicKey) { case OfflineState: removeFromNetmap(ctx, publicKey) runtime.Log("remove storage node from the network map") + case MaintenanceState: + updateNetmapState(ctx, publicKey, MaintenanceState) + runtime.Log("move storage node to a maintenance state") default: panic("unsupported state") } @@ -338,6 +342,8 @@ func UpdateStateIR(state NodeState, publicKey interop.PublicKey) { switch state { case OfflineState: removeFromNetmap(ctx, publicKey) + case MaintenanceState: + updateNetmapState(ctx, publicKey, MaintenanceState) default: panic("unsupported state") } @@ -649,6 +655,14 @@ func removeFromNetmap(ctx storage.Context, key interop.PublicKey) { storage.Delete(ctx, storageKey) } +func updateNetmapState(ctx storage.Context, key interop.PublicKey, state NodeState) { + storageKey := append(candidatePrefix, key...) + raw := storage.Get(ctx, storageKey).([]byte) + node := std.Deserialize(raw).(netmapNode) + node.state = state + storage.Put(ctx, storageKey, std.Serialize(node)) +} + func filterNetmap(ctx storage.Context, st NodeState) []storageNode { var ( netmap = getNetmapNodes(ctx) diff --git a/tests/netmap_test.go b/tests/netmap_test.go index b76690b..375d0ae 100644 --- a/tests/netmap_test.go +++ b/tests/netmap_test.go @@ -312,22 +312,37 @@ func TestUpdateStateIR(t *testing.T) { acc := cNm.NewAccount(t) dummyInfo := dummyNodeInfo(acc) cNm.Invoke(t, stackitem.Null{}, "addPeerIR", dummyInfo.raw) - pub := acc.(neotest.SingleSigner).Account().PrivateKey().PublicKey().Bytes() + acc1 := cNm.NewAccount(t) + dummyInfo1 := dummyNodeInfo(acc1) + cNm.Invoke(t, stackitem.Null{}, "addPeerIR", dummyInfo1.raw) + t.Run("must be signed by the alphabet", func(t *testing.T) { cAcc := cNm.WithSigners(acc) - cAcc.InvokeFail(t, common.ErrAlphabetWitnessFailed, "updateStateIR", int64(2), pub) + cAcc.InvokeFail(t, common.ErrAlphabetWitnessFailed, "updateStateIR", int64(netmap.OfflineState), pub) + }) + t.Run("can't move online", func(t *testing.T) { + cNm.InvokeFail(t, "unsupported state", "updateStateIR", int64(netmap.OnlineState), pub) }) t.Run("invalid state", func(t *testing.T) { cNm.InvokeFail(t, "unsupported state", "updateStateIR", int64(42), pub) }) + checkNetmapCandidates(t, cNm, 2) + + // Move the first node offline. + cNm.Invoke(t, stackitem.Null{}, "updateStateIR", int64(netmap.OfflineState), pub) checkNetmapCandidates(t, cNm, 1) - t.Run("good", func(t *testing.T) { - cNm.Invoke(t, stackitem.Null{}, "updateStateIR", int64(2), pub) - checkNetmapCandidates(t, cNm, 0) - }) + + // Move the second node in the maintenance state. + pub1 := acc1.(neotest.SingleSigner).Account().PrivateKey().PublicKey().Bytes() + cNm.Invoke(t, stackitem.Null{}, "updateStateIR", int64(netmap.MaintenanceState), pub1) + arr := checkNetmapCandidates(t, cNm, 1) + nn := arr[0].Value().([]stackitem.Item) + state, err := nn[1].TryInteger() + require.NoError(t, err) + require.Equal(t, int64(netmap.MaintenanceState), state.Int64()) } func TestUpdateState(t *testing.T) { @@ -365,7 +380,7 @@ func TestUpdateState(t *testing.T) { checkNetmapCandidates(t, cNm, 0) } -func checkNetmapCandidates(t *testing.T, c *neotest.ContractInvoker, size int) { +func checkNetmapCandidates(t *testing.T, c *neotest.ContractInvoker, size int) []stackitem.Item { s, err := c.TestInvoke(t, "netmapCandidates") require.NoError(t, err) require.Equal(t, 1, s.Len()) @@ -373,4 +388,5 @@ func checkNetmapCandidates(t *testing.T, c *neotest.ContractInvoker, size int) { arr, ok := s.Pop().Value().([]stackitem.Item) require.True(t, ok) require.Equal(t, size, len(arr)) + return arr }