github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/pkg/core/native/native_neo.go (about)

     1  package native
     2  
     3  import (
     4  	"context"
     5  	"crypto/elliptic"
     6  	"encoding/binary"
     7  	"errors"
     8  	"fmt"
     9  	"math/big"
    10  	"sort"
    11  	"strings"
    12  
    13  	"github.com/nspcc-dev/neo-go/pkg/config"
    14  	"github.com/nspcc-dev/neo-go/pkg/core/dao"
    15  	"github.com/nspcc-dev/neo-go/pkg/core/interop"
    16  	"github.com/nspcc-dev/neo-go/pkg/core/interop/runtime"
    17  	istorage "github.com/nspcc-dev/neo-go/pkg/core/interop/storage"
    18  	"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
    19  	"github.com/nspcc-dev/neo-go/pkg/core/state"
    20  	"github.com/nspcc-dev/neo-go/pkg/core/storage"
    21  	"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
    22  	"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
    23  	"github.com/nspcc-dev/neo-go/pkg/encoding/bigint"
    24  	"github.com/nspcc-dev/neo-go/pkg/io"
    25  	"github.com/nspcc-dev/neo-go/pkg/smartcontract"
    26  	"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
    27  	"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
    28  	"github.com/nspcc-dev/neo-go/pkg/util"
    29  	"github.com/nspcc-dev/neo-go/pkg/vm/emit"
    30  	"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
    31  )
    32  
    33  // NEO represents NEO native contract.
    34  type NEO struct {
    35  	nep17TokenNative
    36  	GAS    *GAS
    37  	Policy *Policy
    38  
    39  	// Configuration and standby keys are set in constructor and then
    40  	// only read from.
    41  	cfg         config.ProtocolConfiguration
    42  	standbyKeys keys.PublicKeys
    43  }
    44  
    45  type NeoCache struct {
    46  	// gasPerBlock represents the history of generated gas per block.
    47  	gasPerBlock gasRecord
    48  
    49  	registerPrice int64
    50  
    51  	votesChanged   bool
    52  	nextValidators keys.PublicKeys
    53  	// newEpochNextValidators contains cached next block newEpochNextValidators. This list is updated once
    54  	// per dBFT epoch in PostPersist of the last block in the epoch if candidates
    55  	// votes ratio has been changed or register/unregister operation was performed
    56  	// within the last processed epoch. The updated value is being persisted
    57  	// following the standard layered DAO persist rules, so that external users
    58  	// will get the proper value with upper Blockchain's DAO (but this value is
    59  	// relevant only by the moment of first epoch block creation).
    60  	newEpochNextValidators keys.PublicKeys
    61  	// committee contains cached committee members and their votes.
    62  	// It is updated once in a while depending on committee size
    63  	// (every 28 blocks for mainnet). It's value
    64  	// is always equal to the value stored by `prefixCommittee`.
    65  	committee keysWithVotes
    66  	// newEpochCommittee contains cached committee members updated once per dBFT
    67  	// epoch in PostPersist of the last block in the epoch.
    68  	newEpochCommittee keysWithVotes
    69  	// committeeHash contains the script hash of the committee.
    70  	committeeHash util.Uint160
    71  	// newEpochCommitteeHash contains the script hash of the newEpochCommittee.
    72  	newEpochCommitteeHash util.Uint160
    73  
    74  	// gasPerVoteCache contains the last updated value of GAS per vote reward for candidates.
    75  	// It is set in state-modifying methods only and read in `PostPersist`, thus is not protected
    76  	// by any mutex.
    77  	gasPerVoteCache map[string]big.Int
    78  }
    79  
    80  const (
    81  	neoContractID = -5
    82  	// NEOTotalSupply is the total amount of NEO in the system.
    83  	NEOTotalSupply = 100000000
    84  	// DefaultRegisterPrice is the default price for candidate register.
    85  	DefaultRegisterPrice = 1000 * GASFactor
    86  	// prefixCandidate is a prefix used to store validator's data.
    87  	prefixCandidate = 33
    88  	// prefixVotersCount is a prefix for storing total amount of NEO of voters.
    89  	prefixVotersCount = 1
    90  	// prefixVoterRewardPerCommittee is a prefix for storing committee GAS reward.
    91  	prefixVoterRewardPerCommittee = 23
    92  	// voterRewardFactor is a factor by which voter reward per committee is multiplied
    93  	// to make calculations more precise.
    94  	voterRewardFactor = 100_000_000
    95  	// prefixGASPerBlock is a prefix for storing amount of GAS generated per block.
    96  	prefixGASPerBlock = 29
    97  	// prefixRegisterPrice is a prefix for storing candidate register price.
    98  	prefixRegisterPrice = 13
    99  	// effectiveVoterTurnout represents minimal ratio of total supply to total amount voted value
   100  	// which is require to use non-standby validators.
   101  	effectiveVoterTurnout = 5
   102  	// neoHolderRewardRatio is a percent of generated GAS that is distributed to NEO holders.
   103  	neoHolderRewardRatio = 10
   104  	// neoHolderRewardRatio is a percent of generated GAS that is distributed to committee.
   105  	committeeRewardRatio = 10
   106  	// neoHolderRewardRatio is a percent of generated GAS that is distributed to voters.
   107  	voterRewardRatio = 80
   108  
   109  	// maxGetCandidatesRespLen is the maximum number of candidates to return from the
   110  	// getCandidates method.
   111  	maxGetCandidatesRespLen = 256
   112  )
   113  
   114  var (
   115  	// prefixCommittee is a key used to store committee.
   116  	prefixCommittee = []byte{14}
   117  
   118  	bigCommitteeRewardRatio  = big.NewInt(committeeRewardRatio)
   119  	bigVoterRewardRatio      = big.NewInt(voterRewardRatio)
   120  	bigVoterRewardFactor     = big.NewInt(voterRewardFactor)
   121  	bigEffectiveVoterTurnout = big.NewInt(effectiveVoterTurnout)
   122  	big100                   = big.NewInt(100)
   123  )
   124  
   125  var (
   126  	_ interop.Contract        = (*NEO)(nil)
   127  	_ dao.NativeContractCache = (*NeoCache)(nil)
   128  )
   129  
   130  // Copy implements NativeContractCache interface.
   131  func (c *NeoCache) Copy() dao.NativeContractCache {
   132  	cp := &NeoCache{}
   133  	copyNeoCache(c, cp)
   134  	return cp
   135  }
   136  
   137  func copyNeoCache(src, dst *NeoCache) {
   138  	dst.votesChanged = src.votesChanged
   139  	// Can safely omit copying because the new array is created each time
   140  	// newEpochNextValidators list, nextValidators and committee are updated.
   141  	dst.nextValidators = src.nextValidators
   142  	dst.committee = src.committee
   143  	dst.committeeHash = src.committeeHash
   144  	dst.newEpochNextValidators = src.newEpochNextValidators
   145  	dst.newEpochCommittee = src.newEpochCommittee
   146  	dst.newEpochCommitteeHash = src.newEpochCommitteeHash
   147  
   148  	dst.registerPrice = src.registerPrice
   149  
   150  	// Can't omit copying because gasPerBlock is append-only, thus to be able to
   151  	// discard cache changes in case of FAULTed transaction we need a separate
   152  	// container for updated gasPerBlock values.
   153  	dst.gasPerBlock = make(gasRecord, len(src.gasPerBlock))
   154  	copy(dst.gasPerBlock, src.gasPerBlock)
   155  
   156  	dst.gasPerVoteCache = make(map[string]big.Int)
   157  	for k, v := range src.gasPerVoteCache {
   158  		dst.gasPerVoteCache[k] = v
   159  	}
   160  }
   161  
   162  // makeValidatorKey creates a key from the account script hash.
   163  func makeValidatorKey(key *keys.PublicKey) []byte {
   164  	b := key.Bytes()
   165  	// Don't create a new buffer.
   166  	b = append(b, 0)
   167  	copy(b[1:], b[0:])
   168  	b[0] = prefixCandidate
   169  	return b
   170  }
   171  
   172  // newNEO returns NEO native contract.
   173  func newNEO(cfg config.ProtocolConfiguration) *NEO {
   174  	n := &NEO{}
   175  	defer n.BuildHFSpecificMD(n.ActiveIn())
   176  
   177  	nep17 := newNEP17Native(nativenames.Neo, neoContractID)
   178  	nep17.symbol = "NEO"
   179  	nep17.decimals = 0
   180  	nep17.factor = 1
   181  	nep17.incBalance = n.increaseBalance
   182  	nep17.balFromBytes = n.balanceFromBytes
   183  
   184  	n.nep17TokenNative = *nep17
   185  
   186  	err := n.initConfigCache(cfg)
   187  	if err != nil {
   188  		panic(fmt.Errorf("failed to initialize NEO config cache: %w", err))
   189  	}
   190  
   191  	desc := newDescriptor("unclaimedGas", smartcontract.IntegerType,
   192  		manifest.NewParameter("account", smartcontract.Hash160Type),
   193  		manifest.NewParameter("end", smartcontract.IntegerType))
   194  	md := newMethodAndPrice(n.unclaimedGas, 1<<17, callflag.ReadStates)
   195  	n.AddMethod(md, desc)
   196  
   197  	desc = newDescriptor("registerCandidate", smartcontract.BoolType,
   198  		manifest.NewParameter("pubkey", smartcontract.PublicKeyType))
   199  	md = newMethodAndPrice(n.registerCandidate, 0, callflag.States)
   200  	n.AddMethod(md, desc)
   201  
   202  	desc = newDescriptor("unregisterCandidate", smartcontract.BoolType,
   203  		manifest.NewParameter("pubkey", smartcontract.PublicKeyType))
   204  	md = newMethodAndPrice(n.unregisterCandidate, 1<<16, callflag.States)
   205  	n.AddMethod(md, desc)
   206  
   207  	desc = newDescriptor("vote", smartcontract.BoolType,
   208  		manifest.NewParameter("account", smartcontract.Hash160Type),
   209  		manifest.NewParameter("voteTo", smartcontract.PublicKeyType))
   210  	md = newMethodAndPrice(n.vote, 1<<16, callflag.States)
   211  	n.AddMethod(md, desc)
   212  
   213  	desc = newDescriptor("getCandidates", smartcontract.ArrayType)
   214  	md = newMethodAndPrice(n.getCandidatesCall, 1<<22, callflag.ReadStates)
   215  	n.AddMethod(md, desc)
   216  
   217  	desc = newDescriptor("getAllCandidates", smartcontract.InteropInterfaceType)
   218  	md = newMethodAndPrice(n.getAllCandidatesCall, 1<<22, callflag.ReadStates)
   219  	n.AddMethod(md, desc)
   220  
   221  	desc = newDescriptor("getCandidateVote", smartcontract.IntegerType,
   222  		manifest.NewParameter("pubKey", smartcontract.PublicKeyType))
   223  	md = newMethodAndPrice(n.getCandidateVoteCall, 1<<15, callflag.ReadStates)
   224  	n.AddMethod(md, desc)
   225  
   226  	desc = newDescriptor("getAccountState", smartcontract.ArrayType,
   227  		manifest.NewParameter("account", smartcontract.Hash160Type))
   228  	md = newMethodAndPrice(n.getAccountState, 1<<15, callflag.ReadStates)
   229  	n.AddMethod(md, desc)
   230  
   231  	desc = newDescriptor("getCommittee", smartcontract.ArrayType)
   232  	md = newMethodAndPrice(n.getCommittee, 1<<16, callflag.ReadStates)
   233  	n.AddMethod(md, desc)
   234  
   235  	desc = newDescriptor("getCommitteeAddress", smartcontract.Hash160Type)
   236  	md = newMethodAndPrice(n.getCommitteeAddress, 1<<16, callflag.ReadStates, config.HFCockatrice)
   237  	n.AddMethod(md, desc)
   238  
   239  	desc = newDescriptor("getNextBlockValidators", smartcontract.ArrayType)
   240  	md = newMethodAndPrice(n.getNextBlockValidators, 1<<16, callflag.ReadStates)
   241  	n.AddMethod(md, desc)
   242  
   243  	desc = newDescriptor("getGasPerBlock", smartcontract.IntegerType)
   244  	md = newMethodAndPrice(n.getGASPerBlock, 1<<15, callflag.ReadStates)
   245  	n.AddMethod(md, desc)
   246  
   247  	desc = newDescriptor("setGasPerBlock", smartcontract.VoidType,
   248  		manifest.NewParameter("gasPerBlock", smartcontract.IntegerType))
   249  	md = newMethodAndPrice(n.setGASPerBlock, 1<<15, callflag.States)
   250  	n.AddMethod(md, desc)
   251  
   252  	desc = newDescriptor("getRegisterPrice", smartcontract.IntegerType)
   253  	md = newMethodAndPrice(n.getRegisterPrice, 1<<15, callflag.ReadStates)
   254  	n.AddMethod(md, desc)
   255  
   256  	desc = newDescriptor("setRegisterPrice", smartcontract.VoidType,
   257  		manifest.NewParameter("registerPrice", smartcontract.IntegerType))
   258  	md = newMethodAndPrice(n.setRegisterPrice, 1<<15, callflag.States)
   259  	n.AddMethod(md, desc)
   260  
   261  	eDesc := newEventDescriptor("CandidateStateChanged",
   262  		manifest.NewParameter("pubkey", smartcontract.PublicKeyType),
   263  		manifest.NewParameter("registered", smartcontract.BoolType),
   264  		manifest.NewParameter("votes", smartcontract.IntegerType),
   265  	)
   266  	eMD := newEvent(eDesc)
   267  	n.AddEvent(eMD)
   268  
   269  	eDesc = newEventDescriptor("Vote",
   270  		manifest.NewParameter("account", smartcontract.Hash160Type),
   271  		manifest.NewParameter("from", smartcontract.PublicKeyType),
   272  		manifest.NewParameter("to", smartcontract.PublicKeyType),
   273  		manifest.NewParameter("amount", smartcontract.IntegerType),
   274  	)
   275  	eMD = newEvent(eDesc)
   276  	n.AddEvent(eMD)
   277  
   278  	eDesc = newEventDescriptor("CommitteeChanged",
   279  		manifest.NewParameter("old", smartcontract.ArrayType),
   280  		manifest.NewParameter("new", smartcontract.ArrayType),
   281  	)
   282  	eMD = newEvent(eDesc)
   283  	n.AddEvent(eMD)
   284  
   285  	return n
   286  }
   287  
   288  // Initialize initializes a NEO contract.
   289  func (n *NEO) Initialize(ic *interop.Context, hf *config.Hardfork, newMD *interop.HFSpecificContractMD) error {
   290  	if hf != n.ActiveIn() {
   291  		return nil
   292  	}
   293  
   294  	if err := n.nep17TokenNative.Initialize(ic); err != nil {
   295  		return err
   296  	}
   297  
   298  	_, totalSupply := n.nep17TokenNative.getTotalSupply(ic.DAO)
   299  	if totalSupply.Sign() != 0 {
   300  		return errors.New("already initialized")
   301  	}
   302  
   303  	cache := &NeoCache{
   304  		gasPerVoteCache: make(map[string]big.Int),
   305  		votesChanged:    true,
   306  	}
   307  
   308  	// We need cache to be present in DAO before the subsequent call to `mint`.
   309  	ic.DAO.SetCache(n.ID, cache)
   310  
   311  	committee0 := n.standbyKeys[:n.cfg.GetCommitteeSize(ic.Block.Index)]
   312  	cvs := toKeysWithVotes(committee0)
   313  	err := n.updateCache(cache, cvs, ic.BlockHeight())
   314  	if err != nil {
   315  		return err
   316  	}
   317  
   318  	ic.DAO.PutStorageItem(n.ID, prefixCommittee, cvs.Bytes(ic.DAO.GetItemCtx()))
   319  
   320  	h, err := getStandbyValidatorsHash(ic)
   321  	if err != nil {
   322  		return err
   323  	}
   324  	n.mint(ic, h, big.NewInt(NEOTotalSupply), false)
   325  
   326  	var index uint32
   327  	value := big.NewInt(5 * GASFactor)
   328  	n.putGASRecord(ic.DAO, index, value)
   329  
   330  	gr := &gasRecord{{Index: index, GASPerBlock: *value}}
   331  	cache.gasPerBlock = *gr
   332  	ic.DAO.PutStorageItem(n.ID, []byte{prefixVotersCount}, state.StorageItem{})
   333  
   334  	setIntWithKey(n.ID, ic.DAO, []byte{prefixRegisterPrice}, DefaultRegisterPrice)
   335  	cache.registerPrice = int64(DefaultRegisterPrice)
   336  
   337  	var numOfCNs = n.cfg.GetNumOfCNs(ic.Block.Index + 1)
   338  	err = n.updateCachedNewEpochValues(ic.DAO, cache, ic.BlockHeight(), numOfCNs)
   339  	if err != nil {
   340  		return fmt.Errorf("failed to update next block newEpoch* cache: %w", err)
   341  	}
   342  	return nil
   343  }
   344  
   345  // InitializeCache initializes all NEO cache with the proper values from the storage.
   346  // Cache initialization should be done apart from Initialize because Initialize is
   347  // called only when deploying native contracts. InitializeCache implements the Contract
   348  // interface.
   349  func (n *NEO) InitializeCache(blockHeight uint32, d *dao.Simple) error {
   350  	cache := &NeoCache{
   351  		gasPerVoteCache: make(map[string]big.Int),
   352  		votesChanged:    true,
   353  	}
   354  
   355  	var committee = keysWithVotes{}
   356  	si := d.GetStorageItem(n.ID, prefixCommittee)
   357  	if err := committee.DecodeBytes(si); err != nil {
   358  		return fmt.Errorf("failed to decode committee: %w", err)
   359  	}
   360  	if err := n.updateCache(cache, committee, blockHeight); err != nil {
   361  		return fmt.Errorf("failed to update cache: %w", err)
   362  	}
   363  
   364  	cache.gasPerBlock = n.getSortedGASRecordFromDAO(d)
   365  	cache.registerPrice = getIntWithKey(n.ID, d, []byte{prefixRegisterPrice})
   366  
   367  	// Update newEpoch* cache for external users. It holds values for the previous
   368  	// dBFT epoch if the current one isn't yet finished.
   369  	if n.cfg.ShouldUpdateCommitteeAt(blockHeight + 1) {
   370  		var numOfCNs = n.cfg.GetNumOfCNs(blockHeight + 1)
   371  		err := n.updateCachedNewEpochValues(d, cache, blockHeight, numOfCNs)
   372  		if err != nil {
   373  			return fmt.Errorf("failed to update next block newEpoch* cache: %w", err)
   374  		}
   375  	} else {
   376  		// nextValidators, committee and committee hash are filled in by this moment
   377  		// via n.updateCache call.
   378  		cache.newEpochNextValidators = cache.nextValidators.Copy()
   379  		cache.newEpochCommittee = make(keysWithVotes, len(cache.committee))
   380  		copy(cache.newEpochCommittee, cache.committee)
   381  		cache.newEpochCommitteeHash = cache.committeeHash
   382  	}
   383  
   384  	d.SetCache(n.ID, cache)
   385  	return nil
   386  }
   387  
   388  // ActiveIn implements the Contract interface.
   389  func (n *NEO) ActiveIn() *config.Hardfork {
   390  	return nil
   391  }
   392  
   393  func (n *NEO) initConfigCache(cfg config.ProtocolConfiguration) error {
   394  	var err error
   395  
   396  	n.cfg = cfg
   397  	n.standbyKeys, err = keys.NewPublicKeysFromStrings(n.cfg.StandbyCommittee)
   398  	return err
   399  }
   400  
   401  func (n *NEO) updateCache(cache *NeoCache, cvs keysWithVotes, blockHeight uint32) error {
   402  	cache.committee = cvs
   403  
   404  	var committee = getCommitteeMembers(cache.committee)
   405  	script, err := smartcontract.CreateMajorityMultiSigRedeemScript(committee.Copy())
   406  	if err != nil {
   407  		return err
   408  	}
   409  	cache.committeeHash = hash.Hash160(script)
   410  
   411  	nextVals := committee[:n.cfg.GetNumOfCNs(blockHeight+1)].Copy()
   412  	sort.Sort(nextVals)
   413  	cache.nextValidators = nextVals
   414  	return nil
   415  }
   416  
   417  // updateCachedNewEpochValues sets newEpochNextValidators, newEpochCommittee and
   418  // newEpochCommitteeHash cache that will be used by external users to retrieve
   419  // next block validators list of the next dBFT epoch that wasn't yet started and
   420  // will be used by corresponding values initialisation on the next epoch start.
   421  // The updated new epoch cached values computed using the persisted blocks state
   422  // of the latest epoch.
   423  func (n *NEO) updateCachedNewEpochValues(d *dao.Simple, cache *NeoCache, blockHeight uint32, numOfCNs int) error {
   424  	committee, cvs, err := n.computeCommitteeMembers(blockHeight, d)
   425  	if err != nil {
   426  		return fmt.Errorf("failed to compute committee members: %w", err)
   427  	}
   428  	cache.newEpochCommittee = cvs
   429  
   430  	script, err := smartcontract.CreateMajorityMultiSigRedeemScript(committee.Copy())
   431  	if err != nil {
   432  		return err
   433  	}
   434  	cache.newEpochCommitteeHash = hash.Hash160(script)
   435  
   436  	nextVals := committee[:numOfCNs].Copy()
   437  	sort.Sort(nextVals)
   438  	cache.newEpochNextValidators = nextVals
   439  	return nil
   440  }
   441  
   442  // OnPersist implements the Contract interface.
   443  func (n *NEO) OnPersist(ic *interop.Context) error {
   444  	if n.cfg.ShouldUpdateCommitteeAt(ic.Block.Index) {
   445  		cache := ic.DAO.GetRWCache(n.ID).(*NeoCache)
   446  		// Cached newEpoch* values always have proper value set (either by PostPersist
   447  		// during the last epoch block handling or by initialization code).
   448  
   449  		var oldCommittee, newCommittee stackitem.Item
   450  		for i := 0; i < len(cache.committee); i++ {
   451  			if cache.newEpochCommittee[i].Key != cache.committee[i].Key ||
   452  				(i == 0 && len(cache.newEpochCommittee) != len(cache.committee)) {
   453  				oldCommittee, newCommittee = cache.committee.toNotificationItem(), cache.newEpochCommittee.toNotificationItem()
   454  				break
   455  			}
   456  		}
   457  
   458  		cache.nextValidators = cache.newEpochNextValidators
   459  		cache.committee = cache.newEpochCommittee
   460  		cache.committeeHash = cache.newEpochCommitteeHash
   461  		cache.votesChanged = false
   462  
   463  		// We need to put in storage anyway, as it affects dumps
   464  		ic.DAO.PutStorageItem(n.ID, prefixCommittee, cache.committee.Bytes(ic.DAO.GetItemCtx()))
   465  
   466  		if oldCommittee != nil {
   467  			ic.AddNotification(n.Hash, "CommitteeChanged", stackitem.NewArray([]stackitem.Item{
   468  				oldCommittee, newCommittee,
   469  			}))
   470  		}
   471  	}
   472  	return nil
   473  }
   474  
   475  // PostPersist implements the Contract interface.
   476  func (n *NEO) PostPersist(ic *interop.Context) error {
   477  	gas := n.GetGASPerBlock(ic.DAO, ic.Block.Index)
   478  	cache := ic.DAO.GetROCache(n.ID).(*NeoCache)
   479  	pubs := getCommitteeMembers(cache.committee)
   480  	committeeSize := n.cfg.GetCommitteeSize(ic.Block.Index)
   481  	index := int(ic.Block.Index) % committeeSize
   482  	committeeReward := new(big.Int).Mul(gas, bigCommitteeRewardRatio)
   483  	n.GAS.mint(ic, pubs[index].GetScriptHash(), committeeReward.Div(committeeReward, big100), false)
   484  
   485  	var isCacheRW bool
   486  	if n.cfg.ShouldUpdateCommitteeAt(ic.Block.Index) {
   487  		var voterReward = new(big.Int).Set(bigVoterRewardRatio)
   488  		voterReward.Mul(voterReward, gas)
   489  		voterReward.Mul(voterReward, big.NewInt(voterRewardFactor*int64(committeeSize)))
   490  		var validatorsCount = n.cfg.GetNumOfCNs(ic.Block.Index)
   491  		voterReward.Div(voterReward, big.NewInt(int64(committeeSize+validatorsCount)))
   492  		voterReward.Div(voterReward, big100)
   493  
   494  		var (
   495  			cs  = cache.committee
   496  			key = make([]byte, 34)
   497  		)
   498  		for i := range cs {
   499  			if cs[i].Votes.Sign() > 0 {
   500  				var tmp = new(big.Int)
   501  				if i < validatorsCount {
   502  					tmp.Set(intTwo)
   503  				} else {
   504  					tmp.Set(intOne)
   505  				}
   506  				tmp.Mul(tmp, voterReward)
   507  				tmp.Div(tmp, cs[i].Votes)
   508  
   509  				key = makeVoterKey([]byte(cs[i].Key), key)
   510  				r := n.getLatestGASPerVote(ic.DAO, key)
   511  				tmp.Add(tmp, &r)
   512  
   513  				if !isCacheRW {
   514  					cache = ic.DAO.GetRWCache(n.ID).(*NeoCache)
   515  					isCacheRW = true
   516  				}
   517  				cache.gasPerVoteCache[cs[i].Key] = *tmp
   518  
   519  				ic.DAO.PutBigInt(n.ID, key, tmp)
   520  			}
   521  		}
   522  	}
   523  	// Update newEpoch cache for external users and further committee, committeeHash
   524  	// and nextBlockValidators cache initialisation if committee should be updated in
   525  	// the next block.
   526  	if n.cfg.ShouldUpdateCommitteeAt(ic.Block.Index + 1) {
   527  		var (
   528  			h        = ic.Block.Index // consider persisting block as stored to get _next_ block newEpochNextValidators
   529  			numOfCNs = n.cfg.GetNumOfCNs(h + 1)
   530  		)
   531  		if cache.votesChanged ||
   532  			numOfCNs != len(cache.newEpochNextValidators) ||
   533  			n.cfg.GetCommitteeSize(h+1) != len(cache.newEpochCommittee) {
   534  			if !isCacheRW {
   535  				cache = ic.DAO.GetRWCache(n.ID).(*NeoCache)
   536  			}
   537  			err := n.updateCachedNewEpochValues(ic.DAO, cache, h, numOfCNs)
   538  			if err != nil {
   539  				return fmt.Errorf("failed to update next block newEpoch* cache: %w", err)
   540  			}
   541  		}
   542  	}
   543  
   544  	return nil
   545  }
   546  
   547  func (n *NEO) getLatestGASPerVote(d *dao.Simple, key []byte) big.Int {
   548  	var g big.Int
   549  	cache := d.GetROCache(n.ID).(*NeoCache)
   550  	if g, ok := cache.gasPerVoteCache[string(key[1:])]; ok {
   551  		return g
   552  	}
   553  	item := d.GetStorageItem(n.ID, key)
   554  	if item == nil {
   555  		g = *big.NewInt(0)
   556  	} else {
   557  		g = *bigint.FromBytes(item)
   558  	}
   559  	return g
   560  }
   561  
   562  func (n *NEO) increaseBalance(ic *interop.Context, h util.Uint160, si *state.StorageItem, amount *big.Int, checkBal *big.Int) (func(), error) {
   563  	var postF func()
   564  
   565  	acc, err := state.NEOBalanceFromBytes(*si)
   566  	if err != nil {
   567  		return nil, err
   568  	}
   569  	if (amount.Sign() == -1 && acc.Balance.CmpAbs(amount) == -1) ||
   570  		(amount.Sign() == 0 && checkBal != nil && acc.Balance.Cmp(checkBal) == -1) {
   571  		return nil, errors.New("insufficient funds")
   572  	}
   573  	newGas, err := n.distributeGas(ic, acc)
   574  	if err != nil {
   575  		return nil, err
   576  	}
   577  	if newGas != nil { // Can be if it was already distributed in the same block.
   578  		postF = func() { n.GAS.mint(ic, h, newGas, true) }
   579  	}
   580  	if amount.Sign() == 0 {
   581  		*si = acc.Bytes(ic.DAO.GetItemCtx())
   582  		return postF, nil
   583  	}
   584  	if err := n.ModifyAccountVotes(acc, ic.DAO, amount, false); err != nil {
   585  		return nil, err
   586  	}
   587  	if acc.VoteTo != nil {
   588  		if err := n.modifyVoterTurnout(ic.DAO, amount); err != nil {
   589  			return nil, err
   590  		}
   591  	}
   592  	acc.Balance.Add(&acc.Balance, amount)
   593  	if acc.Balance.Sign() != 0 {
   594  		*si = acc.Bytes(ic.DAO.GetItemCtx())
   595  	} else {
   596  		*si = nil
   597  	}
   598  	return postF, nil
   599  }
   600  
   601  func (n *NEO) balanceFromBytes(si *state.StorageItem) (*big.Int, error) {
   602  	acc, err := state.NEOBalanceFromBytes(*si)
   603  	if err != nil {
   604  		return nil, err
   605  	}
   606  	return &acc.Balance, err
   607  }
   608  
   609  func (n *NEO) distributeGas(ic *interop.Context, acc *state.NEOBalance) (*big.Int, error) {
   610  	if ic.Block == nil || ic.Block.Index == 0 || ic.Block.Index == acc.BalanceHeight {
   611  		return nil, nil
   612  	}
   613  	gen, err := n.calculateBonus(ic.DAO, acc, ic.Block.Index)
   614  	if err != nil {
   615  		return nil, err
   616  	}
   617  	acc.BalanceHeight = ic.Block.Index
   618  	if acc.VoteTo != nil {
   619  		latestGasPerVote := n.getLatestGASPerVote(ic.DAO, makeVoterKey(acc.VoteTo.Bytes()))
   620  		acc.LastGasPerVote = latestGasPerVote
   621  	}
   622  
   623  	return gen, nil
   624  }
   625  
   626  func (n *NEO) unclaimedGas(ic *interop.Context, args []stackitem.Item) stackitem.Item {
   627  	u := toUint160(args[0])
   628  	end := uint32(toBigInt(args[1]).Int64())
   629  	gen, err := n.CalculateBonus(ic, u, end)
   630  	if err != nil {
   631  		panic(err)
   632  	}
   633  	return stackitem.NewBigInteger(gen)
   634  }
   635  
   636  func (n *NEO) getGASPerBlock(ic *interop.Context, _ []stackitem.Item) stackitem.Item {
   637  	gas := n.GetGASPerBlock(ic.DAO, ic.Block.Index)
   638  	return stackitem.NewBigInteger(gas)
   639  }
   640  
   641  func (n *NEO) getSortedGASRecordFromDAO(d *dao.Simple) gasRecord {
   642  	var gr = make(gasRecord, 0)
   643  	d.Seek(n.ID, storage.SeekRange{Prefix: []byte{prefixGASPerBlock}}, func(k, v []byte) bool {
   644  		gr = append(gr, gasIndexPair{
   645  			Index:       binary.BigEndian.Uint32(k),
   646  			GASPerBlock: *bigint.FromBytes(v),
   647  		})
   648  		return true
   649  	})
   650  	return gr
   651  }
   652  
   653  // GetGASPerBlock returns gas generated for block with provided index.
   654  func (n *NEO) GetGASPerBlock(d *dao.Simple, index uint32) *big.Int {
   655  	cache := d.GetROCache(n.ID).(*NeoCache)
   656  	gr := cache.gasPerBlock
   657  	for i := len(gr) - 1; i >= 0; i-- {
   658  		if gr[i].Index <= index {
   659  			g := gr[i].GASPerBlock
   660  			return &g
   661  		}
   662  	}
   663  	panic("NEO cache not initialized")
   664  }
   665  
   666  // GetCommitteeAddress returns address of the committee.
   667  func (n *NEO) GetCommitteeAddress(d *dao.Simple) util.Uint160 {
   668  	cache := d.GetROCache(n.ID).(*NeoCache)
   669  	return cache.committeeHash
   670  }
   671  
   672  func (n *NEO) checkCommittee(ic *interop.Context) bool {
   673  	ok, err := runtime.CheckHashedWitness(ic, n.GetCommitteeAddress(ic.DAO))
   674  	if err != nil {
   675  		panic(err)
   676  	}
   677  	return ok
   678  }
   679  
   680  func (n *NEO) setGASPerBlock(ic *interop.Context, args []stackitem.Item) stackitem.Item {
   681  	gas := toBigInt(args[0])
   682  	err := n.SetGASPerBlock(ic, ic.Block.Index+1, gas)
   683  	if err != nil {
   684  		panic(err)
   685  	}
   686  	return stackitem.Null{}
   687  }
   688  
   689  // SetGASPerBlock sets gas generated for blocks after index.
   690  func (n *NEO) SetGASPerBlock(ic *interop.Context, index uint32, gas *big.Int) error {
   691  	if gas.Sign() == -1 || gas.Cmp(big.NewInt(10*GASFactor)) == 1 {
   692  		return errors.New("invalid value for GASPerBlock")
   693  	}
   694  	if !n.checkCommittee(ic) {
   695  		return errors.New("invalid committee signature")
   696  	}
   697  	n.putGASRecord(ic.DAO, index, gas)
   698  	cache := ic.DAO.GetRWCache(n.ID).(*NeoCache)
   699  	cache.gasPerBlock = append(cache.gasPerBlock, gasIndexPair{
   700  		Index:       index,
   701  		GASPerBlock: *gas,
   702  	})
   703  	return nil
   704  }
   705  
   706  func (n *NEO) getRegisterPrice(ic *interop.Context, _ []stackitem.Item) stackitem.Item {
   707  	return stackitem.NewBigInteger(big.NewInt(n.getRegisterPriceInternal(ic.DAO)))
   708  }
   709  
   710  func (n *NEO) getRegisterPriceInternal(d *dao.Simple) int64 {
   711  	cache := d.GetROCache(n.ID).(*NeoCache)
   712  	return cache.registerPrice
   713  }
   714  
   715  func (n *NEO) setRegisterPrice(ic *interop.Context, args []stackitem.Item) stackitem.Item {
   716  	price := toBigInt(args[0])
   717  	if price.Sign() <= 0 || !price.IsInt64() {
   718  		panic("invalid register price")
   719  	}
   720  	if !n.checkCommittee(ic) {
   721  		panic("invalid committee signature")
   722  	}
   723  
   724  	setIntWithKey(n.ID, ic.DAO, []byte{prefixRegisterPrice}, price.Int64())
   725  	cache := ic.DAO.GetRWCache(n.ID).(*NeoCache)
   726  	cache.registerPrice = price.Int64()
   727  	return stackitem.Null{}
   728  }
   729  
   730  func (n *NEO) dropCandidateIfZero(d *dao.Simple, cache *NeoCache, pub *keys.PublicKey, c *candidate) bool {
   731  	if c.Registered || c.Votes.Sign() != 0 {
   732  		return false
   733  	}
   734  	d.DeleteStorageItem(n.ID, makeValidatorKey(pub))
   735  
   736  	voterKey := makeVoterKey(pub.Bytes())
   737  	d.DeleteStorageItem(n.ID, voterKey)
   738  	delete(cache.gasPerVoteCache, string(voterKey))
   739  
   740  	return true
   741  }
   742  
   743  func makeVoterKey(pub []byte, prealloc ...[]byte) []byte {
   744  	var key []byte
   745  	if len(prealloc) != 0 {
   746  		key = prealloc[0]
   747  	} else {
   748  		key = make([]byte, 34)
   749  	}
   750  	key[0] = prefixVoterRewardPerCommittee
   751  	copy(key[1:], pub)
   752  	return key
   753  }
   754  
   755  // CalculateBonus calculates amount of gas generated for holding value NEO from start to end block
   756  // and having voted for active committee member.
   757  func (n *NEO) CalculateBonus(ic *interop.Context, acc util.Uint160, end uint32) (*big.Int, error) {
   758  	if ic.Block == nil || end != ic.Block.Index {
   759  		return nil, errors.New("can't calculate bonus of height unequal (BlockHeight + 1)")
   760  	}
   761  	key := makeAccountKey(acc)
   762  	si := ic.DAO.GetStorageItem(n.ID, key)
   763  	if si == nil {
   764  		return nil, storage.ErrKeyNotFound
   765  	}
   766  	st, err := state.NEOBalanceFromBytes(si)
   767  	if err != nil {
   768  		return nil, err
   769  	}
   770  	return n.calculateBonus(ic.DAO, st, end)
   771  }
   772  
   773  func (n *NEO) calculateBonus(d *dao.Simple, acc *state.NEOBalance, end uint32) (*big.Int, error) {
   774  	r, err := n.CalculateNEOHolderReward(d, &acc.Balance, acc.BalanceHeight, end)
   775  	if err != nil || acc.VoteTo == nil {
   776  		return r, err
   777  	}
   778  
   779  	var key = makeVoterKey(acc.VoteTo.Bytes())
   780  	var reward = n.getLatestGASPerVote(d, key)
   781  	var tmp = big.NewInt(0).Sub(&reward, &acc.LastGasPerVote)
   782  	tmp.Mul(tmp, &acc.Balance)
   783  	tmp.Div(tmp, bigVoterRewardFactor)
   784  	tmp.Add(tmp, r)
   785  	return tmp, nil
   786  }
   787  
   788  // CalculateNEOHolderReward return GAS reward for holding `value` of NEO from start to end block.
   789  func (n *NEO) CalculateNEOHolderReward(d *dao.Simple, value *big.Int, start, end uint32) (*big.Int, error) {
   790  	if value.Sign() == 0 || start >= end {
   791  		return big.NewInt(0), nil
   792  	} else if value.Sign() < 0 {
   793  		return nil, errors.New("negative value")
   794  	}
   795  	cache := d.GetROCache(n.ID).(*NeoCache)
   796  	gr := cache.gasPerBlock
   797  	var sum, tmp big.Int
   798  	for i := len(gr) - 1; i >= 0; i-- {
   799  		if gr[i].Index >= end {
   800  			continue
   801  		} else if gr[i].Index <= start {
   802  			tmp.SetInt64(int64(end - start))
   803  			tmp.Mul(&tmp, &gr[i].GASPerBlock)
   804  			sum.Add(&sum, &tmp)
   805  			break
   806  		}
   807  		tmp.SetInt64(int64(end - gr[i].Index))
   808  		tmp.Mul(&tmp, &gr[i].GASPerBlock)
   809  		sum.Add(&sum, &tmp)
   810  		end = gr[i].Index
   811  	}
   812  	res := new(big.Int).Mul(value, &sum)
   813  	res.Mul(res, tmp.SetInt64(neoHolderRewardRatio))
   814  	res.Div(res, tmp.SetInt64(100*NEOTotalSupply))
   815  	return res, nil
   816  }
   817  
   818  func (n *NEO) registerCandidate(ic *interop.Context, args []stackitem.Item) stackitem.Item {
   819  	pub := toPublicKey(args[0])
   820  	ok, err := runtime.CheckKeyedWitness(ic, pub)
   821  	if err != nil {
   822  		panic(err)
   823  	} else if !ok {
   824  		return stackitem.NewBool(false)
   825  	}
   826  	if !ic.VM.AddGas(n.getRegisterPriceInternal(ic.DAO)) {
   827  		panic("insufficient gas")
   828  	}
   829  	err = n.RegisterCandidateInternal(ic, pub)
   830  	return stackitem.NewBool(err == nil)
   831  }
   832  
   833  // RegisterCandidateInternal registers pub as a new candidate.
   834  func (n *NEO) RegisterCandidateInternal(ic *interop.Context, pub *keys.PublicKey) error {
   835  	var emitEvent = true
   836  
   837  	key := makeValidatorKey(pub)
   838  	si := ic.DAO.GetStorageItem(n.ID, key)
   839  	var c *candidate
   840  	if si == nil {
   841  		c = &candidate{Registered: true}
   842  	} else {
   843  		c = new(candidate).FromBytes(si)
   844  		emitEvent = !c.Registered
   845  		c.Registered = true
   846  	}
   847  	err := putConvertibleToDAO(n.ID, ic.DAO, key, c)
   848  	if emitEvent {
   849  		cache := ic.DAO.GetRWCache(n.ID).(*NeoCache)
   850  		cache.votesChanged = true
   851  		ic.AddNotification(n.Hash, "CandidateStateChanged", stackitem.NewArray([]stackitem.Item{
   852  			stackitem.NewByteArray(pub.Bytes()),
   853  			stackitem.NewBool(c.Registered),
   854  			stackitem.NewBigInteger(&c.Votes),
   855  		}))
   856  	}
   857  	return err
   858  }
   859  
   860  func (n *NEO) unregisterCandidate(ic *interop.Context, args []stackitem.Item) stackitem.Item {
   861  	pub := toPublicKey(args[0])
   862  	ok, err := runtime.CheckKeyedWitness(ic, pub)
   863  	if err != nil {
   864  		panic(err)
   865  	} else if !ok {
   866  		return stackitem.NewBool(false)
   867  	}
   868  	err = n.UnregisterCandidateInternal(ic, pub)
   869  	return stackitem.NewBool(err == nil)
   870  }
   871  
   872  // UnregisterCandidateInternal unregisters pub as a candidate.
   873  func (n *NEO) UnregisterCandidateInternal(ic *interop.Context, pub *keys.PublicKey) error {
   874  	var err error
   875  
   876  	key := makeValidatorKey(pub)
   877  	si := ic.DAO.GetStorageItem(n.ID, key)
   878  	if si == nil {
   879  		return nil
   880  	}
   881  	cache := ic.DAO.GetRWCache(n.ID).(*NeoCache)
   882  	// Not only current committee/validators cache is interested in votesChanged, but also
   883  	// newEpoch cache, thus, modify votesChanged to update the latter.
   884  	cache.votesChanged = true
   885  	c := new(candidate).FromBytes(si)
   886  	emitEvent := c.Registered
   887  	c.Registered = false
   888  	ok := n.dropCandidateIfZero(ic.DAO, cache, pub, c)
   889  	if !ok {
   890  		err = putConvertibleToDAO(n.ID, ic.DAO, key, c)
   891  	}
   892  	if emitEvent {
   893  		ic.AddNotification(n.Hash, "CandidateStateChanged", stackitem.NewArray([]stackitem.Item{
   894  			stackitem.NewByteArray(pub.Bytes()),
   895  			stackitem.NewBool(c.Registered),
   896  			stackitem.NewBigInteger(&c.Votes),
   897  		}))
   898  	}
   899  	return err
   900  }
   901  
   902  func (n *NEO) vote(ic *interop.Context, args []stackitem.Item) stackitem.Item {
   903  	acc := toUint160(args[0])
   904  	var pub *keys.PublicKey
   905  	if _, ok := args[1].(stackitem.Null); !ok {
   906  		pub = toPublicKey(args[1])
   907  	}
   908  	err := n.VoteInternal(ic, acc, pub)
   909  	return stackitem.NewBool(err == nil)
   910  }
   911  
   912  // VoteInternal votes from account h for validarors specified in pubs.
   913  func (n *NEO) VoteInternal(ic *interop.Context, h util.Uint160, pub *keys.PublicKey) error {
   914  	ok, err := runtime.CheckHashedWitness(ic, h)
   915  	if err != nil {
   916  		return err
   917  	} else if !ok {
   918  		return errors.New("invalid signature")
   919  	}
   920  	key := makeAccountKey(h)
   921  	si := ic.DAO.GetStorageItem(n.ID, key)
   922  	if si == nil {
   923  		return errors.New("invalid account")
   924  	}
   925  	acc, err := state.NEOBalanceFromBytes(si)
   926  	if err != nil {
   927  		return err
   928  	}
   929  	// we should put it in storage anyway as it affects dumps
   930  	ic.DAO.PutStorageItem(n.ID, key, si)
   931  	if pub != nil {
   932  		valKey := makeValidatorKey(pub)
   933  		valSi := ic.DAO.GetStorageItem(n.ID, valKey)
   934  		if valSi == nil {
   935  			return errors.New("unknown validator")
   936  		}
   937  		cd := new(candidate).FromBytes(valSi)
   938  		// we should put it in storage anyway as it affects dumps
   939  		ic.DAO.PutStorageItem(n.ID, valKey, valSi)
   940  		if !cd.Registered {
   941  			return errors.New("validator must be registered")
   942  		}
   943  	}
   944  
   945  	if (acc.VoteTo == nil) != (pub == nil) {
   946  		val := &acc.Balance
   947  		if pub == nil {
   948  			val = new(big.Int).Neg(val)
   949  		}
   950  		if err := n.modifyVoterTurnout(ic.DAO, val); err != nil {
   951  			return err
   952  		}
   953  	}
   954  	newGas, err := n.distributeGas(ic, acc)
   955  	if err != nil {
   956  		return err
   957  	}
   958  	if err := n.ModifyAccountVotes(acc, ic.DAO, new(big.Int).Neg(&acc.Balance), false); err != nil {
   959  		return err
   960  	}
   961  	if pub != nil && pub != acc.VoteTo {
   962  		acc.LastGasPerVote = n.getLatestGASPerVote(ic.DAO, makeVoterKey(pub.Bytes()))
   963  	}
   964  	oldVote := acc.VoteTo
   965  	acc.VoteTo = pub
   966  	if err := n.ModifyAccountVotes(acc, ic.DAO, &acc.Balance, true); err != nil {
   967  		return err
   968  	}
   969  	if pub == nil {
   970  		acc.LastGasPerVote = *big.NewInt(0)
   971  	}
   972  	ic.DAO.PutStorageItem(n.ID, key, acc.Bytes(ic.DAO.GetItemCtx()))
   973  
   974  	ic.AddNotification(n.Hash, "Vote", stackitem.NewArray([]stackitem.Item{
   975  		stackitem.NewByteArray(h.BytesBE()),
   976  		keyToStackItem(oldVote),
   977  		keyToStackItem(pub),
   978  		stackitem.NewBigInteger(&acc.Balance),
   979  	}))
   980  
   981  	if newGas != nil { // Can be if it was already distributed in the same block.
   982  		n.GAS.mint(ic, h, newGas, true)
   983  	}
   984  	return nil
   985  }
   986  
   987  func keyToStackItem(k *keys.PublicKey) stackitem.Item {
   988  	if k == nil {
   989  		return stackitem.Null{}
   990  	}
   991  	return stackitem.NewByteArray(k.Bytes())
   992  }
   993  
   994  // ModifyAccountVotes modifies votes of the specified account by value (can be negative).
   995  // typ specifies if this modify is occurring during transfer or vote (with old or new validator).
   996  func (n *NEO) ModifyAccountVotes(acc *state.NEOBalance, d *dao.Simple, value *big.Int, isNewVote bool) error {
   997  	cache := d.GetRWCache(n.ID).(*NeoCache)
   998  	cache.votesChanged = true
   999  	if acc.VoteTo != nil {
  1000  		key := makeValidatorKey(acc.VoteTo)
  1001  		si := d.GetStorageItem(n.ID, key)
  1002  		if si == nil {
  1003  			return errors.New("invalid validator")
  1004  		}
  1005  		cd := new(candidate).FromBytes(si)
  1006  		cd.Votes.Add(&cd.Votes, value)
  1007  		if !isNewVote {
  1008  			ok := n.dropCandidateIfZero(d, cache, acc.VoteTo, cd)
  1009  			if ok {
  1010  				return nil
  1011  			}
  1012  		}
  1013  		return putConvertibleToDAO(n.ID, d, key, cd)
  1014  	}
  1015  	return nil
  1016  }
  1017  
  1018  func (n *NEO) getCandidates(d *dao.Simple, sortByKey bool, max int) ([]keyWithVotes, error) {
  1019  	arr := make([]keyWithVotes, 0)
  1020  	buf := io.NewBufBinWriter()
  1021  	d.Seek(n.ID, storage.SeekRange{Prefix: []byte{prefixCandidate}}, func(k, v []byte) bool {
  1022  		c := new(candidate).FromBytes(v)
  1023  		emit.CheckSig(buf.BinWriter, k)
  1024  		if c.Registered && !n.Policy.IsBlocked(d, hash.Hash160(buf.Bytes())) {
  1025  			arr = append(arr, keyWithVotes{Key: string(k), Votes: &c.Votes})
  1026  		}
  1027  		buf.Reset()
  1028  		return !sortByKey || max > 0 && len(arr) < max
  1029  	})
  1030  
  1031  	if !sortByKey {
  1032  		// sortByKey assumes to sort by serialized key bytes (that's the way keys
  1033  		// are stored and retrieved from the storage by default). Otherwise, need
  1034  		// to sort using big.Int comparator.
  1035  		sort.Slice(arr, func(i, j int) bool {
  1036  			// The most-voted validators should end up in the front of the list.
  1037  			cmp := arr[i].Votes.Cmp(arr[j].Votes)
  1038  			if cmp != 0 {
  1039  				return cmp > 0
  1040  			}
  1041  			// Ties are broken with deserialized public keys.
  1042  			// Sort by ECPoint's (X, Y) components: compare X first, and then compare Y.
  1043  			cmpX := strings.Compare(arr[i].Key[1:], arr[j].Key[1:])
  1044  			if cmpX != 0 {
  1045  				return cmpX == -1
  1046  			}
  1047  			// The case when X components are the same is extremely rare, thus we perform
  1048  			// key deserialization only if needed. No error can occur.
  1049  			ki, _ := keys.NewPublicKeyFromBytes([]byte(arr[i].Key), elliptic.P256())
  1050  			kj, _ := keys.NewPublicKeyFromBytes([]byte(arr[j].Key), elliptic.P256())
  1051  			return ki.Y.Cmp(kj.Y) == -1
  1052  		})
  1053  	}
  1054  	return arr, nil
  1055  }
  1056  
  1057  // GetCandidates returns current registered validators list with keys
  1058  // and votes.
  1059  func (n *NEO) GetCandidates(d *dao.Simple) ([]state.Validator, error) {
  1060  	kvs, err := n.getCandidates(d, true, maxGetCandidatesRespLen)
  1061  	if err != nil {
  1062  		return nil, err
  1063  	}
  1064  	arr := make([]state.Validator, len(kvs))
  1065  	for i := range kvs {
  1066  		arr[i].Key, err = keys.NewPublicKeyFromBytes([]byte(kvs[i].Key), elliptic.P256())
  1067  		if err != nil {
  1068  			return nil, err
  1069  		}
  1070  		arr[i].Votes = kvs[i].Votes
  1071  	}
  1072  	return arr, nil
  1073  }
  1074  
  1075  func (n *NEO) getCandidatesCall(ic *interop.Context, _ []stackitem.Item) stackitem.Item {
  1076  	validators, err := n.getCandidates(ic.DAO, true, maxGetCandidatesRespLen)
  1077  	if err != nil {
  1078  		panic(err)
  1079  	}
  1080  	arr := make([]stackitem.Item, len(validators))
  1081  	for i := range validators {
  1082  		arr[i] = stackitem.NewStruct([]stackitem.Item{
  1083  			stackitem.NewByteArray([]byte(validators[i].Key)),
  1084  			stackitem.NewBigInteger(validators[i].Votes),
  1085  		})
  1086  	}
  1087  	return stackitem.NewArray(arr)
  1088  }
  1089  
  1090  func (n *NEO) getCommitteeAddress(ic *interop.Context, _ []stackitem.Item) stackitem.Item {
  1091  	return stackitem.NewByteArray(n.GetCommitteeAddress(ic.DAO).BytesBE())
  1092  }
  1093  
  1094  func (n *NEO) getAllCandidatesCall(ic *interop.Context, _ []stackitem.Item) stackitem.Item {
  1095  	ctx, cancel := context.WithCancel(context.Background())
  1096  	prefix := []byte{prefixCandidate}
  1097  	buf := io.NewBufBinWriter()
  1098  	keep := func(kv storage.KeyValue) bool {
  1099  		c := new(candidate).FromBytes(kv.Value)
  1100  		emit.CheckSig(buf.BinWriter, kv.Key)
  1101  		if c.Registered && !n.Policy.IsBlocked(ic.DAO, hash.Hash160(buf.Bytes())) {
  1102  			buf.Reset()
  1103  			return true
  1104  		}
  1105  		buf.Reset()
  1106  		return false
  1107  	}
  1108  	seekres := ic.DAO.SeekAsync(ctx, n.ID, storage.SeekRange{Prefix: prefix})
  1109  	filteredRes := make(chan storage.KeyValue)
  1110  	go func() {
  1111  		for kv := range seekres {
  1112  			if keep(kv) {
  1113  				filteredRes <- kv
  1114  			}
  1115  		}
  1116  		close(filteredRes)
  1117  	}()
  1118  
  1119  	opts := istorage.FindRemovePrefix | istorage.FindDeserialize | istorage.FindPick1
  1120  	item := istorage.NewIterator(filteredRes, prefix, int64(opts))
  1121  	ic.RegisterCancelFunc(func() {
  1122  		cancel()
  1123  		for range seekres { //nolint:revive //empty-block
  1124  		}
  1125  	})
  1126  	return stackitem.NewInterop(item)
  1127  }
  1128  
  1129  func (n *NEO) getCandidateVoteCall(ic *interop.Context, args []stackitem.Item) stackitem.Item {
  1130  	pub := toPublicKey(args[0])
  1131  	key := makeValidatorKey(pub)
  1132  	si := ic.DAO.GetStorageItem(n.ID, key)
  1133  	if si == nil {
  1134  		return stackitem.NewBigInteger(big.NewInt(-1))
  1135  	}
  1136  	c := new(candidate).FromBytes(si)
  1137  	if !c.Registered {
  1138  		return stackitem.NewBigInteger(big.NewInt(-1))
  1139  	}
  1140  	return stackitem.NewBigInteger(&c.Votes)
  1141  }
  1142  
  1143  func (n *NEO) getAccountState(ic *interop.Context, args []stackitem.Item) stackitem.Item {
  1144  	key := makeAccountKey(toUint160(args[0]))
  1145  	si := ic.DAO.GetStorageItem(n.ID, key)
  1146  	if len(si) == 0 {
  1147  		return stackitem.Null{}
  1148  	}
  1149  
  1150  	item, err := stackitem.Deserialize(si)
  1151  	if err != nil {
  1152  		panic(err) // no errors are expected but we better be sure
  1153  	}
  1154  	return item
  1155  }
  1156  
  1157  // ComputeNextBlockValidators computes an actual list of current validators that is
  1158  // relevant for the latest processed dBFT epoch and based on the changes made by
  1159  // register/unregister/vote calls during the latest epoch.
  1160  // Note: this method isn't actually "computes" new committee list and calculates
  1161  // new validators list from it. Instead, it uses cache, and the cache itself is
  1162  // updated during the PostPersist of the last block of every epoch.
  1163  func (n *NEO) ComputeNextBlockValidators(d *dao.Simple) keys.PublicKeys {
  1164  	// It should always be OK with RO cache if using lower-layered DAO with proper
  1165  	// cache set.
  1166  	cache := d.GetROCache(n.ID).(*NeoCache)
  1167  	if vals := cache.newEpochNextValidators; vals != nil {
  1168  		return vals.Copy()
  1169  	}
  1170  	// It's a caller's program error to call ComputeNextBlockValidators not having
  1171  	// the right value in lower cache. With the current scheme of handling
  1172  	// newEpochNextValidators cache this code is expected to be unreachable, but
  1173  	// let's have this panic here just in case.
  1174  	panic("bug: unexpected external call to newEpochNextValidators cache")
  1175  }
  1176  
  1177  func (n *NEO) getCommittee(ic *interop.Context, _ []stackitem.Item) stackitem.Item {
  1178  	pubs := n.GetCommitteeMembers(ic.DAO)
  1179  	sort.Sort(pubs)
  1180  	return pubsToArray(pubs)
  1181  }
  1182  
  1183  func (n *NEO) modifyVoterTurnout(d *dao.Simple, amount *big.Int) error {
  1184  	key := []byte{prefixVotersCount}
  1185  	si := d.GetStorageItem(n.ID, key)
  1186  	if si == nil {
  1187  		return errors.New("voters count not found")
  1188  	}
  1189  	votersCount := bigint.FromBytes(si)
  1190  	votersCount.Add(votersCount, amount)
  1191  	d.PutBigInt(n.ID, key, votersCount)
  1192  	return nil
  1193  }
  1194  
  1195  // GetCommitteeMembers returns public keys of nodes in committee using cached value.
  1196  func (n *NEO) GetCommitteeMembers(d *dao.Simple) keys.PublicKeys {
  1197  	cache := d.GetROCache(n.ID).(*NeoCache)
  1198  	return getCommitteeMembers(cache.committee)
  1199  }
  1200  
  1201  func getCommitteeMembers(cvs keysWithVotes) keys.PublicKeys {
  1202  	var committee = make(keys.PublicKeys, len(cvs))
  1203  	var err error
  1204  	for i := range committee {
  1205  		committee[i], err = cvs[i].PublicKey()
  1206  		if err != nil {
  1207  			panic(err)
  1208  		}
  1209  	}
  1210  	return committee
  1211  }
  1212  
  1213  func toKeysWithVotes(pubs keys.PublicKeys) keysWithVotes {
  1214  	ks := make(keysWithVotes, len(pubs))
  1215  	for i := range pubs {
  1216  		ks[i].UnmarshaledKey = pubs[i]
  1217  		ks[i].Key = string(pubs[i].Bytes())
  1218  		ks[i].Votes = big.NewInt(0)
  1219  	}
  1220  	return ks
  1221  }
  1222  
  1223  // computeCommitteeMembers returns public keys of nodes in committee.
  1224  func (n *NEO) computeCommitteeMembers(blockHeight uint32, d *dao.Simple) (keys.PublicKeys, keysWithVotes, error) {
  1225  	key := []byte{prefixVotersCount}
  1226  	si := d.GetStorageItem(n.ID, key)
  1227  	if si == nil {
  1228  		return nil, nil, errors.New("voters count not found")
  1229  	}
  1230  	votersCount := bigint.FromBytes(si)
  1231  	// votersCount / totalSupply must be >= 0.2
  1232  	votersCount.Mul(votersCount, bigEffectiveVoterTurnout)
  1233  	_, totalSupply := n.getTotalSupply(d)
  1234  	voterTurnout := votersCount.Div(votersCount, totalSupply)
  1235  
  1236  	count := n.cfg.GetCommitteeSize(blockHeight + 1)
  1237  	// Can be sorted and/or returned to outside users, thus needs to be copied.
  1238  	sbVals := keys.PublicKeys(n.standbyKeys[:count]).Copy()
  1239  	cs, err := n.getCandidates(d, false, -1)
  1240  	if err != nil {
  1241  		return nil, nil, err
  1242  	}
  1243  	if voterTurnout.Sign() != 1 || len(cs) < count {
  1244  		kvs := make(keysWithVotes, count)
  1245  		for i := range kvs {
  1246  			kvs[i].UnmarshaledKey = sbVals[i]
  1247  			kvs[i].Key = string(sbVals[i].Bytes())
  1248  			votes := big.NewInt(0)
  1249  			for j := range cs {
  1250  				if cs[j].Key == kvs[i].Key {
  1251  					votes = cs[j].Votes
  1252  					break
  1253  				}
  1254  			}
  1255  			kvs[i].Votes = votes
  1256  		}
  1257  		return sbVals, kvs, nil
  1258  	}
  1259  	pubs := make(keys.PublicKeys, count)
  1260  	for i := range pubs {
  1261  		pubs[i], err = cs[i].PublicKey()
  1262  		if err != nil {
  1263  			return nil, nil, err
  1264  		}
  1265  	}
  1266  	return pubs, cs[:count], nil
  1267  }
  1268  
  1269  func (n *NEO) getNextBlockValidators(ic *interop.Context, _ []stackitem.Item) stackitem.Item {
  1270  	result := n.GetNextBlockValidatorsInternal(ic.DAO)
  1271  	return pubsToArray(result)
  1272  }
  1273  
  1274  // GetNextBlockValidatorsInternal returns next block validators.
  1275  func (n *NEO) GetNextBlockValidatorsInternal(d *dao.Simple) keys.PublicKeys {
  1276  	cache := d.GetROCache(n.ID).(*NeoCache)
  1277  	return cache.nextValidators.Copy()
  1278  }
  1279  
  1280  // BalanceOf returns native NEO token balance for the acc.
  1281  func (n *NEO) BalanceOf(d *dao.Simple, acc util.Uint160) (*big.Int, uint32) {
  1282  	key := makeAccountKey(acc)
  1283  	si := d.GetStorageItem(n.ID, key)
  1284  	if si == nil {
  1285  		return big.NewInt(0), 0
  1286  	}
  1287  	st, err := state.NEOBalanceFromBytes(si)
  1288  	if err != nil {
  1289  		panic(fmt.Errorf("failed to decode NEO balance state: %w", err))
  1290  	}
  1291  	return &st.Balance, st.BalanceHeight
  1292  }
  1293  
  1294  func pubsToArray(pubs keys.PublicKeys) stackitem.Item {
  1295  	arr := make([]stackitem.Item, len(pubs))
  1296  	for i := range pubs {
  1297  		arr[i] = stackitem.NewByteArray(pubs[i].Bytes())
  1298  	}
  1299  	return stackitem.NewArray(arr)
  1300  }
  1301  
  1302  func toPublicKey(s stackitem.Item) *keys.PublicKey {
  1303  	buf, err := s.TryBytes()
  1304  	if err != nil {
  1305  		panic(err)
  1306  	}
  1307  	pub := new(keys.PublicKey)
  1308  	if err := pub.DecodeBytes(buf); err != nil {
  1309  		panic(err)
  1310  	}
  1311  	return pub
  1312  }
  1313  
  1314  // putGASRecord is a helper which creates key and puts GASPerBlock value into the storage.
  1315  func (n *NEO) putGASRecord(dao *dao.Simple, index uint32, value *big.Int) {
  1316  	key := make([]byte, 5)
  1317  	key[0] = prefixGASPerBlock
  1318  	binary.BigEndian.PutUint32(key[1:], index)
  1319  	dao.PutBigInt(n.ID, key, value)
  1320  }