neoneo-go/pkg/core/native/native_test/designate_test.go
Anna Shaleva 11ab42d91c core: keep Designation cache always valid and up-to-date
Always use cache instead of DAO where possible. Update cache in-place
each time new designated node is chosen.
2022-04-29 16:10:04 +03:00

139 lines
4.5 KiB
Go

package native_test
import (
"testing"
"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
"github.com/nspcc-dev/neo-go/pkg/core/native/noderoles"
"github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/neotest"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"github.com/stretchr/testify/require"
)
func newDesignateClient(t *testing.T) *neotest.ContractInvoker {
return newNativeClient(t, nativenames.Designation)
}
func TestDesignate_DesignateAsRole(t *testing.T) {
c := newDesignateClient(t)
e := c.Executor
designateInvoker := c.WithSigners(c.Committee)
priv, err := keys.NewPrivateKey()
require.NoError(t, err)
pubs := keys.PublicKeys{priv.PublicKey()}
setNodesByRole(t, designateInvoker, false, 0xFF, pubs)
setNodesByRole(t, designateInvoker, true, noderoles.Oracle, pubs)
index := e.Chain.BlockHeight() + 1
checkNodeRoles(t, designateInvoker, false, 0xFF, 0, nil)
checkNodeRoles(t, designateInvoker, false, noderoles.Oracle, 100500, nil)
checkNodeRoles(t, designateInvoker, true, noderoles.Oracle, 0, keys.PublicKeys{}) // returns an empty list
checkNodeRoles(t, designateInvoker, true, noderoles.Oracle, index, pubs) // returns pubs
priv1, err := keys.NewPrivateKey()
require.NoError(t, err)
pubs = keys.PublicKeys{priv1.PublicKey()}
setNodesByRole(t, designateInvoker, true, noderoles.StateValidator, pubs)
checkNodeRoles(t, designateInvoker, true, noderoles.StateValidator, e.Chain.BlockHeight()+1, pubs)
t.Run("neofs", func(t *testing.T) {
priv, err := keys.NewPrivateKey()
require.NoError(t, err)
pubs = keys.PublicKeys{priv.PublicKey()}
setNodesByRole(t, designateInvoker, true, noderoles.NeoFSAlphabet, pubs)
checkNodeRoles(t, designateInvoker, true, noderoles.NeoFSAlphabet, e.Chain.BlockHeight()+1, pubs)
})
}
type dummyOracle struct {
updateNodes func(k keys.PublicKeys)
}
// AddRequests processes new requests.
func (o *dummyOracle) AddRequests(map[uint64]*state.OracleRequest) {
}
// RemoveRequests removes already processed requests.
func (o *dummyOracle) RemoveRequests([]uint64) {
panic("TODO")
}
// UpdateOracleNodes updates oracle nodes.
func (o *dummyOracle) UpdateOracleNodes(k keys.PublicKeys) {
if o.updateNodes != nil {
o.updateNodes(k)
return
}
panic("TODO")
}
// UpdateNativeContract updates oracle contract native script and hash.
func (o *dummyOracle) UpdateNativeContract([]byte, []byte, util.Uint160, int) {
}
// Start runs oracle module.
func (o *dummyOracle) Start() {
panic("TODO")
}
// Shutdown shutdowns oracle module.
func (o *dummyOracle) Shutdown() {
panic("TODO")
}
func TestDesignate_Cache(t *testing.T) {
c := newDesignateClient(t)
e := c.Executor
designateInvoker := c.WithSigners(c.Committee)
r := int64(noderoles.Oracle)
var (
updatedNodes keys.PublicKeys
updateCalled bool
)
oracleServ := &dummyOracle{
updateNodes: func(k keys.PublicKeys) {
updatedNodes = k
updateCalled = true
},
}
privGood, err := keys.NewPrivateKey()
require.NoError(t, err)
pubsGood := []interface{}{privGood.PublicKey().Bytes()}
privBad, err := keys.NewPrivateKey()
require.NoError(t, err)
pubsBad := []interface{}{privBad.PublicKey().Bytes()}
// Firstly, designate good Oracle node and check that OracleService callback was called during PostPersist.
e.Chain.SetOracle(oracleServ)
txDesignateGood := designateInvoker.PrepareInvoke(t, "designateAsRole", r, pubsGood)
e.AddNewBlock(t, txDesignateGood)
e.CheckHalt(t, txDesignateGood.Hash(), stackitem.Null{})
require.True(t, updateCalled)
require.Equal(t, keys.PublicKeys{privGood.PublicKey()}, updatedNodes)
updatedNodes = nil
updateCalled = false
// Check designated node in a separate block.
checkNodeRoles(t, designateInvoker, true, noderoles.Oracle, e.Chain.BlockHeight()+1, keys.PublicKeys{privGood.PublicKey()})
// Designate privBad as oracle node and abort the transaction. Designation cache changes
// shouldn't be persisted to the contract and no notification should be sent.
w := io.NewBufBinWriter()
emit.AppCall(w.BinWriter, designateInvoker.Hash, "designateAsRole", callflag.All, int64(r), pubsBad)
emit.Opcodes(w.BinWriter, opcode.ABORT)
require.NoError(t, w.Err)
script := w.Bytes()
designateInvoker.InvokeScriptCheckFAULT(t, script, designateInvoker.Signers, "ABORT")
require.Nil(t, updatedNodes)
require.False(t, updateCalled)
}