Merge pull request #1855 from nspcc-dev/rpc/getDesignatedByRole

rpc: add (*Client).GetDesignatedByRole method
This commit is contained in:
Roman Khimov 2021-03-23 14:43:57 +03:00 committed by GitHub
commit 57c3ecd135
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 184 additions and 91 deletions

View file

@ -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) {

View file

@ -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
}

View file

@ -21,6 +21,8 @@ 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"
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
@ -596,7 +598,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 +809,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 {
@ -1030,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)...),

View file

@ -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.

View file

@ -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))
}

View file

@ -0,0 +1,4 @@
package nativeprices
// NotaryVerificationPrice is the price of `verify` native Notary method.
const NotaryVerificationPrice = 1 << 15

View file

@ -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
)

View file

@ -12,6 +12,8 @@ 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"
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
@ -40,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
@ -87,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)
@ -370,7 +369,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
}

View file

@ -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
}

View file

@ -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)

View file

@ -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)
}

View file

@ -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)

View file

@ -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)

View file

@ -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 },

View file

@ -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()))
}

View file

@ -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
}

View file

@ -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

View file

@ -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",