2020-10-01 15:17:09 +00:00
|
|
|
package native
|
|
|
|
|
|
|
|
import (
|
2020-11-05 16:34:48 +00:00
|
|
|
"encoding/binary"
|
2020-10-01 15:17:09 +00:00
|
|
|
"errors"
|
|
|
|
"math"
|
2021-04-29 11:12:48 +00:00
|
|
|
"math/big"
|
2020-10-01 15:17:09 +00:00
|
|
|
"sort"
|
|
|
|
"sync/atomic"
|
|
|
|
|
2020-09-28 11:58:04 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/blockchainer/services"
|
2020-10-01 15:17:09 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/dao"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/interop/runtime"
|
2020-12-13 18:25:04 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
|
2021-03-23 10:37:30 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/native/noderoles"
|
2020-10-01 15:17:09 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
2022-01-13 22:51:24 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/stateroot"
|
2022-03-31 15:14:11 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/storage"
|
2020-10-01 15:17:09 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
2020-12-29 10:45:49 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
|
2020-10-01 15:17:09 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
2020-11-05 16:34:48 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
2020-10-01 15:17:09 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Designate represents designation contract.
|
|
|
|
type Designate struct {
|
|
|
|
interop.ContractMD
|
|
|
|
NEO *NEO
|
|
|
|
|
2020-11-18 08:59:34 +00:00
|
|
|
// p2pSigExtensionsEnabled defines whether the P2P signature extensions logic is relevant.
|
|
|
|
p2pSigExtensionsEnabled bool
|
2020-09-28 11:58:04 +00:00
|
|
|
|
|
|
|
OracleService atomic.Value
|
2020-12-30 08:01:13 +00:00
|
|
|
// NotaryService represents Notary node module.
|
|
|
|
NotaryService atomic.Value
|
2021-02-01 16:00:07 +00:00
|
|
|
// StateRootService represents StateRoot node module.
|
2022-01-13 22:51:24 +00:00
|
|
|
StateRootService *stateroot.Module
|
2020-11-05 16:34:48 +00:00
|
|
|
}
|
|
|
|
|
2021-01-15 11:05:30 +00:00
|
|
|
type roleData struct {
|
2020-11-05 16:34:48 +00:00
|
|
|
nodes keys.PublicKeys
|
|
|
|
addr util.Uint160
|
|
|
|
height uint32
|
2020-10-01 15:17:09 +00:00
|
|
|
}
|
|
|
|
|
2022-04-12 14:29:11 +00:00
|
|
|
type DesignationCache struct {
|
2022-04-19 09:26:46 +00:00
|
|
|
rolesChangedFlag bool
|
|
|
|
oracles roleData
|
|
|
|
stateVals roleData
|
|
|
|
neofsAlphabet roleData
|
|
|
|
notaries roleData
|
2022-04-12 14:29:11 +00:00
|
|
|
}
|
|
|
|
|
2020-10-01 15:17:09 +00:00
|
|
|
const (
|
2021-02-15 15:43:10 +00:00
|
|
|
designateContractID = -8
|
2020-10-21 09:50:26 +00:00
|
|
|
|
|
|
|
// maxNodeCount is the maximum number of nodes to set the role for.
|
|
|
|
maxNodeCount = 32
|
2021-04-29 11:12:48 +00:00
|
|
|
|
|
|
|
// DesignationEventName is the name of a designation event.
|
|
|
|
DesignationEventName = "Designation"
|
2020-10-01 15:17:09 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// Various errors.
|
|
|
|
var (
|
2020-11-05 16:34:48 +00:00
|
|
|
ErrAlreadyDesignated = errors.New("already designated given role at current block")
|
|
|
|
ErrEmptyNodeList = errors.New("node list is empty")
|
|
|
|
ErrInvalidIndex = errors.New("invalid index")
|
|
|
|
ErrInvalidRole = errors.New("invalid role")
|
|
|
|
ErrLargeNodeList = errors.New("node list is too large")
|
|
|
|
ErrNoBlock = errors.New("no persisting block in the context")
|
2020-10-01 15:17:09 +00:00
|
|
|
)
|
|
|
|
|
2022-04-15 14:48:58 +00:00
|
|
|
var (
|
|
|
|
_ interop.Contract = (*Designate)(nil)
|
|
|
|
_ storage.NativeContractCache = (*DesignationCache)(nil)
|
|
|
|
)
|
|
|
|
|
|
|
|
// Copy implements NativeContractCache interface.
|
|
|
|
func (c *DesignationCache) Copy() storage.NativeContractCache {
|
|
|
|
cp := &DesignationCache{}
|
|
|
|
copyDesignationCache(c, cp)
|
|
|
|
return cp
|
|
|
|
}
|
|
|
|
|
|
|
|
// Persist implements NativeContractCache interface.
|
|
|
|
func (c *DesignationCache) Persist(ps storage.NativeContractCache) (storage.NativeContractCache, error) {
|
|
|
|
if ps == nil {
|
|
|
|
ps = &DesignationCache{}
|
|
|
|
}
|
|
|
|
psCache, ok := ps.(*DesignationCache)
|
|
|
|
if !ok {
|
|
|
|
return nil, errors.New("not a Designation native cache")
|
|
|
|
}
|
|
|
|
copyDesignationCache(c, psCache)
|
|
|
|
return psCache, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func copyDesignationCache(src, dst *DesignationCache) {
|
2022-04-19 09:26:46 +00:00
|
|
|
*dst = *src
|
2022-04-15 14:48:58 +00:00
|
|
|
}
|
|
|
|
|
2021-03-23 10:37:30 +00:00
|
|
|
func (s *Designate) isValidRole(r noderoles.Role) bool {
|
|
|
|
return r == noderoles.Oracle || r == noderoles.StateValidator ||
|
|
|
|
r == noderoles.NeoFSAlphabet || (s.p2pSigExtensionsEnabled && r == noderoles.P2PNotary)
|
2020-10-01 15:17:09 +00:00
|
|
|
}
|
|
|
|
|
2020-11-18 08:59:34 +00:00
|
|
|
func newDesignate(p2pSigExtensionsEnabled bool) *Designate {
|
2021-01-15 21:17:31 +00:00
|
|
|
s := &Designate{ContractMD: *interop.NewContractMD(nativenames.Designation, designateContractID)}
|
2020-11-18 08:59:34 +00:00
|
|
|
s.p2pSigExtensionsEnabled = p2pSigExtensionsEnabled
|
2021-02-15 13:40:44 +00:00
|
|
|
defer s.UpdateHash()
|
2020-10-01 15:17:09 +00:00
|
|
|
|
|
|
|
desc := newDescriptor("getDesignatedByRole", smartcontract.ArrayType,
|
2020-11-05 16:34:48 +00:00
|
|
|
manifest.NewParameter("role", smartcontract.IntegerType),
|
|
|
|
manifest.NewParameter("index", smartcontract.IntegerType))
|
2021-03-05 10:30:16 +00:00
|
|
|
md := newMethodAndPrice(s.getDesignatedByRole, 1<<15, callflag.ReadStates)
|
2020-12-08 10:27:41 +00:00
|
|
|
s.AddMethod(md, desc)
|
2020-10-01 15:17:09 +00:00
|
|
|
|
|
|
|
desc = newDescriptor("designateAsRole", smartcontract.VoidType,
|
|
|
|
manifest.NewParameter("role", smartcontract.IntegerType),
|
|
|
|
manifest.NewParameter("nodes", smartcontract.ArrayType))
|
2021-04-29 11:12:48 +00:00
|
|
|
md = newMethodAndPrice(s.designateAsRole, 1<<15, callflag.States|callflag.AllowNotify)
|
2020-12-08 10:27:41 +00:00
|
|
|
s.AddMethod(md, desc)
|
2020-10-01 15:17:09 +00:00
|
|
|
|
2021-04-29 11:12:48 +00:00
|
|
|
s.AddEvent(DesignationEventName,
|
|
|
|
manifest.NewParameter("Role", smartcontract.IntegerType),
|
|
|
|
manifest.NewParameter("BlockIndex", smartcontract.IntegerType))
|
|
|
|
|
2020-10-01 15:17:09 +00:00
|
|
|
return s
|
|
|
|
}
|
|
|
|
|
|
|
|
// Initialize initializes Oracle contract.
|
|
|
|
func (s *Designate) Initialize(ic *interop.Context) error {
|
2022-04-12 14:29:11 +00:00
|
|
|
cache := &DesignationCache{}
|
2022-04-19 09:26:46 +00:00
|
|
|
cache.rolesChangedFlag = true
|
2022-04-12 14:29:11 +00:00
|
|
|
ic.DAO.Store.SetCache(s.ID, cache)
|
2020-10-01 15:17:09 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-12-13 18:36:06 +00:00
|
|
|
// OnPersist implements Contract interface.
|
|
|
|
func (s *Designate) OnPersist(ic *interop.Context) error {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// PostPersist implements Contract interface.
|
|
|
|
func (s *Designate) PostPersist(ic *interop.Context) error {
|
2022-04-15 14:48:58 +00:00
|
|
|
cache := ic.DAO.Store.GetRWCache(s.ID).(*DesignationCache)
|
2022-04-12 14:29:11 +00:00
|
|
|
if !rolesChanged(cache) {
|
2020-10-01 15:17:09 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-04-12 14:29:11 +00:00
|
|
|
if err := s.updateCachedRoleData(&cache.oracles, ic.DAO, noderoles.Oracle); err != nil {
|
2020-10-01 15:17:09 +00:00
|
|
|
return err
|
|
|
|
}
|
2022-04-12 14:29:11 +00:00
|
|
|
if err := s.updateCachedRoleData(&cache.stateVals, ic.DAO, noderoles.StateValidator); err != nil {
|
2021-01-15 11:05:30 +00:00
|
|
|
return err
|
2020-11-05 16:34:48 +00:00
|
|
|
}
|
2022-04-12 14:29:11 +00:00
|
|
|
if err := s.updateCachedRoleData(&cache.neofsAlphabet, ic.DAO, noderoles.NeoFSAlphabet); err != nil {
|
2021-03-05 10:13:31 +00:00
|
|
|
return err
|
|
|
|
}
|
2021-01-15 11:05:30 +00:00
|
|
|
if s.p2pSigExtensionsEnabled {
|
2022-04-12 14:29:11 +00:00
|
|
|
if err := s.updateCachedRoleData(&cache.notaries, ic.DAO, noderoles.P2PNotary); err != nil {
|
2021-01-15 11:05:30 +00:00
|
|
|
return err
|
|
|
|
}
|
2020-09-28 11:58:04 +00:00
|
|
|
}
|
2021-01-15 11:05:30 +00:00
|
|
|
|
2022-04-19 09:26:46 +00:00
|
|
|
cache.rolesChangedFlag = false
|
2020-10-01 15:17:09 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Metadata returns contract metadata.
|
|
|
|
func (s *Designate) Metadata() *interop.ContractMD {
|
|
|
|
return &s.ContractMD
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Designate) getDesignatedByRole(ic *interop.Context, args []stackitem.Item) stackitem.Item {
|
2020-11-18 08:59:34 +00:00
|
|
|
r, ok := s.getRole(args[0])
|
2020-10-01 15:17:09 +00:00
|
|
|
if !ok {
|
|
|
|
panic(ErrInvalidRole)
|
|
|
|
}
|
2020-11-05 16:34:48 +00:00
|
|
|
ind, err := args[1].TryInteger()
|
|
|
|
if err != nil || !ind.IsUint64() {
|
|
|
|
panic(ErrInvalidIndex)
|
|
|
|
}
|
|
|
|
index := ind.Uint64()
|
|
|
|
if index > uint64(ic.Chain.BlockHeight()+1) {
|
|
|
|
panic(ErrInvalidIndex)
|
|
|
|
}
|
|
|
|
pubs, _, err := s.GetDesignatedByRole(ic.DAO, r, uint32(index))
|
2020-10-01 15:17:09 +00:00
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
return pubsToArray(pubs)
|
|
|
|
}
|
|
|
|
|
2022-04-12 14:29:11 +00:00
|
|
|
func rolesChanged(cache *DesignationCache) bool {
|
2022-04-19 09:26:46 +00:00
|
|
|
return cache.rolesChangedFlag
|
2020-10-01 15:17:09 +00:00
|
|
|
}
|
|
|
|
|
2021-03-23 10:37:30 +00:00
|
|
|
func (s *Designate) hashFromNodes(r noderoles.Role, nodes keys.PublicKeys) util.Uint160 {
|
2020-11-05 16:34:48 +00:00
|
|
|
if len(nodes) == 0 {
|
|
|
|
return util.Uint160{}
|
|
|
|
}
|
2021-01-25 07:37:59 +00:00
|
|
|
var script []byte
|
|
|
|
switch r {
|
2021-03-23 10:37:30 +00:00
|
|
|
case noderoles.P2PNotary:
|
2021-01-25 07:37:59 +00:00
|
|
|
script, _ = smartcontract.CreateMultiSigRedeemScript(1, nodes.Copy())
|
|
|
|
default:
|
2021-02-01 16:00:07 +00:00
|
|
|
script, _ = smartcontract.CreateDefaultMultiSigRedeemScript(nodes.Copy())
|
2021-01-25 07:37:59 +00:00
|
|
|
}
|
2020-11-05 16:34:48 +00:00
|
|
|
return hash.Hash160(script)
|
|
|
|
}
|
|
|
|
|
2022-04-19 09:26:46 +00:00
|
|
|
func (s *Designate) updateCachedRoleData(v *roleData, d *dao.Simple, r noderoles.Role) error {
|
2021-01-15 11:05:30 +00:00
|
|
|
nodeKeys, height, err := s.GetDesignatedByRole(d, r, math.MaxUint32)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2022-04-19 09:26:46 +00:00
|
|
|
v.nodes = nodeKeys
|
|
|
|
v.addr = s.hashFromNodes(r, nodeKeys)
|
|
|
|
v.height = height
|
2020-12-30 08:01:13 +00:00
|
|
|
switch r {
|
2021-03-23 10:37:30 +00:00
|
|
|
case noderoles.Oracle:
|
2021-01-15 11:05:30 +00:00
|
|
|
if orc, _ := s.OracleService.Load().(services.Oracle); orc != nil {
|
|
|
|
orc.UpdateOracleNodes(nodeKeys.Copy())
|
|
|
|
}
|
2021-03-23 10:37:30 +00:00
|
|
|
case noderoles.P2PNotary:
|
2020-12-30 08:01:13 +00:00
|
|
|
if ntr, _ := s.NotaryService.Load().(services.Notary); ntr != nil {
|
|
|
|
ntr.UpdateNotaryNodes(nodeKeys.Copy())
|
|
|
|
}
|
2021-03-23 10:37:30 +00:00
|
|
|
case noderoles.StateValidator:
|
2021-02-01 16:00:07 +00:00
|
|
|
if s.StateRootService != nil {
|
|
|
|
s.StateRootService.UpdateStateValidators(height, nodeKeys.Copy())
|
|
|
|
}
|
2021-01-15 11:05:30 +00:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-04-12 14:29:11 +00:00
|
|
|
func getCachedRoleData(cache *DesignationCache, r noderoles.Role) *roleData {
|
2021-01-15 11:05:30 +00:00
|
|
|
switch r {
|
2021-03-23 10:37:30 +00:00
|
|
|
case noderoles.Oracle:
|
2022-04-19 09:26:46 +00:00
|
|
|
return &cache.oracles
|
2021-03-23 10:37:30 +00:00
|
|
|
case noderoles.StateValidator:
|
2022-04-19 09:26:46 +00:00
|
|
|
return &cache.stateVals
|
2021-03-23 10:37:30 +00:00
|
|
|
case noderoles.NeoFSAlphabet:
|
2022-04-19 09:26:46 +00:00
|
|
|
return &cache.neofsAlphabet
|
2021-03-23 10:37:30 +00:00
|
|
|
case noderoles.P2PNotary:
|
2022-04-19 09:26:46 +00:00
|
|
|
return &cache.notaries
|
2021-01-15 11:05:30 +00:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-01-18 12:52:51 +00:00
|
|
|
// GetLastDesignatedHash returns last designated hash of a given role.
|
2022-02-16 15:04:47 +00:00
|
|
|
func (s *Designate) GetLastDesignatedHash(d *dao.Simple, r noderoles.Role) (util.Uint160, error) {
|
2020-11-18 08:59:34 +00:00
|
|
|
if !s.isValidRole(r) {
|
2020-11-05 16:34:48 +00:00
|
|
|
return util.Uint160{}, ErrInvalidRole
|
|
|
|
}
|
2022-04-15 14:48:58 +00:00
|
|
|
cache := d.Store.GetROCache(s.ID).(*DesignationCache)
|
2022-04-12 14:29:11 +00:00
|
|
|
if !rolesChanged(cache) {
|
|
|
|
if val := getCachedRoleData(cache, r); val != nil {
|
2021-01-15 11:05:30 +00:00
|
|
|
return val.addr, nil
|
2020-11-05 16:34:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
nodes, _, err := s.GetDesignatedByRole(d, r, math.MaxUint32)
|
|
|
|
if err != nil {
|
|
|
|
return util.Uint160{}, err
|
|
|
|
}
|
|
|
|
// We only have hashing defined for oracles now.
|
2021-01-25 07:37:59 +00:00
|
|
|
return s.hashFromNodes(r, nodes), nil
|
2020-11-05 16:34:48 +00:00
|
|
|
}
|
|
|
|
|
2020-10-01 15:17:09 +00:00
|
|
|
// GetDesignatedByRole returns nodes for role r.
|
2022-02-16 15:04:47 +00:00
|
|
|
func (s *Designate) GetDesignatedByRole(d *dao.Simple, r noderoles.Role, index uint32) (keys.PublicKeys, uint32, error) {
|
2020-11-18 08:59:34 +00:00
|
|
|
if !s.isValidRole(r) {
|
2020-11-05 16:34:48 +00:00
|
|
|
return nil, 0, ErrInvalidRole
|
2020-10-01 15:17:09 +00:00
|
|
|
}
|
2022-04-15 14:48:58 +00:00
|
|
|
cache := d.Store.GetROCache(s.ID).(*DesignationCache)
|
2022-04-12 14:29:11 +00:00
|
|
|
if !rolesChanged(cache) {
|
|
|
|
if val := getCachedRoleData(cache, r); val != nil && val.height <= index {
|
2021-01-15 11:05:30 +00:00
|
|
|
return val.nodes.Copy(), val.height, nil
|
2020-11-05 16:34:48 +00:00
|
|
|
}
|
|
|
|
}
|
2021-09-24 14:22:45 +00:00
|
|
|
var (
|
|
|
|
ns NodeList
|
|
|
|
bestIndex uint32
|
2022-03-31 15:14:11 +00:00
|
|
|
resVal []byte
|
|
|
|
start = make([]byte, 4)
|
2021-09-24 14:22:45 +00:00
|
|
|
)
|
2022-03-31 15:14:11 +00:00
|
|
|
|
|
|
|
binary.BigEndian.PutUint32(start, index)
|
|
|
|
d.Seek(s.ID, storage.SeekRange{
|
|
|
|
Prefix: []byte{byte(r)},
|
|
|
|
Start: start,
|
|
|
|
Backwards: true,
|
|
|
|
}, func(k, v []byte) bool {
|
|
|
|
bestIndex = binary.BigEndian.Uint32(k) // If len(k) < 4 the DB is broken and it deserves a panic.
|
|
|
|
resVal = v
|
|
|
|
// Take just the latest item, it's the one we need.
|
|
|
|
return false
|
|
|
|
})
|
|
|
|
if resVal != nil {
|
|
|
|
err := stackitem.DeserializeConvertible(resVal, &ns)
|
2021-07-17 15:37:33 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, 0, err
|
2020-11-05 16:34:48 +00:00
|
|
|
}
|
|
|
|
}
|
2022-03-31 15:14:11 +00:00
|
|
|
return keys.PublicKeys(ns), bestIndex, nil
|
2020-10-01 15:17:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Designate) designateAsRole(ic *interop.Context, args []stackitem.Item) stackitem.Item {
|
2020-11-18 08:59:34 +00:00
|
|
|
r, ok := s.getRole(args[0])
|
2020-10-01 15:17:09 +00:00
|
|
|
if !ok {
|
|
|
|
panic(ErrInvalidRole)
|
|
|
|
}
|
|
|
|
var ns NodeList
|
2021-07-17 15:37:33 +00:00
|
|
|
if err := ns.FromStackItem(args[1]); err != nil {
|
2020-10-01 15:17:09 +00:00
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
err := s.DesignateAsRole(ic, r, keys.PublicKeys(ns))
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
2021-02-15 15:13:00 +00:00
|
|
|
return stackitem.Null{}
|
2020-10-01 15:17:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// DesignateAsRole sets nodes for role r.
|
2021-03-23 10:37:30 +00:00
|
|
|
func (s *Designate) DesignateAsRole(ic *interop.Context, r noderoles.Role, pubs keys.PublicKeys) error {
|
2020-10-21 09:50:26 +00:00
|
|
|
length := len(pubs)
|
|
|
|
if length == 0 {
|
2020-10-01 15:17:09 +00:00
|
|
|
return ErrEmptyNodeList
|
|
|
|
}
|
2020-10-21 09:50:26 +00:00
|
|
|
if length > maxNodeCount {
|
|
|
|
return ErrLargeNodeList
|
|
|
|
}
|
2020-11-18 08:59:34 +00:00
|
|
|
if !s.isValidRole(r) {
|
2020-10-01 15:17:09 +00:00
|
|
|
return ErrInvalidRole
|
|
|
|
}
|
2022-04-12 14:29:11 +00:00
|
|
|
h := s.NEO.GetCommitteeAddress(ic.DAO)
|
2020-10-01 15:17:09 +00:00
|
|
|
if ok, err := runtime.CheckHashedWitness(ic, h); err != nil || !ok {
|
|
|
|
return ErrInvalidWitness
|
|
|
|
}
|
2020-11-05 16:34:48 +00:00
|
|
|
if ic.Block == nil {
|
|
|
|
return ErrNoBlock
|
|
|
|
}
|
|
|
|
var key = make([]byte, 5)
|
|
|
|
key[0] = byte(r)
|
|
|
|
binary.BigEndian.PutUint32(key[1:], ic.Block.Index+1)
|
2020-10-01 15:17:09 +00:00
|
|
|
|
2021-02-09 09:26:25 +00:00
|
|
|
si := ic.DAO.GetStorageItem(s.ID, key)
|
2020-11-05 16:34:48 +00:00
|
|
|
if si != nil {
|
|
|
|
return ErrAlreadyDesignated
|
|
|
|
}
|
2020-10-01 15:17:09 +00:00
|
|
|
sort.Sort(pubs)
|
2021-07-17 15:37:33 +00:00
|
|
|
nl := NodeList(pubs)
|
2022-04-19 09:26:46 +00:00
|
|
|
ic.DAO.Store.GetRWCache(s.ID).(*DesignationCache).rolesChangedFlag = true
|
2021-07-17 15:37:33 +00:00
|
|
|
err := putConvertibleToDAO(s.ID, ic.DAO, key, &nl)
|
2021-04-29 11:12:48 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
ic.Notifications = append(ic.Notifications, state.NotificationEvent{
|
|
|
|
ScriptHash: s.Hash,
|
|
|
|
Name: DesignationEventName,
|
|
|
|
Item: stackitem.NewArray([]stackitem.Item{
|
|
|
|
stackitem.NewBigInteger(big.NewInt(int64(r))),
|
|
|
|
stackitem.NewBigInteger(big.NewInt(int64(ic.Block.Index))),
|
|
|
|
}),
|
|
|
|
})
|
|
|
|
return nil
|
2020-10-01 15:17:09 +00:00
|
|
|
}
|
|
|
|
|
2021-03-23 10:37:30 +00:00
|
|
|
func (s *Designate) getRole(item stackitem.Item) (noderoles.Role, bool) {
|
2020-10-01 15:17:09 +00:00
|
|
|
bi, err := item.TryInteger()
|
|
|
|
if err != nil {
|
|
|
|
return 0, false
|
|
|
|
}
|
|
|
|
if !bi.IsUint64() {
|
|
|
|
return 0, false
|
|
|
|
}
|
|
|
|
u := bi.Uint64()
|
2021-03-23 10:37:30 +00:00
|
|
|
return noderoles.Role(u), u <= math.MaxUint8 && s.isValidRole(noderoles.Role(u))
|
2020-10-01 15:17:09 +00:00
|
|
|
}
|
2021-07-30 13:57:42 +00:00
|
|
|
|
|
|
|
// InitializeCache invalidates native Designate cache.
|
2022-04-12 14:29:11 +00:00
|
|
|
func (s *Designate) InitializeCache(d *dao.Simple) {
|
|
|
|
cache := &DesignationCache{}
|
2022-04-19 09:26:46 +00:00
|
|
|
cache.rolesChangedFlag = true
|
2022-04-12 14:29:11 +00:00
|
|
|
d.Store.SetCache(s.ID, cache)
|
2021-07-30 13:57:42 +00:00
|
|
|
}
|