Skip to content

Commit

Permalink
Test migration of the contracts to notary mode
Browse files Browse the repository at this point in the history
Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
  • Loading branch information
cthulhu-rider committed Mar 17, 2023
1 parent 237309e commit 194e1a7
Show file tree
Hide file tree
Showing 12 changed files with 941 additions and 45 deletions.
119 changes: 119 additions & 0 deletions alphabet/migration_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package alphabet_test

import (
"math/rand"
"path/filepath"
"testing"

"github.com/nspcc-dev/neo-go/pkg/interop"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"github.com/nspcc-dev/neofs-contract/tests/dump"
"github.com/nspcc-dev/neofs-contract/tests/migration"
"github.com/stretchr/testify/require"
)

const name = "alphabet"

func TestMigration(t *testing.T) {
err := dump.IterateDumps("../testdata", func(id dump.ID, r *dump.Reader) {
t.Run(id.String()+"/"+name, func(t *testing.T) {
testMigrationFromDump(t, r)
})
})
require.NoError(t, err)
}

func replaceArgI(vs []interface{}, i int, v interface{}) []interface{} {
res := make([]interface{}, len(vs))
copy(res, vs)
res[i] = v
return res
}

func randUint160() (u util.Uint160) {
rand.Read(u[:])
return
}

var notaryDisabledKey = []byte("notary")

func testMigrationFromDump(t *testing.T, d *dump.Reader) {
// init test contract shell
c := migration.NewContract(t, d, "alphabet0", migration.ContractOptions{
SourceCodeDir: filepath.Join("..", name),
})

migration.SkipUnsupportedVersions(t, c)

// gather values which can't be fetched via contract API
v := c.GetStorageItem(notaryDisabledKey)
notaryDisabled := len(v) == 1 && v[0] == 1

readPendingVotes := func() bool {
if v := c.GetStorageItem([]byte("ballots")); v != nil {
item, err := stackitem.Deserialize(v)
require.NoError(t, err)
arr, ok := item.Value().([]stackitem.Item)
if ok {
return len(arr) > 0
} else {
require.Equal(t, stackitem.Null{}, item)
}
}
return false
}

prevPendingVote := readPendingVotes()

// read previous values using contract API
readName := func() string {
b, err := c.Call(t, "name").TryBytes()
require.NoError(t, err)
return string(b)
}

prevName := readName()

// try to update the contract
proxyContract := randUint160()
updPrm := []interface{}{
false, // non-notary mode
randUint160(), // unused
[]byte{}, // Proxy contract (custom)
"", // unused
0, // unused
0, // unused
}

c.CheckUpdateFail(t, "update to non-notary mode is not supported anymore",
replaceArgI(updPrm, 0, true)...)

if notaryDisabled {
c.CheckUpdateFail(t, "address of the Proxy contract is missing or invalid",
replaceArgI(updPrm, 2, make([]byte, interop.Hash160Len+1))...)
c.CheckUpdateFail(t, "token not found", updPrm...)

c.RegisterContractInNNS(t, "proxy", proxyContract)

if prevPendingVote {
c.CheckUpdateFail(t, "pending vote detected", updPrm...)
return
}
}

c.CheckUpdateSuccess(t, updPrm...)

// check that contract was updates as expected
newName := readName()
newPendingVote := readPendingVotes()

require.Nil(t, c.GetStorageItem(notaryDisabledKey), "notary flag should be removed")
require.Nil(t, c.GetStorageItem([]byte("innerring")), "Inner Ring nodes should be removed")
require.Equal(t, prevName, newName, "name should remain")
require.False(t, newPendingVote, "there should be no more pending votes")

if notaryDisabled {
require.Equal(t, proxyContract[:], c.GetStorageItem([]byte("proxyScriptHash")), "name should remain")
}
}
62 changes: 62 additions & 0 deletions audit/migration_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package audit_test

import (
"testing"

"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"github.com/nspcc-dev/neofs-contract/tests/dump"
"github.com/nspcc-dev/neofs-contract/tests/migration"
"github.com/stretchr/testify/require"
)

const name = "audit"

func TestMigration(t *testing.T) {
err := dump.IterateDumps("../testdata", func(id dump.ID, r *dump.Reader) {
t.Run(id.String()+"/"+name, func(t *testing.T) {
testMigrationFromDump(t, r)
})
})
require.NoError(t, err)
}

func testMigrationFromDump(t *testing.T, d *dump.Reader) {
// init test contract shell
c := migration.NewContract(t, d, name, migration.ContractOptions{})

migration.SkipUnsupportedVersions(t, c)

// read previous values using contract API
readAllAuditResults := func() []stackitem.Item {
r := c.Call(t, "list")
items, ok := r.Value().([]stackitem.Item)
if !ok {
require.Equal(t, stackitem.Null{}, r)
}

var results []stackitem.Item

for i := range items {
bID, err := items[i].TryBytes()
require.NoError(t, err)

results = append(results, c.Call(t, "get", bID))
}

return results
}

prevAuditResults := readAllAuditResults()

// try to update the contract
var notary bool
c.CheckUpdateFail(t, "update to non-notary mode is not supported anymore", !notary)
c.CheckUpdateSuccess(t, notary)

// check that contract was updates as expected
newAuditResults := readAllAuditResults()

require.Nil(t, c.GetStorageItem([]byte("notary")), "notary flag should be removed")
require.Nil(t, c.GetStorageItem([]byte("netmapScriptHash")), "Netmap contract address should be removed")
require.ElementsMatch(t, prevAuditResults, newAuditResults, "audit results should remain")
}
81 changes: 81 additions & 0 deletions balance/migration_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package balance_test

import (
"testing"

"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"github.com/nspcc-dev/neofs-contract/tests/dump"
"github.com/nspcc-dev/neofs-contract/tests/migration"
"github.com/stretchr/testify/require"
)

const name = "balance"

func TestMigration(t *testing.T) {
err := dump.IterateDumps("../testdata", func(id dump.ID, r *dump.Reader) {
t.Run(id.String()+"/"+name, func(t *testing.T) {
testMigrationFromDump(t, r)
})
})
require.NoError(t, err)
}

var notaryDisabledKey = []byte("notary")

func testMigrationFromDump(t *testing.T, d *dump.Reader) {
// init test contract shell
c := migration.NewContract(t, d, name, migration.ContractOptions{})

migration.SkipUnsupportedVersions(t, c)

// gather values which can't be fetched via contract API
v := c.GetStorageItem(notaryDisabledKey)
notaryDisabled := len(v) == 1 && v[0] == 1

readPendingVotes := func() bool {
if v := c.GetStorageItem([]byte("ballots")); v != nil {
item, err := stackitem.Deserialize(v)
require.NoError(t, err)
arr, ok := item.Value().([]stackitem.Item)
if ok {
return len(arr) > 0
} else {
require.Equal(t, stackitem.Null{}, item)
}
}
return false
}

prevPendingVotes := readPendingVotes()

// read previous values using contract API
readTotalSupply := func() int64 {
n, err := c.Call(t, "totalSupply").TryInteger()
require.NoError(t, err)
return n.Int64()
}

prevTotalSupply := readTotalSupply()

// try to update the contract
var notary bool
c.CheckUpdateFail(t, "update to non-notary mode is not supported anymore", !notary)

if notaryDisabled && prevPendingVotes {
c.CheckUpdateFail(t, "pending vote detected", notary)
return
}

c.CheckUpdateSuccess(t, notary)

// check that contract was updates as expected
newTotalSupply := readTotalSupply()
newPendingVotes := readPendingVotes()

require.False(t, newPendingVotes, "there should be no more pending votes")
require.Nil(t, c.GetStorageItem(notaryDisabledKey), "notary flag should be removed")
require.Nil(t, c.GetStorageItem([]byte("containerScriptHash")), "Container contract address should be removed")
require.Nil(t, c.GetStorageItem([]byte("netmapScriptHash")), "Netmap contract address should be removed")

require.Equal(t, prevTotalSupply, newTotalSupply)
}
119 changes: 119 additions & 0 deletions container/migration_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package container_test

import (
"bytes"
"testing"

"github.com/mr-tron/base58"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"github.com/nspcc-dev/neofs-contract/tests/dump"
"github.com/nspcc-dev/neofs-contract/tests/migration"
"github.com/stretchr/testify/require"
)

const name = "container"

func TestMigration(t *testing.T) {
err := dump.IterateDumps("../testdata", func(id dump.ID, r *dump.Reader) {
t.Run(id.String()+"/"+name, func(t *testing.T) {
testMigrationFromDump(t, r)
})
})
require.NoError(t, err)
}

var notaryDisabledKey = []byte("notary")

func testMigrationFromDump(t *testing.T, d *dump.Reader) {
// gather values which can't be fetched via contract API
var owners [][]byte

c := migration.NewContract(t, d, "container", migration.ContractOptions{
StorageDumpHandler: func(key, value []byte) {
const ownerLen = 25
if len(key) == ownerLen+32 { // + cid
for i := range owners {
if bytes.Equal(owners[i], key[:ownerLen]) {
return
}
}
owners = append(owners, key[:ownerLen])
}
},
})

migration.SkipUnsupportedVersions(t, c)

v := c.GetStorageItem(notaryDisabledKey)
notaryDisabled := len(v) == 1 && v[0] == 1

readPendingVotes := func() bool {
if v := c.GetStorageItem([]byte("ballots")); v != nil {
item, err := stackitem.Deserialize(v)
require.NoError(t, err)
arr, ok := item.Value().([]stackitem.Item)
if ok {
return len(arr) > 0
} else {
require.Equal(t, stackitem.Null{}, item)
}
}
return false
}

prevPendingVote := readPendingVotes()

// read previous values using contract API
readAllContainers := func() []stackitem.Item {
containers, ok := c.Call(t, "list", []byte{}).Value().([]stackitem.Item)
require.True(t, ok)
return containers
}

readContainerCount := func() uint64 {
nContainers, err := c.Call(t, "count").TryInteger()
require.NoError(t, err)
return nContainers.Uint64()
}

readOwnersToContainers := func() map[string][]stackitem.Item {
m := make(map[string][]stackitem.Item, len(owners))
for i := range owners {
m[string(owners[i])] = c.Call(t, "list", owners[i]).Value().([]stackitem.Item)
}
return m
}

prevContainers := readAllContainers()
prevContainerCount := readContainerCount()
prevOwnersToContainers := readOwnersToContainers()

// try to update the contract
var notary bool
c.CheckUpdateFail(t, "update to non-notary mode is not supported anymore", !notary)

if notaryDisabled && prevPendingVote {
c.CheckUpdateFail(t, "pending vote detected", notary)
return
}

c.CheckUpdateSuccess(t, notary)

// check that contract was updates as expected
newPendingVote := readPendingVotes()
newContainers := readAllContainers()
newContainerCount := readContainerCount()
newOwnersToContainers := readOwnersToContainers()

require.Nil(t, c.GetStorageItem(notaryDisabledKey), "notary flag should be removed")
require.Equal(t, prevContainerCount, newContainerCount, "number of containers should remain")
require.ElementsMatch(t, prevContainers, newContainers, "container list should remain")
require.False(t, newPendingVote, "there should be no more pending votes")

require.Equal(t, len(prevOwnersToContainers), len(newOwnersToContainers))
for k, vPrev := range prevOwnersToContainers {
vNew, ok := newOwnersToContainers[k]
require.True(t, ok)
require.ElementsMatch(t, vPrev, vNew, "containers of '%s' owner should remain", base58.Encode([]byte(k)))
}
}
Loading

0 comments on commit 194e1a7

Please sign in to comment.