[#224] netmap: Add tests for NewEpoch

Ensure snapshots are handled properly.

Signed-off-by: Evgenii Stratonikov <evgeniy@nspcc.ru>
This commit is contained in:
Evgenii Stratonikov 2022-03-10 14:29:24 +03:00 committed by Alex Vanin
parent 9884f8e68f
commit 666e1d6d8d
2 changed files with 93 additions and 6 deletions

View file

@ -52,8 +52,8 @@ const (
const ( const (
// V2 format // V2 format
_ nodeState = iota _ nodeState = iota
onlineState OnlineState
offlineState OfflineState
) )
var ( var (
@ -323,7 +323,7 @@ func UpdateState(state int, publicKey interop.PublicKey) {
} }
switch nodeState(state) { switch nodeState(state) {
case offlineState: case OfflineState:
removeFromNetmap(ctx, publicKey) removeFromNetmap(ctx, publicKey)
runtime.Log("remove storage node from the network map") runtime.Log("remove storage node from the network map")
default: default:
@ -343,7 +343,7 @@ func UpdateStateIR(state nodeState, publicKey interop.PublicKey) {
common.CheckAlphabetWitness(common.AlphabetAddress()) common.CheckAlphabetWitness(common.AlphabetAddress())
switch state { switch state {
case offlineState: case OfflineState:
removeFromNetmap(ctx, publicKey) removeFromNetmap(ctx, publicKey)
default: default:
panic("unsupported state") panic("unsupported state")
@ -396,7 +396,7 @@ func NewEpoch(epochNum int) {
panic("invalid epoch") // ignore invocations with invalid epoch panic("invalid epoch") // ignore invocations with invalid epoch
} }
dataOnlineState := filterNetmap(ctx, onlineState) dataOnlineState := filterNetmap(ctx, OnlineState)
runtime.Log("process new epoch") runtime.Log("process new epoch")
@ -556,7 +556,7 @@ func addToNetmap(ctx storage.Context, n storageNode) {
node = netmapNode{ node = netmapNode{
node: n, node: n,
state: onlineState, state: OnlineState,
} }
) )

View file

@ -4,6 +4,7 @@ import (
"math/big" "math/big"
"math/rand" "math/rand"
"path" "path"
"strings"
"testing" "testing"
"github.com/nspcc-dev/neo-go/pkg/encoding/bigint" "github.com/nspcc-dev/neo-go/pkg/encoding/bigint"
@ -13,6 +14,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"github.com/nspcc-dev/neofs-contract/common" "github.com/nspcc-dev/neofs-contract/common"
"github.com/nspcc-dev/neofs-contract/container" "github.com/nspcc-dev/neofs-contract/container"
"github.com/nspcc-dev/neofs-contract/netmap"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@ -104,6 +106,91 @@ func TestAddPeer(t *testing.T) {
c.Invoke(t, stackitem.Null{}, "addPeerIR", dummyInfo.raw) c.Invoke(t, stackitem.Null{}, "addPeerIR", dummyInfo.raw)
} }
func TestNewEpoch(t *testing.T) {
rand.Seed(42)
const epochCount = netmap.SnapshotCount * 2
cNm := newNetmapInvoker(t)
nodes := make([][]testNodeInfo, epochCount)
for i := range nodes {
size := rand.Int()%5 + 1
arr := make([]testNodeInfo, size)
for j := 0; j < size; j++ {
arr[j] = newStorageNode(t, cNm)
}
nodes[i] = arr
}
for i := 0; i < epochCount; i++ {
for _, tn := range nodes[i] {
cNm.WithSigners(tn.signer).Invoke(t, stackitem.Null{}, "addPeer", tn.raw)
cNm.Invoke(t, stackitem.Null{}, "addPeerIR", tn.raw)
}
if i > 0 {
// Remove random nodes from the previous netmap.
current := make([]testNodeInfo, 0, len(nodes[i])+len(nodes[i-1]))
current = append(current, nodes[i]...)
for j := range nodes[i-1] {
if rand.Int()%3 == 0 {
cNm.Invoke(t, stackitem.Null{}, "updateStateIR",
int64(netmap.OfflineState), nodes[i-1][j].pub)
} else {
current = append(current, nodes[i-1][j])
}
}
nodes[i] = current
}
cNm.Invoke(t, stackitem.Null{}, "newEpoch", i+1)
t.Logf("Epoch: %d, Netmap()", i)
s, err := cNm.TestInvoke(t, "netmap")
require.NoError(t, err)
require.Equal(t, 1, s.Len())
checkSnapshot(t, s, nodes[i])
for j := 0; j <= i && j < netmap.SnapshotCount; j++ {
t.Logf("Epoch: %d, diff: %d", i, j)
s, err := cNm.TestInvoke(t, "snapshot", int64(j))
require.NoError(t, err)
require.Equal(t, 1, s.Len())
checkSnapshot(t, s, nodes[i-j])
}
_, err = cNm.TestInvoke(t, "snapshot", netmap.SnapshotCount)
require.Error(t, err)
require.True(t, strings.Contains(err.Error(), "incorrect diff"))
_, err = cNm.TestInvoke(t, "snapshot", -1)
require.Error(t, err)
require.True(t, strings.Contains(err.Error(), "incorrect diff"))
}
}
func checkSnapshot(t *testing.T, s *vm.Stack, nodes []testNodeInfo) {
arr, ok := s.Pop().Value().([]stackitem.Item)
require.True(t, ok, "expected array")
require.Equal(t, len(nodes), len(arr), "expected %d nodes", len(nodes))
actual := make([][]byte, len(nodes))
expected := make([][]byte, len(nodes))
for i := range nodes {
n, ok := arr[i].Value().([]stackitem.Item)
require.True(t, ok, "expected node struct")
require.Equal(t, 1, len(n), "expected single field")
raw, ok := n[0].Value().([]byte)
require.True(t, ok, "expected bytes")
actual[i] = raw
expected[i] = nodes[i].raw
}
require.ElementsMatch(t, expected, actual, "snapshot is different")
}
func TestUpdateState(t *testing.T) { func TestUpdateState(t *testing.T) {
cNm := newNetmapInvoker(t) cNm := newNetmapInvoker(t)