From 681bd89cc763486de46340cb0df2a6edbe0110da Mon Sep 17 00:00:00 2001 From: Anna Shaleva Date: Tue, 23 Mar 2021 13:37:30 +0300 Subject: [PATCH 1/3] core: move native node roles to a separate pkg We need this to avoid `native` dependency in the RPC client. --- pkg/compiler/native_test.go | 9 ++--- pkg/core/blockchain.go | 9 ++--- pkg/core/blockchain_test.go | 5 +-- pkg/core/helper_test.go | 3 +- pkg/core/native/designate.go | 58 +++++++++++++----------------- pkg/core/native/noderoles/roles.go | 12 +++++++ pkg/core/native/notary.go | 3 +- pkg/core/native/oracle.go | 5 +-- pkg/core/native_designate_test.go | 47 ++++++++++++------------ pkg/core/native_notary_test.go | 4 +-- pkg/core/native_oracle_test.go | 3 +- pkg/core/notary_test.go | 4 +-- pkg/core/oracle_test.go | 6 ++-- pkg/core/stateroot_test.go | 10 +++--- 14 files changed, 94 insertions(+), 84 deletions(-) create mode 100644 pkg/core/native/noderoles/roles.go diff --git a/pkg/compiler/native_test.go b/pkg/compiler/native_test.go index 644d9bace..457c2b8df 100644 --- a/pkg/compiler/native_test.go +++ b/pkg/compiler/native_test.go @@ -9,6 +9,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/core/interop" "github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames" "github.com/nspcc-dev/neo-go/pkg/core/native" + "github.com/nspcc-dev/neo-go/pkg/core/native/noderoles" "github.com/nspcc-dev/neo-go/pkg/interop/native/crypto" "github.com/nspcc-dev/neo-go/pkg/interop/native/gas" "github.com/nspcc-dev/neo-go/pkg/interop/native/ledger" @@ -69,10 +70,10 @@ func TestContractParameterTypes(t *testing.T) { } func TestRoleManagementRole(t *testing.T) { - require.EqualValues(t, native.RoleOracle, roles.Oracle) - require.EqualValues(t, native.RoleStateValidator, roles.StateValidator) - require.EqualValues(t, native.RoleNeoFSAlphabet, roles.NeoFSAlphabet) - require.EqualValues(t, native.RoleP2PNotary, roles.P2PNotary) + require.EqualValues(t, noderoles.Oracle, roles.Oracle) + require.EqualValues(t, noderoles.StateValidator, roles.StateValidator) + require.EqualValues(t, noderoles.NeoFSAlphabet, roles.NeoFSAlphabet) + require.EqualValues(t, noderoles.P2PNotary, roles.P2PNotary) } func TestNameServiceRecordType(t *testing.T) { diff --git a/pkg/core/blockchain.go b/pkg/core/blockchain.go index 5a7154045..f09d77cf6 100644 --- a/pkg/core/blockchain.go +++ b/pkg/core/blockchain.go @@ -20,6 +20,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/core/interop/contract" "github.com/nspcc-dev/neo-go/pkg/core/mempool" "github.com/nspcc-dev/neo-go/pkg/core/native" + "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/core/stateroot" "github.com/nspcc-dev/neo-go/pkg/core/storage" @@ -791,11 +792,11 @@ func (bc *Blockchain) storeBlock(block *block.Block, txpool *mempool.Pool) error func (bc *Blockchain) updateExtensibleWhitelist(height uint32) error { updateCommittee := native.ShouldUpdateCommittee(height, bc) - oracles, oh, err := bc.contracts.Designate.GetDesignatedByRole(bc.dao, native.RoleOracle, height) + oracles, oh, err := bc.contracts.Designate.GetDesignatedByRole(bc.dao, noderoles.Oracle, height) if err != nil { return err } - stateVals, sh, err := bc.contracts.Designate.GetDesignatedByRole(bc.dao, native.RoleStateValidator, height) + stateVals, sh, err := bc.contracts.Designate.GetDesignatedByRole(bc.dao, noderoles.StateValidator, height) if err != nil { return err } @@ -814,7 +815,7 @@ func (bc *Blockchain) updateExtensibleWhitelist(height uint32) error { bc.updateExtensibleList(&newList, bc.contracts.NEO.GetNextBlockValidatorsInternal()) if len(oracles) > 0 { - h, err := bc.contracts.Designate.GetLastDesignatedHash(bc.dao, native.RoleOracle) + h, err := bc.contracts.Designate.GetLastDesignatedHash(bc.dao, noderoles.Oracle) if err != nil { return err } @@ -823,7 +824,7 @@ func (bc *Blockchain) updateExtensibleWhitelist(height uint32) error { } if len(stateVals) > 0 { - h, err := bc.contracts.Designate.GetLastDesignatedHash(bc.dao, native.RoleStateValidator) + h, err := bc.contracts.Designate.GetLastDesignatedHash(bc.dao, noderoles.StateValidator) if err != nil { return err } diff --git a/pkg/core/blockchain_test.go b/pkg/core/blockchain_test.go index bc933a83f..132d763a2 100644 --- a/pkg/core/blockchain_test.go +++ b/pkg/core/blockchain_test.go @@ -21,6 +21,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames" "github.com/nspcc-dev/neo-go/pkg/core/mempool" "github.com/nspcc-dev/neo-go/pkg/core/native" + "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/core/storage" "github.com/nspcc-dev/neo-go/pkg/core/transaction" @@ -596,7 +597,7 @@ func TestVerifyTx(t *testing.T) { ic := bc.newInteropContext(trigger.All, bc.dao, bl, txSetOracle) ic.SpawnVM() ic.VM.LoadScript([]byte{byte(opcode.RET)}) - require.NoError(t, bc.contracts.Designate.DesignateAsRole(ic, native.RoleOracle, oraclePubs)) + require.NoError(t, bc.contracts.Designate.DesignateAsRole(ic, noderoles.Oracle, oraclePubs)) _, err = ic.DAO.Persist() require.NoError(t, err) @@ -807,7 +808,7 @@ func TestVerifyTx(t *testing.T) { ic := bc.newInteropContext(trigger.All, bc.dao, bl, txSetNotary) ic.SpawnVM() ic.VM.LoadScript([]byte{byte(opcode.RET)}) - require.NoError(t, bc.contracts.Designate.DesignateAsRole(ic, native.RoleP2PNotary, keys.PublicKeys{notary.PrivateKey().PublicKey()})) + require.NoError(t, bc.contracts.Designate.DesignateAsRole(ic, noderoles.P2PNotary, keys.PublicKeys{notary.PrivateKey().PublicKey()})) _, err = ic.DAO.Persist() require.NoError(t, err) getNotaryAssistedTx := func(signaturesCount uint8, serviceFee int64) *transaction.Transaction { diff --git a/pkg/core/helper_test.go b/pkg/core/helper_test.go index 751039bbc..21c46c920 100644 --- a/pkg/core/helper_test.go +++ b/pkg/core/helper_test.go @@ -23,6 +23,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/core/chaindump" "github.com/nspcc-dev/neo-go/pkg/core/fee" "github.com/nspcc-dev/neo-go/pkg/core/native" + "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/core/storage" "github.com/nspcc-dev/neo-go/pkg/core/transaction" @@ -472,7 +473,7 @@ func initBasicChain(t *testing.T, bc *Blockchain) { ntr, err := wallet.NewWalletFromFile(path.Join(notaryModulePath, "./testdata/notary1.json")) require.NoError(t, err) require.NoError(t, ntr.Accounts[0].Decrypt("one")) - bc.setNodesByRole(t, true, native.RoleP2PNotary, keys.PublicKeys{ntr.Accounts[0].PrivateKey().PublicKey()}) + bc.setNodesByRole(t, true, noderoles.P2PNotary, keys.PublicKeys{ntr.Accounts[0].PrivateKey().PublicKey()}) t.Logf("Designated Notary node: %s", hex.EncodeToString(ntr.Accounts[0].PrivateKey().PublicKey().Bytes())) // Push verification contract with arguments into the chain. diff --git a/pkg/core/native/designate.go b/pkg/core/native/designate.go index c70e70640..e0edc425e 100644 --- a/pkg/core/native/designate.go +++ b/pkg/core/native/designate.go @@ -13,6 +13,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/core/interop" "github.com/nspcc-dev/neo-go/pkg/core/interop/runtime" "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/hash" "github.com/nspcc-dev/neo-go/pkg/crypto/keys" @@ -58,17 +59,6 @@ const ( maxNodeCount = 32 ) -// Role represents type of participant. -type Role byte - -// Role enumeration. -const ( - RoleStateValidator Role = 4 - RoleOracle Role = 8 - RoleNeoFSAlphabet Role = 16 - RoleP2PNotary Role = 128 -) - // Various errors. var ( ErrAlreadyDesignated = errors.New("already designated given role at current block") @@ -79,9 +69,9 @@ var ( ErrNoBlock = errors.New("no persisting block in the context") ) -func (s *Designate) isValidRole(r Role) bool { - return r == RoleOracle || r == RoleStateValidator || - r == RoleNeoFSAlphabet || (s.p2pSigExtensionsEnabled && r == RoleP2PNotary) +func (s *Designate) isValidRole(r noderoles.Role) bool { + return r == noderoles.Oracle || r == noderoles.StateValidator || + r == noderoles.NeoFSAlphabet || (s.p2pSigExtensionsEnabled && r == noderoles.P2PNotary) } func newDesignate(p2pSigExtensionsEnabled bool) *Designate { @@ -120,17 +110,17 @@ func (s *Designate) PostPersist(ic *interop.Context) error { return nil } - if err := s.updateCachedRoleData(&s.oracles, ic.DAO, RoleOracle); err != nil { + if err := s.updateCachedRoleData(&s.oracles, ic.DAO, noderoles.Oracle); err != nil { return err } - if err := s.updateCachedRoleData(&s.stateVals, ic.DAO, RoleStateValidator); err != nil { + if err := s.updateCachedRoleData(&s.stateVals, ic.DAO, noderoles.StateValidator); err != nil { return err } - if err := s.updateCachedRoleData(&s.neofsAlphabet, ic.DAO, RoleNeoFSAlphabet); err != nil { + if err := s.updateCachedRoleData(&s.neofsAlphabet, ic.DAO, noderoles.NeoFSAlphabet); err != nil { return err } if s.p2pSigExtensionsEnabled { - if err := s.updateCachedRoleData(&s.notaries, ic.DAO, RoleP2PNotary); err != nil { + if err := s.updateCachedRoleData(&s.notaries, ic.DAO, noderoles.P2PNotary); err != nil { return err } } @@ -169,13 +159,13 @@ func (s *Designate) rolesChanged() bool { return rc == nil || rc.(bool) } -func (s *Designate) hashFromNodes(r Role, nodes keys.PublicKeys) util.Uint160 { +func (s *Designate) hashFromNodes(r noderoles.Role, nodes keys.PublicKeys) util.Uint160 { if len(nodes) == 0 { return util.Uint160{} } var script []byte switch r { - case RoleP2PNotary: + case noderoles.P2PNotary: script, _ = smartcontract.CreateMultiSigRedeemScript(1, nodes.Copy()) default: script, _ = smartcontract.CreateDefaultMultiSigRedeemScript(nodes.Copy()) @@ -183,7 +173,7 @@ func (s *Designate) hashFromNodes(r Role, nodes keys.PublicKeys) util.Uint160 { return hash.Hash160(script) } -func (s *Designate) updateCachedRoleData(v *atomic.Value, d dao.DAO, r Role) error { +func (s *Designate) updateCachedRoleData(v *atomic.Value, d dao.DAO, r noderoles.Role) error { nodeKeys, height, err := s.GetDesignatedByRole(d, r, math.MaxUint32) if err != nil { return err @@ -194,15 +184,15 @@ func (s *Designate) updateCachedRoleData(v *atomic.Value, d dao.DAO, r Role) err height: height, }) switch r { - case RoleOracle: + case noderoles.Oracle: if orc, _ := s.OracleService.Load().(services.Oracle); orc != nil { orc.UpdateOracleNodes(nodeKeys.Copy()) } - case RoleP2PNotary: + case noderoles.P2PNotary: if ntr, _ := s.NotaryService.Load().(services.Notary); ntr != nil { ntr.UpdateNotaryNodes(nodeKeys.Copy()) } - case RoleStateValidator: + case noderoles.StateValidator: if s.StateRootService != nil { s.StateRootService.UpdateStateValidators(height, nodeKeys.Copy()) } @@ -210,16 +200,16 @@ func (s *Designate) updateCachedRoleData(v *atomic.Value, d dao.DAO, r Role) err return nil } -func (s *Designate) getCachedRoleData(r Role) *roleData { +func (s *Designate) getCachedRoleData(r noderoles.Role) *roleData { var val interface{} switch r { - case RoleOracle: + case noderoles.Oracle: val = s.oracles.Load() - case RoleStateValidator: + case noderoles.StateValidator: val = s.stateVals.Load() - case RoleNeoFSAlphabet: + case noderoles.NeoFSAlphabet: val = s.neofsAlphabet.Load() - case RoleP2PNotary: + case noderoles.P2PNotary: val = s.notaries.Load() } if val != nil { @@ -229,7 +219,7 @@ func (s *Designate) getCachedRoleData(r Role) *roleData { } // GetLastDesignatedHash returns last designated hash of a given role. -func (s *Designate) GetLastDesignatedHash(d dao.DAO, r Role) (util.Uint160, error) { +func (s *Designate) GetLastDesignatedHash(d dao.DAO, r noderoles.Role) (util.Uint160, error) { if !s.isValidRole(r) { return util.Uint160{}, ErrInvalidRole } @@ -247,7 +237,7 @@ func (s *Designate) GetLastDesignatedHash(d dao.DAO, r Role) (util.Uint160, erro } // GetDesignatedByRole returns nodes for role r. -func (s *Designate) GetDesignatedByRole(d dao.DAO, r Role, index uint32) (keys.PublicKeys, uint32, error) { +func (s *Designate) GetDesignatedByRole(d dao.DAO, r noderoles.Role, index uint32) (keys.PublicKeys, uint32, error) { if !s.isValidRole(r) { return nil, 0, ErrInvalidRole } @@ -301,7 +291,7 @@ func (s *Designate) designateAsRole(ic *interop.Context, args []stackitem.Item) } // DesignateAsRole sets nodes for role r. -func (s *Designate) DesignateAsRole(ic *interop.Context, r Role, pubs keys.PublicKeys) error { +func (s *Designate) DesignateAsRole(ic *interop.Context, r noderoles.Role, pubs keys.PublicKeys) error { length := len(pubs) if length == 0 { return ErrEmptyNodeList @@ -332,7 +322,7 @@ func (s *Designate) DesignateAsRole(ic *interop.Context, r Role, pubs keys.Publi return ic.DAO.PutStorageItem(s.ID, key, NodeList(pubs).Bytes()) } -func (s *Designate) getRole(item stackitem.Item) (Role, bool) { +func (s *Designate) getRole(item stackitem.Item) (noderoles.Role, bool) { bi, err := item.TryInteger() if err != nil { return 0, false @@ -341,5 +331,5 @@ func (s *Designate) getRole(item stackitem.Item) (Role, bool) { return 0, false } u := bi.Uint64() - return Role(u), u <= math.MaxUint8 && s.isValidRole(Role(u)) + return noderoles.Role(u), u <= math.MaxUint8 && s.isValidRole(noderoles.Role(u)) } diff --git a/pkg/core/native/noderoles/roles.go b/pkg/core/native/noderoles/roles.go new file mode 100644 index 000000000..3a0572fe2 --- /dev/null +++ b/pkg/core/native/noderoles/roles.go @@ -0,0 +1,12 @@ +package noderoles + +// Role represents type of participant. +type Role byte + +// Role enumeration. +const ( + StateValidator Role = 4 + Oracle Role = 8 + NeoFSAlphabet Role = 16 + P2PNotary Role = 128 +) diff --git a/pkg/core/native/notary.go b/pkg/core/native/notary.go index abf0d2b66..70ae4468d 100644 --- a/pkg/core/native/notary.go +++ b/pkg/core/native/notary.go @@ -12,6 +12,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/core/interop/contract" "github.com/nspcc-dev/neo-go/pkg/core/interop/runtime" "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/core/storage" "github.com/nspcc-dev/neo-go/pkg/core/transaction" @@ -370,7 +371,7 @@ func (n *Notary) verify(ic *interop.Context, args []stackitem.Item) stackitem.It // GetNotaryNodes returns public keys of notary nodes. func (n *Notary) GetNotaryNodes(d dao.DAO) (keys.PublicKeys, error) { - nodes, _, err := n.Desig.GetDesignatedByRole(d, RoleP2PNotary, math.MaxUint32) + nodes, _, err := n.Desig.GetDesignatedByRole(d, noderoles.P2PNotary, math.MaxUint32) return nodes, err } diff --git a/pkg/core/native/oracle.go b/pkg/core/native/oracle.go index 5533eaf66..9bc81cd18 100644 --- a/pkg/core/native/oracle.go +++ b/pkg/core/native/oracle.go @@ -15,6 +15,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/core/interop/contract" "github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames" "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/core/storage" "github.com/nspcc-dev/neo-go/pkg/core/transaction" @@ -410,12 +411,12 @@ func (o *Oracle) PutRequestInternal(id uint64, req *state.OracleRequest, d dao.D // GetScriptHash returns script hash or oracle nodes. func (o *Oracle) GetScriptHash(d dao.DAO) (util.Uint160, error) { - return o.Desig.GetLastDesignatedHash(d, RoleOracle) + return o.Desig.GetLastDesignatedHash(d, noderoles.Oracle) } // GetOracleNodes returns public keys of oracle nodes. func (o *Oracle) GetOracleNodes(d dao.DAO) (keys.PublicKeys, error) { - nodes, _, err := o.Desig.GetDesignatedByRole(d, RoleOracle, math.MaxUint32) + nodes, _, err := o.Desig.GetDesignatedByRole(d, noderoles.Oracle, math.MaxUint32) return nodes, err } diff --git a/pkg/core/native_designate_test.go b/pkg/core/native_designate_test.go index 8e85e74c5..c19794478 100644 --- a/pkg/core/native_designate_test.go +++ b/pkg/core/native_designate_test.go @@ -8,6 +8,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/config/netmode" "github.com/nspcc-dev/neo-go/pkg/core/block" "github.com/nspcc-dev/neo-go/pkg/core/native" + "github.com/nspcc-dev/neo-go/pkg/core/native/noderoles" "github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/io" @@ -20,7 +21,7 @@ import ( "github.com/stretchr/testify/require" ) -func (bc *Blockchain) setNodesByRole(t *testing.T, ok bool, r native.Role, nodes keys.PublicKeys) { +func (bc *Blockchain) setNodesByRole(t *testing.T, ok bool, r noderoles.Role, nodes keys.PublicKeys) { w := io.NewBufBinWriter() for _, pub := range nodes { emit.Bytes(w.BinWriter, pub.Bytes()) @@ -63,7 +64,7 @@ func (bc *Blockchain) setNodesByRole(t *testing.T, ok bool, r native.Role, nodes } } -func (bc *Blockchain) getNodesByRole(t *testing.T, ok bool, r native.Role, index uint32, resLen int) { +func (bc *Blockchain) getNodesByRole(t *testing.T, ok bool, r noderoles.Role, index uint32, resLen int) { res, err := invokeContractMethod(bc, 10_000_000, bc.contracts.Designate.Hash, "getDesignatedByRole", int64(r), int64(index)) require.NoError(t, err) if ok { @@ -86,25 +87,25 @@ func TestDesignate_DesignateAsRoleTx(t *testing.T) { pubs := keys.PublicKeys{priv.PublicKey()} bc.setNodesByRole(t, false, 0xFF, pubs) - bc.setNodesByRole(t, true, native.RoleOracle, pubs) + bc.setNodesByRole(t, true, noderoles.Oracle, pubs) index := bc.BlockHeight() + 1 bc.getNodesByRole(t, false, 0xFF, 0, 0) - bc.getNodesByRole(t, false, native.RoleOracle, 100500, 0) - bc.getNodesByRole(t, true, native.RoleOracle, 0, 0) // returns an empty list - bc.getNodesByRole(t, true, native.RoleOracle, index, 1) // returns pubs + bc.getNodesByRole(t, false, noderoles.Oracle, 100500, 0) + bc.getNodesByRole(t, true, noderoles.Oracle, 0, 0) // returns an empty list + bc.getNodesByRole(t, true, noderoles.Oracle, index, 1) // returns pubs priv1, err := keys.NewPrivateKey() require.NoError(t, err) pubs = keys.PublicKeys{priv1.PublicKey()} - bc.setNodesByRole(t, true, native.RoleStateValidator, pubs) - bc.getNodesByRole(t, true, native.RoleStateValidator, bc.BlockHeight()+1, 1) + bc.setNodesByRole(t, true, noderoles.StateValidator, pubs) + bc.getNodesByRole(t, true, noderoles.StateValidator, bc.BlockHeight()+1, 1) t.Run("neofs", func(t *testing.T) { priv, err := keys.NewPrivateKey() require.NoError(t, err) pubs = keys.PublicKeys{priv.PublicKey()} - bc.setNodesByRole(t, true, native.RoleNeoFSAlphabet, pubs) - bc.getNodesByRole(t, true, native.RoleNeoFSAlphabet, bc.BlockHeight()+1, 1) + bc.setNodesByRole(t, true, noderoles.NeoFSAlphabet, pubs) + bc.getNodesByRole(t, true, noderoles.NeoFSAlphabet, bc.BlockHeight()+1, 1) }) } @@ -123,15 +124,15 @@ func TestDesignate_DesignateAsRole(t *testing.T) { pubs, index, err := des.GetDesignatedByRole(bc.dao, 0xFF, 255) require.True(t, errors.Is(err, native.ErrInvalidRole), "got: %v", err) - pubs, index, err = des.GetDesignatedByRole(bc.dao, native.RoleOracle, 255) + pubs, index, err = des.GetDesignatedByRole(bc.dao, noderoles.Oracle, 255) require.NoError(t, err) require.Equal(t, 0, len(pubs)) require.Equal(t, uint32(0), index) - err = des.DesignateAsRole(ic, native.RoleOracle, keys.PublicKeys{}) + err = des.DesignateAsRole(ic, noderoles.Oracle, keys.PublicKeys{}) require.True(t, errors.Is(err, native.ErrEmptyNodeList), "got: %v", err) - err = des.DesignateAsRole(ic, native.RoleOracle, make(keys.PublicKeys, 32+1)) + err = des.DesignateAsRole(ic, noderoles.Oracle, make(keys.PublicKeys, 32+1)) require.True(t, errors.Is(err, native.ErrLargeNodeList), "got: %v", err) priv, err := keys.NewPrivateKey() @@ -141,19 +142,19 @@ func TestDesignate_DesignateAsRole(t *testing.T) { err = des.DesignateAsRole(ic, 0xFF, keys.PublicKeys{pub}) require.True(t, errors.Is(err, native.ErrInvalidRole), "got: %v", err) - err = des.DesignateAsRole(ic, native.RoleOracle, keys.PublicKeys{pub}) + err = des.DesignateAsRole(ic, noderoles.Oracle, keys.PublicKeys{pub}) require.True(t, errors.Is(err, native.ErrInvalidWitness), "got: %v", err) setSigner(tx, testchain.CommitteeScriptHash()) - err = des.DesignateAsRole(ic, native.RoleOracle, keys.PublicKeys{pub}) + err = des.DesignateAsRole(ic, noderoles.Oracle, keys.PublicKeys{pub}) require.NoError(t, err) - pubs, index, err = des.GetDesignatedByRole(ic.DAO, native.RoleOracle, bl.Index+1) + pubs, index, err = des.GetDesignatedByRole(ic.DAO, noderoles.Oracle, bl.Index+1) require.NoError(t, err) require.Equal(t, keys.PublicKeys{pub}, pubs) require.Equal(t, bl.Index+1, index) - pubs, index, err = des.GetDesignatedByRole(ic.DAO, native.RoleStateValidator, 255) + pubs, index, err = des.GetDesignatedByRole(ic.DAO, noderoles.StateValidator, 255) require.NoError(t, err) require.Equal(t, 0, len(pubs)) require.Equal(t, uint32(0), index) @@ -162,29 +163,29 @@ func TestDesignate_DesignateAsRole(t *testing.T) { _, err = keys.NewPrivateKey() require.NoError(t, err) pub1 := priv.PublicKey() - err = des.DesignateAsRole(ic, native.RoleStateValidator, keys.PublicKeys{pub1}) + err = des.DesignateAsRole(ic, noderoles.StateValidator, keys.PublicKeys{pub1}) require.NoError(t, err) - pubs, index, err = des.GetDesignatedByRole(ic.DAO, native.RoleOracle, 255) + pubs, index, err = des.GetDesignatedByRole(ic.DAO, noderoles.Oracle, 255) require.NoError(t, err) require.Equal(t, keys.PublicKeys{pub}, pubs) require.Equal(t, bl.Index+1, index) - pubs, index, err = des.GetDesignatedByRole(ic.DAO, native.RoleStateValidator, 255) + pubs, index, err = des.GetDesignatedByRole(ic.DAO, noderoles.StateValidator, 255) require.NoError(t, err) require.Equal(t, keys.PublicKeys{pub1}, pubs) require.Equal(t, bl.Index+1, index) // Set P2PNotary role. - pubs, index, err = des.GetDesignatedByRole(ic.DAO, native.RoleP2PNotary, 255) + pubs, index, err = des.GetDesignatedByRole(ic.DAO, noderoles.P2PNotary, 255) require.NoError(t, err) require.Equal(t, 0, len(pubs)) require.Equal(t, uint32(0), index) - err = des.DesignateAsRole(ic, native.RoleP2PNotary, keys.PublicKeys{pub1}) + err = des.DesignateAsRole(ic, noderoles.P2PNotary, keys.PublicKeys{pub1}) require.NoError(t, err) - pubs, index, err = des.GetDesignatedByRole(ic.DAO, native.RoleP2PNotary, 255) + pubs, index, err = des.GetDesignatedByRole(ic.DAO, noderoles.P2PNotary, 255) require.NoError(t, err) require.Equal(t, keys.PublicKeys{pub1}, pubs) require.Equal(t, bl.Index+1, index) diff --git a/pkg/core/native_notary_test.go b/pkg/core/native_notary_test.go index 85ab22a8d..fc1294272 100644 --- a/pkg/core/native_notary_test.go +++ b/pkg/core/native_notary_test.go @@ -5,7 +5,7 @@ import ( "testing" "github.com/nspcc-dev/neo-go/internal/testchain" - "github.com/nspcc-dev/neo-go/pkg/core/native" + "github.com/nspcc-dev/neo-go/pkg/core/native/noderoles" "github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/io" @@ -261,7 +261,7 @@ func TestNotaryNodesReward(t *testing.T) { require.NoError(t, err) notaryNodesPublicKeys[i] = notaryNodes[i].PublicKey() } - chain.setNodesByRole(t, true, native.RoleP2PNotary, notaryNodesPublicKeys) + chain.setNodesByRole(t, true, noderoles.P2PNotary, notaryNodesPublicKeys) for _, notaryNode := range notaryNodesPublicKeys { checkBalanceOf(t, chain, notaryNode.GetScriptHash(), 0) } diff --git a/pkg/core/native_oracle_test.go b/pkg/core/native_oracle_test.go index 12591014c..f1191278d 100644 --- a/pkg/core/native_oracle_test.go +++ b/pkg/core/native_oracle_test.go @@ -11,6 +11,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/core/block" "github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames" "github.com/nspcc-dev/neo-go/pkg/core/native" + "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/core/transaction" "github.com/nspcc-dev/neo-go/pkg/crypto/hash" @@ -154,7 +155,7 @@ func TestOracle_Request(t *testing.T) { ic := bc.newInteropContext(trigger.Application, bc.dao, bl, tx) ic.SpawnVM() ic.VM.LoadScript([]byte{byte(opcode.RET)}) - err = bc.contracts.Designate.DesignateAsRole(ic, native.RoleOracle, keys.PublicKeys{pub}) + err = bc.contracts.Designate.DesignateAsRole(ic, noderoles.Oracle, keys.PublicKeys{pub}) require.NoError(t, err) tx = transaction.New(netmode.UnitTestNet, orc.GetOracleResponseScript(), 0) diff --git a/pkg/core/notary_test.go b/pkg/core/notary_test.go index 2f18333b6..c3ee363f0 100644 --- a/pkg/core/notary_test.go +++ b/pkg/core/notary_test.go @@ -16,7 +16,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/core/block" "github.com/nspcc-dev/neo-go/pkg/core/blockchainer" "github.com/nspcc-dev/neo-go/pkg/core/mempool" - "github.com/nspcc-dev/neo-go/pkg/core/native" + "github.com/nspcc-dev/neo-go/pkg/core/native/noderoles" "github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/crypto/hash" "github.com/nspcc-dev/neo-go/pkg/crypto/keys" @@ -104,7 +104,7 @@ func TestNotary(t *testing.T) { }) notaryNodes := keys.PublicKeys{acc1.PrivateKey().PublicKey(), acc2.PrivateKey().PublicKey()} - bc.setNodesByRole(t, true, native.RoleP2PNotary, notaryNodes) + bc.setNodesByRole(t, true, noderoles.P2PNotary, notaryNodes) createFallbackTx := func(requester *wallet.Account, mainTx *transaction.Transaction, nvbIncrement ...uint32) *transaction.Transaction { fallback := transaction.New(testchain.Network(), []byte{byte(opcode.RET)}, 2000_0000) diff --git a/pkg/core/oracle_test.go b/pkg/core/oracle_test.go index 2ebda6109..81fa264a5 100644 --- a/pkg/core/oracle_test.go +++ b/pkg/core/oracle_test.go @@ -14,7 +14,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/config" "github.com/nspcc-dev/neo-go/pkg/config/netmode" - "github.com/nspcc-dev/neo-go/pkg/core/native" + "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/core/transaction" "github.com/nspcc-dev/neo-go/pkg/crypto/keys" @@ -120,7 +120,7 @@ func TestOracle(t *testing.T) { acc2, orc2, m2, ch2 := getTestOracle(t, bc, "./testdata/oracle2.json", "two") oracleNodes := keys.PublicKeys{acc1.PrivateKey().PublicKey(), acc2.PrivateKey().PublicKey()} // Must be set in native contract for tx verification. - bc.setNodesByRole(t, true, native.RoleOracle, oracleNodes) + bc.setNodesByRole(t, true, noderoles.Oracle, oracleNodes) orc1.UpdateOracleNodes(oracleNodes.Copy()) orc2.UpdateOracleNodes(oracleNodes.Copy()) @@ -278,7 +278,7 @@ func TestOracleFull(t *testing.T) { go orc.Run() t.Cleanup(orc.Shutdown) - bc.setNodesByRole(t, true, native.RoleOracle, keys.PublicKeys{acc.PrivateKey().PublicKey()}) + bc.setNodesByRole(t, true, noderoles.Oracle, keys.PublicKeys{acc.PrivateKey().PublicKey()}) putOracleRequest(t, cs.Hash, bc, "http://get.1234", new(string), "handle", []byte{}, 10_000_000) require.Eventually(t, func() bool { return mp.Count() == 1 }, diff --git a/pkg/core/stateroot_test.go b/pkg/core/stateroot_test.go index 9b9d2e0b6..dc9632081 100644 --- a/pkg/core/stateroot_test.go +++ b/pkg/core/stateroot_test.go @@ -10,7 +10,7 @@ import ( "github.com/nspcc-dev/neo-go/internal/testserdes" "github.com/nspcc-dev/neo-go/pkg/config" - "github.com/nspcc-dev/neo-go/pkg/core/native" + "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/core/storage" "github.com/nspcc-dev/neo-go/pkg/core/transaction" @@ -73,7 +73,7 @@ func TestStateRoot(t *testing.T) { bc := newTestChain(t) h, pubs, accs := newMajorityMultisigWithGAS(t, 2) - bc.setNodesByRole(t, true, native.RoleStateValidator, pubs) + bc.setNodesByRole(t, true, noderoles.StateValidator, pubs) updateIndex := bc.BlockHeight() transferTokenFromMultisigAccount(t, bc, h, bc.contracts.GAS.Hash, 1_0000_0000) @@ -142,7 +142,7 @@ func TestStateRootInitNonZeroHeight(t *testing.T) { var root util.Uint256 t.Run("init", func(t *testing.T) { // this is in a separate test to do proper cleanup bc := newTestChainWithCustomCfgAndStore(t, st, nil) - bc.setNodesByRole(t, true, native.RoleStateValidator, pubs) + bc.setNodesByRole(t, true, noderoles.StateValidator, pubs) transferTokenFromMultisigAccount(t, bc, h, bc.contracts.GAS.Hash, 1_0000_0000) _, err := persistBlock(bc) @@ -210,7 +210,7 @@ func TestStateRootFull(t *testing.T) { lastValidated.Store(ep) }) - bc.setNodesByRole(t, true, native.RoleStateValidator, pubs) + bc.setNodesByRole(t, true, noderoles.StateValidator, pubs) transferTokenFromMultisigAccount(t, bc, h, bc.contracts.GAS.Hash, 1_0000_0000) require.Eventually(t, func() bool { return lastHeight.Load() == 2 }, time.Second, time.Millisecond) checkVoteBroadcasted(t, bc, lastValidated.Load().(*payload.Extensible), 2, 1) @@ -247,7 +247,7 @@ func checkVoteBroadcasted(t *testing.T, bc *Blockchain, p *payload.Extensible, require.Equal(t, height, vote.Height) require.Equal(t, int32(valIndex), vote.ValidatorIndex) - pubs, _, err := bc.contracts.Designate.GetDesignatedByRole(bc.dao, native.RoleStateValidator, bc.BlockHeight()) + pubs, _, err := bc.contracts.Designate.GetDesignatedByRole(bc.dao, noderoles.StateValidator, bc.BlockHeight()) require.True(t, len(pubs) > int(valIndex)) require.True(t, pubs[valIndex].Verify(vote.Signature, r.GetSignedHash().BytesBE())) } From 1e649bc9a0f0e5f335cc71d0757015588fad19e1 Mon Sep 17 00:00:00 2001 From: Anna Shaleva Date: Tue, 23 Mar 2021 13:49:27 +0300 Subject: [PATCH 2/3] core: move NotaryVerificationPrice to a separate package It is needed to avoid `native` dependency in RPC client. --- pkg/core/blockchain_test.go | 3 ++- pkg/core/native/nativeprices/prices.go | 4 ++++ pkg/core/native/notary.go | 6 ++---- pkg/rpc/client/rpc.go | 4 ++-- 4 files changed, 10 insertions(+), 7 deletions(-) create mode 100644 pkg/core/native/nativeprices/prices.go diff --git a/pkg/core/blockchain_test.go b/pkg/core/blockchain_test.go index 132d763a2..f5d77bfcf 100644 --- a/pkg/core/blockchain_test.go +++ b/pkg/core/blockchain_test.go @@ -21,6 +21,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames" "github.com/nspcc-dev/neo-go/pkg/core/mempool" "github.com/nspcc-dev/neo-go/pkg/core/native" + "github.com/nspcc-dev/neo-go/pkg/core/native/nativeprices" "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/core/storage" @@ -1031,7 +1032,7 @@ func TestVerifyTx(t *testing.T) { fee.Opcode(bc.GetBaseExecFee(), // Notary verification script opcode.PUSHDATA1, opcode.RET, // invocation script opcode.PUSH0, opcode.SYSCALL, opcode.RET) + // Neo.Native.Call - native.NotaryVerificationPrice*bc.GetBaseExecFee() // Notary witness verification price + nativeprices.NotaryVerificationPrice*bc.GetBaseExecFee() // Notary witness verification price tx.Scripts = []transaction.Witness{ { InvocationScript: append([]byte{byte(opcode.PUSHDATA1), 64}, make([]byte, 64, 64)...), diff --git a/pkg/core/native/nativeprices/prices.go b/pkg/core/native/nativeprices/prices.go new file mode 100644 index 000000000..a722c5239 --- /dev/null +++ b/pkg/core/native/nativeprices/prices.go @@ -0,0 +1,4 @@ +package nativeprices + +// NotaryVerificationPrice is the price of `verify` native Notary method. +const NotaryVerificationPrice = 1 << 15 diff --git a/pkg/core/native/notary.go b/pkg/core/native/notary.go index 70ae4468d..34beafc4d 100644 --- a/pkg/core/native/notary.go +++ b/pkg/core/native/notary.go @@ -12,6 +12,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/core/interop/contract" "github.com/nspcc-dev/neo-go/pkg/core/interop/runtime" "github.com/nspcc-dev/neo-go/pkg/core/native/nativenames" + "github.com/nspcc-dev/neo-go/pkg/core/native/nativeprices" "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/core/storage" @@ -41,9 +42,6 @@ type Notary struct { const ( notaryContractID = reservedContractID - 1 - // NotaryVerificationPrice is the price of `verify` Notary method. - NotaryVerificationPrice = 1 << 15 - // prefixDeposit is a prefix for storing Notary deposits. prefixDeposit = 1 defaultDepositDeltaTill = 5760 @@ -88,7 +86,7 @@ func newNotary() *Notary { desc = newDescriptor("verify", smartcontract.BoolType, manifest.NewParameter("signature", smartcontract.SignatureType)) - md = newMethodAndPrice(n.verify, NotaryVerificationPrice, callflag.ReadStates) + md = newMethodAndPrice(n.verify, nativeprices.NotaryVerificationPrice, callflag.ReadStates) n.AddMethod(md, desc) desc = newDescriptor("getMaxNotValidBeforeDelta", smartcontract.IntegerType) diff --git a/pkg/rpc/client/rpc.go b/pkg/rpc/client/rpc.go index a70a10242..dcec9177c 100644 --- a/pkg/rpc/client/rpc.go +++ b/pkg/rpc/client/rpc.go @@ -8,8 +8,8 @@ import ( "github.com/nspcc-dev/neo-go/pkg/config/netmode" "github.com/nspcc-dev/neo-go/pkg/core/block" "github.com/nspcc-dev/neo-go/pkg/core/fee" - "github.com/nspcc-dev/neo-go/pkg/core/native" "github.com/nspcc-dev/neo-go/pkg/core/native/nativenames" + "github.com/nspcc-dev/neo-go/pkg/core/native/nativeprices" "github.com/nspcc-dev/neo-go/pkg/core/state" "github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/crypto/keys" @@ -693,7 +693,7 @@ func (c *Client) CalculateNotaryFee(nKeys uint8) (int64, error) { fee.Opcode(baseExecFee, // Notary node witness opcode.PUSHDATA1, opcode.RET, // invocation script opcode.PUSH0, opcode.SYSCALL, opcode.RET) + // System.Contract.CallNative - native.NotaryVerificationPrice*baseExecFee + // Notary witness verification price + nativeprices.NotaryVerificationPrice*baseExecFee + // Notary witness verification price feePerByte*int64(io.GetVarSize(make([]byte, 66))) + // invocation script per-byte fee feePerByte*int64(io.GetVarSize([]byte{})), // verification script per-byte fee nil From 10fb86c0b2af7b39ac36f4be40aae910e005c60b Mon Sep 17 00:00:00 2001 From: Anna Shaleva Date: Mon, 22 Mar 2021 20:34:27 +0300 Subject: [PATCH 3/3] rpc: add (*Client).GetDesignatedByRole method --- pkg/rpc/client/native.go | 56 ++++++++++++++++++++++++++++++++++++++ pkg/rpc/client/rpc_test.go | 24 ++++++++++++++++ 2 files changed, 80 insertions(+) diff --git a/pkg/rpc/client/native.go b/pkg/rpc/client/native.go index e1a20dcb5..883910354 100644 --- a/pkg/rpc/client/native.go +++ b/pkg/rpc/client/native.go @@ -3,9 +3,14 @@ package client // Various non-policy things from native contracts. import ( + "crypto/elliptic" "fmt" "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/crypto/keys" + "github.com/nspcc-dev/neo-go/pkg/smartcontract" + "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" ) // GetOraclePrice invokes `getPrice` method on a native Oracle contract. @@ -34,3 +39,54 @@ func (c *Client) GetGasPerBlock() (int64, error) { } return c.invokeNativeGetMethod(neoHash, "getGasPerBlock") } + +// GetDesignatedByRole invokes `getDesignatedByRole` method on a native RoleManagement contract. +func (c *Client) GetDesignatedByRole(role noderoles.Role, index uint32) (keys.PublicKeys, error) { + rmHash, err := c.GetNativeContractHash(nativenames.Designation) + if err != nil { + return nil, fmt.Errorf("failed to get native RoleManagement hash: %w", err) + } + result, err := c.InvokeFunction(rmHash, "getDesignatedByRole", []smartcontract.Parameter{ + { + Type: smartcontract.IntegerType, + Value: int64(role), + }, + { + Type: smartcontract.IntegerType, + Value: int64(index), + }, + }, nil) + if err != nil { + return nil, err + } + err = getInvocationError(result) + if err != nil { + return nil, fmt.Errorf("`getDesignatedByRole`: %w", err) + } + return topPublicKeysFromStack(result.Stack) +} + +// topPublicKeysFromStack returns the top array of public keys from stack. +func topPublicKeysFromStack(st []stackitem.Item) (keys.PublicKeys, error) { + index := len(st) - 1 // top stack element is last in the array + var ( + pks keys.PublicKeys + err error + ) + items, ok := st[index].Value().([]stackitem.Item) + if !ok { + return nil, fmt.Errorf("invalid stack item type: %s", st[index].Type()) + } + pks = make(keys.PublicKeys, len(items)) + for i, item := range items { + val, ok := item.Value().([]byte) + if !ok { + return nil, fmt.Errorf("invalid array element #%d: %s", i, item.Type()) + } + pks[i], err = keys.NewPublicKeyFromBytes(val, elliptic.P256()) + if err != nil { + return nil, err + } + } + return pks, nil +} diff --git a/pkg/rpc/client/rpc_test.go b/pkg/rpc/client/rpc_test.go index 68657bce4..7f48ea0b6 100644 --- a/pkg/rpc/client/rpc_test.go +++ b/pkg/rpc/client/rpc_test.go @@ -2,6 +2,7 @@ package client import ( "context" + "crypto/elliptic" "encoding/base64" "encoding/hex" "encoding/json" @@ -17,6 +18,7 @@ import ( "github.com/nspcc-dev/neo-go/internal/testserdes" "github.com/nspcc-dev/neo-go/pkg/config/netmode" "github.com/nspcc-dev/neo-go/pkg/core/block" + "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/core/transaction" "github.com/nspcc-dev/neo-go/pkg/crypto/hash" @@ -476,6 +478,28 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{ }, }, }, + "getDesignatedByRole": { + { + name: "positive", + invoke: func(c *Client) (interface{}, error) { + return c.GetDesignatedByRole(noderoles.P2PNotary, 10) + }, + serverResponse: `{"id" : 1,"result" : {"stack" : [{"value" : [{"type":"ByteString","value":"Aw0WkQoDc8WqpG18xPMTEgfHO6gRTVtMN0Mw6zw06fzl"},{"type":"ByteString","value":"A+bmJ9wIaj96Ygr+uQQvQ0AaUrQmj2b3AGnztAOkU3/L"}],"type" : "Array"}],"exception" : null,"script" : "ERQSwB8ME2dldERlc2lnbmF0ZWRCeVJvbGUMFOKV45FUTBeK2U8D7E3N/3hTTs9JQWJ9W1I=","gasconsumed" : "2028150","state" : "HALT"}, "jsonrpc" : "2.0"}`, + result: func(c *Client) interface{} { + pk1Bytes, _ := base64.StdEncoding.DecodeString("Aw0WkQoDc8WqpG18xPMTEgfHO6gRTVtMN0Mw6zw06fzl") + pk1, err := keys.NewPublicKeyFromBytes(pk1Bytes, elliptic.P256()) + if err != nil { + panic("invalid pub key #1 bytes") + } + pk2Bytes, _ := base64.StdEncoding.DecodeString("A+bmJ9wIaj96Ygr+uQQvQ0AaUrQmj2b3AGnztAOkU3/L") + pk2, err := keys.NewPublicKeyFromBytes(pk2Bytes, elliptic.P256()) + if err != nil { + panic("invalid pub key #2 bytes") + } + return keys.PublicKeys{pk1, pk2} + }, + }, + }, "getMaxNotValidBeforeDelta": { { name: "positive",