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

     1  package native_test
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"fmt"
     7  	"math"
     8  	"math/big"
     9  	"sort"
    10  	"strings"
    11  	"testing"
    12  
    13  	"github.com/nspcc-dev/neo-go/internal/contracts"
    14  	"github.com/nspcc-dev/neo-go/internal/random"
    15  	"github.com/nspcc-dev/neo-go/pkg/compiler"
    16  	"github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames"
    17  	"github.com/nspcc-dev/neo-go/pkg/core/native"
    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/transaction"
    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/io"
    24  	"github.com/nspcc-dev/neo-go/pkg/neotest"
    25  	"github.com/nspcc-dev/neo-go/pkg/neotest/chain"
    26  	"github.com/nspcc-dev/neo-go/pkg/smartcontract"
    27  	"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
    28  	"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
    29  	"github.com/nspcc-dev/neo-go/pkg/util"
    30  	"github.com/nspcc-dev/neo-go/pkg/vm/emit"
    31  	"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
    32  	"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
    33  	"github.com/stretchr/testify/assert"
    34  	"github.com/stretchr/testify/require"
    35  )
    36  
    37  func newNeoCommitteeClient(t *testing.T, expectedGASBalance int) *neotest.ContractInvoker {
    38  	bc, validators, committee := chain.NewMulti(t)
    39  	e := neotest.NewExecutor(t, bc, validators, committee)
    40  
    41  	if expectedGASBalance > 0 {
    42  		e.ValidatorInvoker(e.NativeHash(t, nativenames.Gas)).Invoke(t, true, "transfer", e.Validator.ScriptHash(), e.CommitteeHash, expectedGASBalance, nil)
    43  	}
    44  
    45  	return e.CommitteeInvoker(e.NativeHash(t, nativenames.Neo))
    46  }
    47  
    48  func newNeoValidatorsClient(t *testing.T) *neotest.ContractInvoker {
    49  	c := newNeoCommitteeClient(t, 100_0000_0000)
    50  	return c.ValidatorInvoker(c.NativeHash(t, nativenames.Neo))
    51  }
    52  
    53  func TestNEO_GasPerBlock(t *testing.T) {
    54  	testGetSet(t, newNeoCommitteeClient(t, 100_0000_0000), "GasPerBlock", 5*native.GASFactor, 0, 10*native.GASFactor)
    55  }
    56  
    57  func TestNEO_GasPerBlockCache(t *testing.T) {
    58  	testGetSetCache(t, newNeoCommitteeClient(t, 100_0000_0000), "GasPerBlock", 5*native.GASFactor)
    59  }
    60  
    61  func TestNEO_RegisterPrice(t *testing.T) {
    62  	testGetSet(t, newNeoCommitteeClient(t, 100_0000_0000), "RegisterPrice", native.DefaultRegisterPrice, 1, math.MaxInt64)
    63  }
    64  
    65  func TestNEO_RegisterPriceCache(t *testing.T) {
    66  	testGetSetCache(t, newNeoCommitteeClient(t, 100_0000_0000), "RegisterPrice", native.DefaultRegisterPrice)
    67  }
    68  
    69  func TestNEO_CandidateEvents(t *testing.T) {
    70  	c := newNativeClient(t, nativenames.Neo)
    71  	singleSigner := c.Signers[0].(neotest.MultiSigner).Single(0)
    72  	cc := c.WithSigners(c.Signers[0], singleSigner)
    73  	e := c.Executor
    74  	pkb := singleSigner.Account().PublicKey().Bytes()
    75  
    76  	// Register 1 -> event
    77  	tx := cc.Invoke(t, true, "registerCandidate", pkb)
    78  	e.CheckTxNotificationEvent(t, tx, 0, state.NotificationEvent{
    79  		ScriptHash: c.Hash,
    80  		Name:       "CandidateStateChanged",
    81  		Item: stackitem.NewArray([]stackitem.Item{
    82  			stackitem.NewByteArray(pkb),
    83  			stackitem.NewBool(true),
    84  			stackitem.Make(0),
    85  		}),
    86  	})
    87  
    88  	// Register 2 -> no event
    89  	tx = cc.Invoke(t, true, "registerCandidate", pkb)
    90  	aer := e.GetTxExecResult(t, tx)
    91  	require.Equal(t, 0, len(aer.Events))
    92  
    93  	// Vote -> event
    94  	tx = c.Invoke(t, true, "vote", c.Signers[0].ScriptHash().BytesBE(), pkb)
    95  	e.CheckTxNotificationEvent(t, tx, 0, state.NotificationEvent{
    96  		ScriptHash: c.Hash,
    97  		Name:       "Vote",
    98  		Item: stackitem.NewArray([]stackitem.Item{
    99  			stackitem.NewByteArray(c.Signers[0].ScriptHash().BytesBE()),
   100  			stackitem.Null{},
   101  			stackitem.NewByteArray(pkb),
   102  			stackitem.Make(100000000),
   103  		}),
   104  	})
   105  
   106  	// Unregister 1 -> event
   107  	tx = cc.Invoke(t, true, "unregisterCandidate", pkb)
   108  	e.CheckTxNotificationEvent(t, tx, 0, state.NotificationEvent{
   109  		ScriptHash: c.Hash,
   110  		Name:       "CandidateStateChanged",
   111  		Item: stackitem.NewArray([]stackitem.Item{
   112  			stackitem.NewByteArray(pkb),
   113  			stackitem.NewBool(false),
   114  			stackitem.Make(100000000),
   115  		}),
   116  	})
   117  
   118  	// Unregister 2 -> no event
   119  	tx = cc.Invoke(t, true, "unregisterCandidate", pkb)
   120  	aer = e.GetTxExecResult(t, tx)
   121  	require.Equal(t, 0, len(aer.Events))
   122  }
   123  
   124  func TestNEO_CommitteeEvents(t *testing.T) {
   125  	neoCommitteeInvoker := newNeoCommitteeClient(t, 100_0000_0000)
   126  	neoValidatorsInvoker := neoCommitteeInvoker.WithSigners(neoCommitteeInvoker.Validator)
   127  	e := neoCommitteeInvoker.Executor
   128  
   129  	cfg := e.Chain.GetConfig()
   130  	committeeSize := cfg.GetCommitteeSize(0)
   131  
   132  	voters := make([]neotest.Signer, committeeSize)
   133  	candidates := make([]neotest.Signer, committeeSize)
   134  	for i := 0; i < committeeSize; i++ {
   135  		voters[i] = e.NewAccount(t, 10_0000_0000)
   136  		candidates[i] = e.NewAccount(t, 2000_0000_0000) // enough for one registration
   137  	}
   138  	txes := make([]*transaction.Transaction, 0, committeeSize*3)
   139  	for i := 0; i < committeeSize; i++ {
   140  		transferTx := neoValidatorsInvoker.PrepareInvoke(t, "transfer", e.Validator.ScriptHash(), voters[i].(neotest.SingleSigner).Account().PrivateKey().GetScriptHash(), int64(committeeSize-i)*1000000, nil)
   141  		txes = append(txes, transferTx)
   142  
   143  		registerTx := neoValidatorsInvoker.WithSigners(candidates[i]).PrepareInvoke(t, "registerCandidate", candidates[i].(neotest.SingleSigner).Account().PublicKey().Bytes())
   144  		txes = append(txes, registerTx)
   145  
   146  		voteTx := neoValidatorsInvoker.WithSigners(voters[i]).PrepareInvoke(t, "vote", voters[i].(neotest.SingleSigner).Account().PrivateKey().GetScriptHash(), candidates[i].(neotest.SingleSigner).Account().PublicKey().Bytes())
   147  		txes = append(txes, voteTx)
   148  	}
   149  	block := neoValidatorsInvoker.AddNewBlock(t, txes...)
   150  	for _, tx := range txes {
   151  		e.CheckHalt(t, tx.Hash(), stackitem.Make(true))
   152  	}
   153  
   154  	// Advance the chain to trigger committee recalculation and potential change.
   155  	for (block.Index)%uint32(committeeSize) != 0 {
   156  		block = neoCommitteeInvoker.AddNewBlock(t)
   157  	}
   158  
   159  	// Check for CommitteeChanged event in the last persisted block's AER.
   160  	blockHash := e.Chain.CurrentBlockHash()
   161  	aer, err := e.Chain.GetAppExecResults(blockHash, trigger.OnPersist)
   162  	require.NoError(t, err)
   163  	require.Equal(t, 1, len(aer))
   164  
   165  	require.Equal(t, aer[0].Events[0].Name, "CommitteeChanged")
   166  	require.Equal(t, 2, len(aer[0].Events[0].Item.Value().([]stackitem.Item)))
   167  
   168  	expectedOldCommitteePublicKeys, err := keys.NewPublicKeysFromStrings(cfg.StandbyCommittee)
   169  	require.NoError(t, err)
   170  	expectedOldCommitteeStackItems := make([]stackitem.Item, len(expectedOldCommitteePublicKeys))
   171  	for i, pubKey := range expectedOldCommitteePublicKeys {
   172  		expectedOldCommitteeStackItems[i] = stackitem.NewByteArray(pubKey.Bytes())
   173  	}
   174  	oldCommitteeStackItem := aer[0].Events[0].Item.Value().([]stackitem.Item)[0].(*stackitem.Array)
   175  	for i, item := range oldCommitteeStackItem.Value().([]stackitem.Item) {
   176  		assert.Equal(t, expectedOldCommitteeStackItems[i].(*stackitem.ByteArray).Value().([]byte), item.Value().([]byte))
   177  	}
   178  	expectedNewCommitteeStackItems := make([]stackitem.Item, 0, committeeSize)
   179  	for _, candidate := range candidates {
   180  		expectedNewCommitteeStackItems = append(expectedNewCommitteeStackItems, stackitem.NewByteArray(candidate.(neotest.SingleSigner).Account().PublicKey().Bytes()))
   181  	}
   182  	newCommitteeStackItem := aer[0].Events[0].Item.Value().([]stackitem.Item)[1].(*stackitem.Array)
   183  	for i, item := range newCommitteeStackItem.Value().([]stackitem.Item) {
   184  		assert.Equal(t, expectedNewCommitteeStackItems[i].(*stackitem.ByteArray).Value().([]byte), item.Value().([]byte))
   185  	}
   186  }
   187  
   188  func TestNEO_Vote(t *testing.T) {
   189  	neoCommitteeInvoker := newNeoCommitteeClient(t, 100_0000_0000)
   190  	neoValidatorsInvoker := neoCommitteeInvoker.WithSigners(neoCommitteeInvoker.Validator)
   191  	policyInvoker := neoCommitteeInvoker.CommitteeInvoker(neoCommitteeInvoker.NativeHash(t, nativenames.Policy))
   192  	e := neoCommitteeInvoker.Executor
   193  
   194  	cfg := e.Chain.GetConfig()
   195  	committeeSize := cfg.GetCommitteeSize(0)
   196  	validatorsCount := cfg.GetNumOfCNs(0)
   197  	freq := validatorsCount + committeeSize
   198  	advanceChain := func(t *testing.T) {
   199  		for i := 0; i < freq; i++ {
   200  			neoCommitteeInvoker.AddNewBlock(t)
   201  		}
   202  	}
   203  
   204  	standBySorted, err := keys.NewPublicKeysFromStrings(e.Chain.GetConfig().StandbyCommittee)
   205  	require.NoError(t, err)
   206  	standBySorted = standBySorted[:validatorsCount]
   207  	sort.Sort(standBySorted)
   208  	pubs := e.Chain.ComputeNextBlockValidators()
   209  	require.Equal(t, standBySorted, keys.PublicKeys(pubs))
   210  
   211  	// voters vote for candidates. The aim of this test is to check if voting
   212  	// reward is proportional to the NEO balance.
   213  	voters := make([]neotest.Signer, committeeSize+1)
   214  	// referenceAccounts perform the same actions as voters except voting, i.e. we
   215  	// will transfer the same amount of NEO to referenceAccounts and see how much
   216  	// GAS they receive for NEO ownership. We need these values to be able to define
   217  	// how much GAS voters receive for NEO ownership.
   218  	referenceAccounts := make([]neotest.Signer, committeeSize+1)
   219  	candidates := make([]neotest.Signer, committeeSize+1)
   220  	for i := 0; i < committeeSize+1; i++ {
   221  		voters[i] = e.NewAccount(t, 10_0000_0000)
   222  		referenceAccounts[i] = e.NewAccount(t, 10_0000_0000)
   223  		candidates[i] = e.NewAccount(t, 2000_0000_0000) // enough for one registration
   224  	}
   225  	txes := make([]*transaction.Transaction, 0, committeeSize*4-2)
   226  	for i := 0; i < committeeSize+1; i++ {
   227  		transferTx := neoValidatorsInvoker.PrepareInvoke(t, "transfer", e.Validator.ScriptHash(), voters[i].(neotest.SingleSigner).Account().PrivateKey().GetScriptHash(), int64(committeeSize+1-i)*1000000, nil)
   228  		txes = append(txes, transferTx)
   229  		transferTx = neoValidatorsInvoker.PrepareInvoke(t, "transfer", e.Validator.ScriptHash(), referenceAccounts[i].(neotest.SingleSigner).Account().PrivateKey().GetScriptHash(), int64(committeeSize+1-i)*1000000, nil)
   230  		txes = append(txes, transferTx)
   231  		if i > 0 {
   232  			registerTx := neoValidatorsInvoker.WithSigners(candidates[i]).PrepareInvoke(t, "registerCandidate", candidates[i].(neotest.SingleSigner).Account().PublicKey().Bytes())
   233  			txes = append(txes, registerTx)
   234  			voteTx := neoValidatorsInvoker.WithSigners(voters[i]).PrepareInvoke(t, "vote", voters[i].(neotest.SingleSigner).Account().PrivateKey().GetScriptHash(), candidates[i].(neotest.SingleSigner).Account().PublicKey().Bytes())
   235  			txes = append(txes, voteTx)
   236  		}
   237  	}
   238  	txes = append(txes, policyInvoker.PrepareInvoke(t, "blockAccount", candidates[len(candidates)-1].(neotest.SingleSigner).Account().ScriptHash()))
   239  	neoValidatorsInvoker.AddNewBlock(t, txes...)
   240  	for _, tx := range txes {
   241  		e.CheckHalt(t, tx.Hash(), stackitem.Make(true)) // luckily, both `transfer`, `registerCandidate` and `vote` return boolean values
   242  	}
   243  
   244  	// We still haven't voted enough validators in.
   245  	pubs = e.Chain.ComputeNextBlockValidators()
   246  	require.NoError(t, err)
   247  	require.Equal(t, standBySorted, keys.PublicKeys(pubs))
   248  
   249  	advanceChain(t)
   250  	pubs, err = e.Chain.GetNextBlockValidators()
   251  	require.NoError(t, err)
   252  	require.EqualValues(t, standBySorted, keys.PublicKeys(pubs))
   253  
   254  	// Register and give some value to the last validator.
   255  	txes = txes[:0]
   256  	registerTx := neoValidatorsInvoker.WithSigners(candidates[0]).PrepareInvoke(t, "registerCandidate", candidates[0].(neotest.SingleSigner).Account().PublicKey().Bytes())
   257  	txes = append(txes, registerTx)
   258  	voteTx := neoValidatorsInvoker.WithSigners(voters[0]).PrepareInvoke(t, "vote", voters[0].(neotest.SingleSigner).Account().PrivateKey().GetScriptHash(), candidates[0].(neotest.SingleSigner).Account().PublicKey().Bytes())
   259  	txes = append(txes, voteTx)
   260  	neoValidatorsInvoker.AddNewBlock(t, txes...)
   261  	for _, tx := range txes {
   262  		e.CheckHalt(t, tx.Hash(), stackitem.Make(true)) // luckily, both `transfer`, `registerCandidate` and `vote` return boolean values
   263  	}
   264  
   265  	advanceChain(t)
   266  	pubs, err = neoCommitteeInvoker.Chain.GetNextBlockValidators()
   267  	require.NoError(t, err)
   268  	sortedCandidates := make(keys.PublicKeys, validatorsCount)
   269  	for i := range candidates[:validatorsCount] {
   270  		sortedCandidates[i] = candidates[i].(neotest.SingleSigner).Account().PublicKey()
   271  	}
   272  	sort.Sort(sortedCandidates)
   273  	require.EqualValues(t, sortedCandidates, keys.PublicKeys(pubs))
   274  
   275  	pubs, err = neoCommitteeInvoker.Chain.GetNextBlockValidators()
   276  	require.NoError(t, err)
   277  	require.EqualValues(t, sortedCandidates, pubs)
   278  
   279  	t.Run("check voter rewards", func(t *testing.T) {
   280  		gasBalance := make([]*big.Int, len(voters)-1)
   281  		referenceGASBalance := make([]*big.Int, len(referenceAccounts)-1)
   282  		neoBalance := make([]*big.Int, len(voters)-1)
   283  		txes = make([]*transaction.Transaction, 0, len(voters)-1)
   284  		var refTxFee int64
   285  		for i := range voters[:len(voters)-1] {
   286  			h := voters[i].ScriptHash()
   287  			refH := referenceAccounts[i].ScriptHash()
   288  			gasBalance[i] = e.Chain.GetUtilityTokenBalance(h)
   289  			neoBalance[i], _ = e.Chain.GetGoverningTokenBalance(h)
   290  			referenceGASBalance[i] = e.Chain.GetUtilityTokenBalance(refH)
   291  
   292  			tx := neoCommitteeInvoker.WithSigners(voters[i]).PrepareInvoke(t, "transfer", h.BytesBE(), h.BytesBE(), int64(1), nil)
   293  			txes = append(txes, tx)
   294  			tx = neoCommitteeInvoker.WithSigners(referenceAccounts[i]).PrepareInvoke(t, "transfer", refH.BytesBE(), refH.BytesBE(), int64(1), nil)
   295  			txes = append(txes, tx)
   296  			refTxFee = tx.SystemFee + tx.NetworkFee
   297  		}
   298  		neoCommitteeInvoker.AddNewBlock(t, txes...)
   299  		for _, tx := range txes {
   300  			e.CheckHalt(t, tx.Hash(), stackitem.Make(true))
   301  		}
   302  
   303  		// Define reference reward for NEO holding for each voter account.
   304  		for i := range referenceGASBalance {
   305  			newBalance := e.Chain.GetUtilityTokenBalance(referenceAccounts[i].ScriptHash())
   306  			referenceGASBalance[i].Sub(newBalance, referenceGASBalance[i])
   307  			referenceGASBalance[i].Add(referenceGASBalance[i], big.NewInt(refTxFee))
   308  		}
   309  
   310  		// GAS increase consists of 2 parts: NEO holding + voting for committee nodes.
   311  		// Here we check that 2-nd part exists and is proportional to the amount of NEO given.
   312  		for i := range voters[:len(voters)-1] {
   313  			newGAS := e.Chain.GetUtilityTokenBalance(voters[i].ScriptHash())
   314  			newGAS.Sub(newGAS, gasBalance[i])
   315  			gasForHold := referenceGASBalance[i]
   316  			newGAS.Sub(newGAS, gasForHold)
   317  			require.True(t, newGAS.Sign() > 0)
   318  			gasBalance[i] = newGAS
   319  		}
   320  		// First account voted later than the others.
   321  		require.Equal(t, -1, gasBalance[0].Cmp(gasBalance[1]))
   322  		for i := 2; i < validatorsCount; i++ {
   323  			require.Equal(t, 0, gasBalance[i].Cmp(gasBalance[1]))
   324  		}
   325  		require.Equal(t, 1, gasBalance[1].Cmp(gasBalance[validatorsCount]))
   326  		for i := validatorsCount; i < committeeSize; i++ {
   327  			require.Equal(t, 0, gasBalance[i].Cmp(gasBalance[validatorsCount]))
   328  		}
   329  	})
   330  
   331  	neoCommitteeInvoker.WithSigners(candidates[0]).Invoke(t, true, "unregisterCandidate", candidates[0].(neotest.SingleSigner).Account().PublicKey().Bytes())
   332  	neoCommitteeInvoker.WithSigners(voters[0]).Invoke(t, false, "vote", voters[0].(neotest.SingleSigner).Account().PrivateKey().GetScriptHash(), candidates[0].(neotest.SingleSigner).Account().PublicKey().Bytes())
   333  
   334  	advanceChain(t)
   335  
   336  	pubs = e.Chain.ComputeNextBlockValidators()
   337  	for i := range pubs {
   338  		require.NotEqual(t, candidates[0], pubs[i])
   339  		require.NotEqual(t, candidates[len(candidates)-1], pubs[i])
   340  	}
   341  	// LastGasPerVote should be 0 after unvoting
   342  	getAccountState := func(t *testing.T, account util.Uint160) *state.NEOBalance {
   343  		stack, err := neoCommitteeInvoker.TestInvoke(t, "getAccountState", account)
   344  		require.NoError(t, err)
   345  		res := stack.Pop().Item()
   346  		// (s *NEOBalance) FromStackItem is able to handle both 3 and 4 subitems.
   347  		// The forth optional subitem is LastGasPerVote.
   348  		require.Equal(t, 4, len(res.Value().([]stackitem.Item)))
   349  		as := new(state.NEOBalance)
   350  		err = as.FromStackItem(res)
   351  		require.NoError(t, err)
   352  		return as
   353  	}
   354  	registerTx = neoValidatorsInvoker.WithSigners(candidates[0]).PrepareInvoke(t, "registerCandidate", candidates[0].(neotest.SingleSigner).Account().PublicKey().Bytes())
   355  	voteTx = neoValidatorsInvoker.WithSigners(voters[0]).PrepareInvoke(t, "vote", voters[0].(neotest.SingleSigner).Account().PrivateKey().GetScriptHash(), candidates[0].(neotest.SingleSigner).Account().PublicKey().Bytes())
   356  	neoValidatorsInvoker.AddNewBlock(t, registerTx, voteTx)
   357  	e.CheckHalt(t, registerTx.Hash(), stackitem.Make(true))
   358  	e.CheckHalt(t, voteTx.Hash(), stackitem.Make(true))
   359  
   360  	stateBeforeUnvote := getAccountState(t, voters[0].ScriptHash())
   361  	require.NotEqual(t, uint64(0), stateBeforeUnvote.LastGasPerVote.Uint64())
   362  	// Unvote
   363  	unvoteTx := neoValidatorsInvoker.WithSigners(voters[0]).PrepareInvoke(t, "vote", voters[0].(neotest.SingleSigner).Account().PrivateKey().GetScriptHash(), nil)
   364  	neoValidatorsInvoker.AddNewBlock(t, unvoteTx)
   365  	e.CheckHalt(t, unvoteTx.Hash(), stackitem.Make(true))
   366  	advanceChain(t)
   367  
   368  	stateAfterUnvote := getAccountState(t, voters[0].ScriptHash())
   369  	require.Equal(t, uint64(0), stateAfterUnvote.LastGasPerVote.Uint64())
   370  }
   371  
   372  // TestNEO_RecursiveDistribution is a test for https://github.com/nspcc-dev/neo-go/pull/2181.
   373  func TestNEO_RecursiveGASMint(t *testing.T) {
   374  	neoCommitteeInvoker := newNeoCommitteeClient(t, 100_0000_0000)
   375  	neoValidatorInvoker := neoCommitteeInvoker.WithSigners(neoCommitteeInvoker.Validator)
   376  	e := neoCommitteeInvoker.Executor
   377  	gasValidatorInvoker := e.ValidatorInvoker(e.NativeHash(t, nativenames.Gas))
   378  
   379  	c := neotest.CompileFile(t, e.Validator.ScriptHash(), "../../../../internal/basicchain/testdata/test_contract.go", "../../../../internal/basicchain/testdata/test_contract.yml")
   380  	e.DeployContract(t, c, nil)
   381  
   382  	gasValidatorInvoker.Invoke(t, true, "transfer", e.Validator.ScriptHash(), c.Hash, int64(2_0000_0000), nil)
   383  
   384  	// Transfer 10 NEO to test contract, the contract should earn some GAS by owning this NEO.
   385  	neoValidatorInvoker.Invoke(t, true, "transfer", e.Validator.ScriptHash(), c.Hash, int64(10), nil)
   386  
   387  	// Add blocks to be able to trigger NEO transfer from contract address to owner
   388  	// address inside onNEP17Payment (the contract starts NEO transfers from chain height = 100).
   389  	for i := e.Chain.BlockHeight(); i < 100; i++ {
   390  		e.AddNewBlock(t)
   391  	}
   392  
   393  	// Transfer 1 more NEO to the contract. Transfer will trigger onNEP17Payment. OnNEP17Payment will
   394  	// trigger transfer of 11 NEO to the contract owner (based on the contract code). 11 NEO Transfer will
   395  	// trigger GAS distribution. GAS transfer will trigger OnNEP17Payment one more time. The recursion
   396  	// shouldn't occur here, because contract's balance LastUpdated height has already been updated in
   397  	// this block.
   398  	neoValidatorInvoker.Invoke(t, true, "transfer", e.Validator.ScriptHash(), c.Hash, int64(1), nil)
   399  }
   400  
   401  func TestNEO_GetCommitteeAddress(t *testing.T) {
   402  	neoValidatorInvoker := newNeoValidatorsClient(t)
   403  	e := neoValidatorInvoker.Executor
   404  	standByCommitteePublicKeys, err := keys.NewPublicKeysFromStrings(e.Chain.GetConfig().StandbyCommittee)
   405  	require.NoError(t, err)
   406  	sort.Sort(standByCommitteePublicKeys)
   407  	expectedCommitteeAddress, err := smartcontract.CreateMajorityMultiSigRedeemScript(standByCommitteePublicKeys)
   408  	require.NoError(t, err)
   409  	stack, err := neoValidatorInvoker.TestInvoke(t, "getCommitteeAddress")
   410  	require.NoError(t, err)
   411  	require.Equal(t, hash.Hash160(expectedCommitteeAddress).BytesBE(), stack.Pop().Item().Value().([]byte))
   412  }
   413  
   414  func TestNEO_GetAccountState(t *testing.T) {
   415  	neoValidatorInvoker := newNeoValidatorsClient(t)
   416  	e := neoValidatorInvoker.Executor
   417  
   418  	cfg := e.Chain.GetConfig()
   419  	committeeSize := cfg.GetCommitteeSize(0)
   420  	validatorSize := cfg.GetNumOfCNs(0)
   421  	advanceChain := func(t *testing.T) {
   422  		for i := 0; i < committeeSize; i++ {
   423  			neoValidatorInvoker.AddNewBlock(t)
   424  		}
   425  	}
   426  
   427  	t.Run("empty", func(t *testing.T) {
   428  		neoValidatorInvoker.Invoke(t, stackitem.Null{}, "getAccountState", util.Uint160{})
   429  	})
   430  
   431  	t.Run("with funds", func(t *testing.T) {
   432  		amount := int64(1)
   433  		acc := e.NewAccount(t)
   434  		neoValidatorInvoker.Invoke(t, true, "transfer", e.Validator.ScriptHash(), acc.ScriptHash(), amount, nil)
   435  		lub := e.Chain.BlockHeight()
   436  		neoValidatorInvoker.Invoke(t, stackitem.NewStruct([]stackitem.Item{
   437  			stackitem.Make(amount),
   438  			stackitem.Make(lub),
   439  			stackitem.Null{},
   440  			stackitem.Make(0),
   441  		}), "getAccountState", acc.ScriptHash())
   442  	})
   443  
   444  	t.Run("lastGasPerVote", func(t *testing.T) {
   445  		const (
   446  			GasPerBlock      = 5
   447  			VoterRewardRatio = 80
   448  		)
   449  		getAccountState := func(t *testing.T, account util.Uint160) *state.NEOBalance {
   450  			stack, err := neoValidatorInvoker.TestInvoke(t, "getAccountState", account)
   451  			require.NoError(t, err)
   452  			as := new(state.NEOBalance)
   453  			err = as.FromStackItem(stack.Pop().Item())
   454  			require.NoError(t, err)
   455  			return as
   456  		}
   457  
   458  		amount := int64(1000)
   459  		acc := e.NewAccount(t)
   460  		neoValidatorInvoker.Invoke(t, true, "transfer", e.Validator.ScriptHash(), acc.ScriptHash(), amount, nil)
   461  		as := getAccountState(t, acc.ScriptHash())
   462  		require.Equal(t, uint64(amount), as.Balance.Uint64())
   463  		require.Equal(t, e.Chain.BlockHeight(), as.BalanceHeight)
   464  		require.Equal(t, uint64(0), as.LastGasPerVote.Uint64())
   465  		committee, _ := e.Chain.GetCommittee()
   466  		neoValidatorInvoker.WithSigners(e.Validator, e.Validator.(neotest.MultiSigner).Single(0)).Invoke(t, true, "registerCandidate", committee[0].Bytes())
   467  		neoValidatorInvoker.WithSigners(acc).Invoke(t, true, "vote", acc.ScriptHash(), committee[0].Bytes())
   468  		as = getAccountState(t, acc.ScriptHash())
   469  		require.Equal(t, uint64(0), as.LastGasPerVote.Uint64())
   470  		advanceChain(t)
   471  		neoValidatorInvoker.WithSigners(acc).Invoke(t, true, "transfer", acc.ScriptHash(), acc.ScriptHash(), amount, nil)
   472  		as = getAccountState(t, acc.ScriptHash())
   473  		expect := GasPerBlock * native.GASFactor * VoterRewardRatio / 100 * (uint64(e.Chain.BlockHeight()) / uint64(committeeSize))
   474  		expect = expect * uint64(committeeSize) / uint64(validatorSize+committeeSize) * native.NEOTotalSupply / as.Balance.Uint64()
   475  		require.Equal(t, e.Chain.BlockHeight(), as.BalanceHeight)
   476  		require.Equal(t, expect, as.LastGasPerVote.Uint64())
   477  	})
   478  }
   479  
   480  func TestNEO_GetAccountStateInteropAPI(t *testing.T) {
   481  	neoValidatorInvoker := newNeoValidatorsClient(t)
   482  	e := neoValidatorInvoker.Executor
   483  
   484  	cfg := e.Chain.GetConfig()
   485  	committeeSize := cfg.GetCommitteeSize(0)
   486  	validatorSize := cfg.GetNumOfCNs(0)
   487  	advanceChain := func(t *testing.T) {
   488  		for i := 0; i < committeeSize; i++ {
   489  			neoValidatorInvoker.AddNewBlock(t)
   490  		}
   491  	}
   492  
   493  	amount := int64(1000)
   494  	acc := e.NewAccount(t)
   495  	neoValidatorInvoker.Invoke(t, true, "transfer", e.Validator.ScriptHash(), acc.ScriptHash(), amount, nil)
   496  	committee, _ := e.Chain.GetCommittee()
   497  	neoValidatorInvoker.WithSigners(e.Validator, e.Validator.(neotest.MultiSigner).Single(0)).Invoke(t, true, "registerCandidate", committee[0].Bytes())
   498  	neoValidatorInvoker.WithSigners(acc).Invoke(t, true, "vote", acc.ScriptHash(), committee[0].Bytes())
   499  	advanceChain(t)
   500  	neoValidatorInvoker.WithSigners(acc).Invoke(t, true, "transfer", acc.ScriptHash(), acc.ScriptHash(), amount, nil)
   501  
   502  	var hashAStr string
   503  	for i := 0; i < util.Uint160Size; i++ {
   504  		hashAStr += fmt.Sprintf("%#x", acc.ScriptHash()[i])
   505  		if i != util.Uint160Size-1 {
   506  			hashAStr += ", "
   507  		}
   508  	}
   509  	src := `package testaccountstate
   510  	  import (
   511  		  "github.com/nspcc-dev/neo-go/pkg/interop/native/neo"
   512  		  "github.com/nspcc-dev/neo-go/pkg/interop"
   513  	  )
   514  	  func GetLastGasPerVote() int {
   515  		  accState := neo.GetAccountState(interop.Hash160{` + hashAStr + `})
   516  		  if accState == nil {
   517  			  panic("nil state")
   518  		  }
   519  		  return accState.LastGasPerVote
   520  	  }`
   521  	ctr := neotest.CompileSource(t, e.Validator.ScriptHash(), strings.NewReader(src), &compiler.Options{
   522  		Name: "testaccountstate_contract",
   523  	})
   524  	e.DeployContract(t, ctr, nil)
   525  
   526  	const (
   527  		GasPerBlock      = 5
   528  		VoterRewardRatio = 80
   529  	)
   530  	expect := GasPerBlock * native.GASFactor * VoterRewardRatio / 100 * (uint64(e.Chain.BlockHeight()) / uint64(committeeSize))
   531  	expect = expect * uint64(committeeSize) / uint64(validatorSize+committeeSize) * native.NEOTotalSupply / uint64(amount)
   532  	ctrInvoker := e.NewInvoker(ctr.Hash, e.Committee)
   533  	ctrInvoker.Invoke(t, stackitem.Make(expect), "getLastGasPerVote")
   534  }
   535  
   536  func TestNEO_CommitteeBountyOnPersist(t *testing.T) {
   537  	neoCommitteeInvoker := newNeoCommitteeClient(t, 0)
   538  	e := neoCommitteeInvoker.Executor
   539  
   540  	hs, err := keys.NewPublicKeysFromStrings(e.Chain.GetConfig().StandbyCommittee)
   541  	require.NoError(t, err)
   542  	committeeSize := len(hs)
   543  
   544  	const singleBounty = 50000000
   545  	bs := map[int]int64{0: singleBounty}
   546  	checkBalances := func() {
   547  		for i := 0; i < committeeSize; i++ {
   548  			require.EqualValues(t, bs[i], e.Chain.GetUtilityTokenBalance(hs[i].GetScriptHash()).Int64(), i)
   549  		}
   550  	}
   551  	for i := 0; i < committeeSize*2; i++ {
   552  		e.AddNewBlock(t)
   553  		bs[(i+1)%committeeSize] += singleBounty
   554  		checkBalances()
   555  	}
   556  }
   557  
   558  func TestNEO_TransferOnPayment(t *testing.T) {
   559  	neoValidatorsInvoker := newNeoValidatorsClient(t)
   560  	e := neoValidatorsInvoker.Executor
   561  	managementValidatorsInvoker := e.ValidatorInvoker(e.NativeHash(t, nativenames.Management))
   562  
   563  	cs, _ := contracts.GetTestContractState(t, pathToInternalContracts, 1, 2, e.CommitteeHash)
   564  	cs.Hash = state.CreateContractHash(e.Validator.ScriptHash(), cs.NEF.Checksum, cs.Manifest.Name) // set proper hash
   565  	manifB, err := json.Marshal(cs.Manifest)
   566  	require.NoError(t, err)
   567  	nefB, err := cs.NEF.Bytes()
   568  	require.NoError(t, err)
   569  	si, err := cs.ToStackItem()
   570  	require.NoError(t, err)
   571  	managementValidatorsInvoker.Invoke(t, si, "deploy", nefB, manifB)
   572  
   573  	const amount int64 = 2
   574  
   575  	h := neoValidatorsInvoker.Invoke(t, true, "transfer", e.Validator.ScriptHash(), cs.Hash, amount, nil)
   576  	aer := e.GetTxExecResult(t, h)
   577  	require.Equal(t, 3, len(aer.Events)) // transfer + GAS claim for sender + onPayment
   578  	e.CheckTxNotificationEvent(t, h, 1, state.NotificationEvent{
   579  		ScriptHash: cs.Hash,
   580  		Name:       "LastPaymentNEP17",
   581  		Item: stackitem.NewArray([]stackitem.Item{
   582  			stackitem.NewByteArray(neoValidatorsInvoker.Hash.BytesBE()),
   583  			stackitem.NewByteArray(e.Validator.ScriptHash().BytesBE()),
   584  			stackitem.NewBigInteger(big.NewInt(amount)),
   585  			stackitem.Null{},
   586  		}),
   587  	})
   588  
   589  	h = neoValidatorsInvoker.Invoke(t, true, "transfer", e.Validator.ScriptHash(), cs.Hash, amount, nil)
   590  	aer = e.GetTxExecResult(t, h)
   591  	require.Equal(t, 5, len(aer.Events))                         // Now we must also have GAS claim for contract and corresponding `onPayment`.
   592  	e.CheckTxNotificationEvent(t, h, 1, state.NotificationEvent{ // onPayment for NEO transfer
   593  		ScriptHash: cs.Hash,
   594  		Name:       "LastPaymentNEP17",
   595  		Item: stackitem.NewArray([]stackitem.Item{
   596  			stackitem.NewByteArray(e.NativeHash(t, nativenames.Neo).BytesBE()),
   597  			stackitem.NewByteArray(e.Validator.ScriptHash().BytesBE()),
   598  			stackitem.NewBigInteger(big.NewInt(amount)),
   599  			stackitem.Null{},
   600  		}),
   601  	})
   602  	e.CheckTxNotificationEvent(t, h, 4, state.NotificationEvent{ // onPayment for GAS claim
   603  		ScriptHash: cs.Hash,
   604  		Name:       "LastPaymentNEP17",
   605  		Item: stackitem.NewArray([]stackitem.Item{
   606  			stackitem.NewByteArray(e.NativeHash(t, nativenames.Gas).BytesBE()),
   607  			stackitem.Null{},
   608  			stackitem.NewBigInteger(big.NewInt(1)),
   609  			stackitem.Null{},
   610  		}),
   611  	})
   612  }
   613  
   614  func TestNEO_Roundtrip(t *testing.T) {
   615  	neoValidatorsInvoker := newNeoValidatorsClient(t)
   616  	e := neoValidatorsInvoker.Executor
   617  	validatorH := neoValidatorsInvoker.Validator.ScriptHash()
   618  
   619  	initialBalance, initialHeight := e.Chain.GetGoverningTokenBalance(validatorH)
   620  	require.NotNil(t, initialBalance)
   621  
   622  	t.Run("bad: amount > initial balance", func(t *testing.T) {
   623  		h := neoValidatorsInvoker.Invoke(t, false, "transfer", validatorH, validatorH, initialBalance.Int64()+1, nil)
   624  		aer, err := e.Chain.GetAppExecResults(h, trigger.Application)
   625  		require.NoError(t, err)
   626  		require.Equal(t, 0, len(aer[0].Events)) // failed transfer => no events
   627  		// check balance and height were not changed
   628  		updatedBalance, updatedHeight := e.Chain.GetGoverningTokenBalance(validatorH)
   629  		require.Equal(t, initialBalance, updatedBalance)
   630  		require.Equal(t, initialHeight, updatedHeight)
   631  	})
   632  
   633  	t.Run("good: amount == initial balance", func(t *testing.T) {
   634  		h := neoValidatorsInvoker.Invoke(t, true, "transfer", validatorH, validatorH, initialBalance.Int64(), nil)
   635  		aer, err := e.Chain.GetAppExecResults(h, trigger.Application)
   636  		require.NoError(t, err)
   637  		require.Equal(t, 2, len(aer[0].Events)) // roundtrip + GAS claim
   638  		// check balance wasn't changed and height was updated
   639  		updatedBalance, updatedHeight := e.Chain.GetGoverningTokenBalance(validatorH)
   640  		require.Equal(t, initialBalance, updatedBalance)
   641  		require.Equal(t, e.Chain.BlockHeight(), updatedHeight)
   642  	})
   643  }
   644  
   645  func TestNEO_TransferZeroWithZeroBalance(t *testing.T) {
   646  	neoValidatorsInvoker := newNeoValidatorsClient(t)
   647  	e := neoValidatorsInvoker.Executor
   648  
   649  	check := func(t *testing.T, roundtrip bool) {
   650  		acc := neoValidatorsInvoker.WithSigners(e.NewAccount(t))
   651  		accH := acc.Signers[0].ScriptHash()
   652  		to := accH
   653  		if !roundtrip {
   654  			to = random.Uint160()
   655  		}
   656  		h := acc.Invoke(t, true, "transfer", accH, to, int64(0), nil)
   657  		aer, err := e.Chain.GetAppExecResults(h, trigger.Application)
   658  		require.NoError(t, err)
   659  		require.Equal(t, 1, len(aer[0].Events))                                                                       // roundtrip/transfer only, no GAS claim
   660  		require.Equal(t, stackitem.NewBigInteger(big.NewInt(0)), aer[0].Events[0].Item.Value().([]stackitem.Item)[2]) // amount is 0
   661  		// check balance wasn't changed and height was updated
   662  		updatedBalance, updatedHeight := e.Chain.GetGoverningTokenBalance(accH)
   663  		require.Equal(t, int64(0), updatedBalance.Int64())
   664  		require.Equal(t, uint32(0), updatedHeight)
   665  	}
   666  	t.Run("roundtrip: amount == initial balance == 0", func(t *testing.T) {
   667  		check(t, true)
   668  	})
   669  	t.Run("non-roundtrip: amount == initial balance == 0", func(t *testing.T) {
   670  		check(t, false)
   671  	})
   672  }
   673  
   674  func TestNEO_TransferZeroWithNonZeroBalance(t *testing.T) {
   675  	neoValidatorsInvoker := newNeoValidatorsClient(t)
   676  	e := neoValidatorsInvoker.Executor
   677  
   678  	check := func(t *testing.T, roundtrip bool) {
   679  		acc := e.NewAccount(t)
   680  		neoValidatorsInvoker.Invoke(t, true, "transfer", neoValidatorsInvoker.Validator.ScriptHash(), acc.ScriptHash(), int64(100), nil)
   681  		neoAccInvoker := neoValidatorsInvoker.WithSigners(acc)
   682  		initialBalance, _ := e.Chain.GetGoverningTokenBalance(acc.ScriptHash())
   683  		require.True(t, initialBalance.Sign() > 0)
   684  		to := acc.ScriptHash()
   685  		if !roundtrip {
   686  			to = random.Uint160()
   687  		}
   688  		h := neoAccInvoker.Invoke(t, true, "transfer", acc.ScriptHash(), to, int64(0), nil)
   689  
   690  		aer, err := e.Chain.GetAppExecResults(h, trigger.Application)
   691  		require.NoError(t, err)
   692  		require.Equal(t, 2, len(aer[0].Events))                                                                       // roundtrip + GAS claim
   693  		require.Equal(t, stackitem.NewBigInteger(big.NewInt(0)), aer[0].Events[0].Item.Value().([]stackitem.Item)[2]) // amount is 0
   694  		// check balance wasn't changed and height was updated
   695  		updatedBalance, updatedHeight := e.Chain.GetGoverningTokenBalance(acc.ScriptHash())
   696  		require.Equal(t, initialBalance, updatedBalance)
   697  		require.Equal(t, e.Chain.BlockHeight(), updatedHeight)
   698  	}
   699  	t.Run("roundtrip", func(t *testing.T) {
   700  		check(t, true)
   701  	})
   702  	t.Run("non-roundtrip", func(t *testing.T) {
   703  		check(t, false)
   704  	})
   705  }
   706  
   707  // https://github.com/nspcc-dev/neo-go/issues/3190
   708  func TestNEO_TransferNonZeroWithZeroBalance(t *testing.T) {
   709  	neoValidatorsInvoker := newNeoValidatorsClient(t)
   710  	e := neoValidatorsInvoker.Executor
   711  
   712  	acc := neoValidatorsInvoker.WithSigners(e.NewAccount(t))
   713  	accH := acc.Signers[0].ScriptHash()
   714  	h := acc.Invoke(t, false, "transfer", accH, accH, int64(5), nil)
   715  	aer := e.CheckHalt(t, h, stackitem.Make(false))
   716  	require.Equal(t, 0, len(aer.Events))
   717  	// check balance wasn't changed and height was not updated
   718  	updatedBalance, updatedHeight := e.Chain.GetGoverningTokenBalance(accH)
   719  	require.Equal(t, int64(0), updatedBalance.Int64())
   720  	require.Equal(t, uint32(0), updatedHeight)
   721  }
   722  
   723  func TestNEO_CalculateBonus(t *testing.T) {
   724  	neoCommitteeInvoker := newNeoCommitteeClient(t, 10_0000_0000)
   725  	e := neoCommitteeInvoker.Executor
   726  	neoValidatorsInvoker := neoCommitteeInvoker.WithSigners(e.Validator)
   727  
   728  	acc := neoValidatorsInvoker.WithSigners(e.NewAccount(t))
   729  	accH := acc.Signers[0].ScriptHash()
   730  	rewardDistance := 10
   731  
   732  	t.Run("Zero", func(t *testing.T) {
   733  		initialGASBalance := e.Chain.GetUtilityTokenBalance(accH)
   734  		for i := 0; i < rewardDistance; i++ {
   735  			e.AddNewBlock(t)
   736  		}
   737  		// Claim GAS, but there's no NEO on the account, so no GAS should be earned.
   738  		h := acc.Invoke(t, true, "transfer", accH, accH, 0, nil)
   739  		claimTx, _ := e.GetTransaction(t, h)
   740  
   741  		e.CheckGASBalance(t, accH, big.NewInt(initialGASBalance.Int64()-claimTx.SystemFee-claimTx.NetworkFee))
   742  	})
   743  
   744  	t.Run("Many blocks", func(t *testing.T) {
   745  		amount := 100
   746  		defaultGASParBlock := 5
   747  		newGASPerBlock := 1
   748  
   749  		initialGASBalance := e.Chain.GetUtilityTokenBalance(accH)
   750  
   751  		// Five blocks of NEO owning with default GasPerBlockValue.
   752  		neoValidatorsInvoker.Invoke(t, true, "transfer", e.Validator.ScriptHash(), accH, amount, nil)
   753  		for i := 0; i < rewardDistance/2-2; i++ {
   754  			e.AddNewBlock(t)
   755  		}
   756  		neoCommitteeInvoker.Invoke(t, stackitem.Null{}, "setGasPerBlock", newGASPerBlock*native.GASFactor)
   757  
   758  		// Five blocks more with modified GasPerBlock value.
   759  		for i := 0; i < rewardDistance/2; i++ {
   760  			e.AddNewBlock(t)
   761  		}
   762  
   763  		// GAS claim for the last 10 blocks of NEO owning.
   764  		h := acc.Invoke(t, true, "transfer", accH, accH, amount, nil)
   765  		claimTx, _ := e.GetTransaction(t, h)
   766  
   767  		firstPart := int64(amount*rewardDistance/2*defaultGASParBlock) / int64(rewardDistance)
   768  		secondPart := int64(amount*rewardDistance/2*newGASPerBlock) / int64(rewardDistance)
   769  		e.CheckGASBalance(t, accH, big.NewInt(initialGASBalance.Int64()-
   770  			claimTx.SystemFee-claimTx.NetworkFee + +firstPart + secondPart))
   771  	})
   772  }
   773  
   774  func TestNEO_GetCandidates(t *testing.T) {
   775  	neoCommitteeInvoker := newNeoCommitteeClient(t, 100_0000_0000)
   776  	neoValidatorsInvoker := neoCommitteeInvoker.WithSigners(neoCommitteeInvoker.Validator)
   777  	policyInvoker := neoCommitteeInvoker.CommitteeInvoker(neoCommitteeInvoker.NativeHash(t, nativenames.Policy))
   778  	e := neoCommitteeInvoker.Executor
   779  
   780  	cfg := e.Chain.GetConfig()
   781  	candidatesCount := cfg.GetCommitteeSize(0) - 1
   782  
   783  	// Register a set of candidates and vote for them.
   784  	voters := make([]neotest.Signer, candidatesCount)
   785  	candidates := make([]neotest.Signer, candidatesCount)
   786  	for i := 0; i < candidatesCount; i++ {
   787  		voters[i] = e.NewAccount(t, 10_0000_0000)
   788  		candidates[i] = e.NewAccount(t, 2000_0000_0000) // enough for one registration
   789  	}
   790  	txes := make([]*transaction.Transaction, 0, candidatesCount*3)
   791  	for i := 0; i < candidatesCount; i++ {
   792  		transferTx := neoValidatorsInvoker.PrepareInvoke(t, "transfer", e.Validator.ScriptHash(), voters[i].(neotest.SingleSigner).Account().PrivateKey().GetScriptHash(), int64(candidatesCount+1-i)*1000000, nil)
   793  		txes = append(txes, transferTx)
   794  		registerTx := neoValidatorsInvoker.WithSigners(candidates[i]).PrepareInvoke(t, "registerCandidate", candidates[i].(neotest.SingleSigner).Account().PublicKey().Bytes())
   795  		txes = append(txes, registerTx)
   796  		voteTx := neoValidatorsInvoker.WithSigners(voters[i]).PrepareInvoke(t, "vote", voters[i].(neotest.SingleSigner).Account().PrivateKey().GetScriptHash(), candidates[i].(neotest.SingleSigner).Account().PublicKey().Bytes())
   797  		txes = append(txes, voteTx)
   798  	}
   799  
   800  	neoValidatorsInvoker.AddNewBlock(t, txes...)
   801  	for _, tx := range txes {
   802  		e.CheckHalt(t, tx.Hash(), stackitem.Make(true)) // luckily, both `transfer`, `registerCandidate` and `vote` return boolean values
   803  	}
   804  	expected := make([]stackitem.Item, candidatesCount)
   805  	for i := range expected {
   806  		pub := candidates[i].(neotest.SingleSigner).Account().PublicKey().Bytes()
   807  		v := stackitem.NewBigInteger(big.NewInt(int64(candidatesCount-i+1) * 1000000))
   808  		expected[i] = stackitem.NewStruct([]stackitem.Item{
   809  			stackitem.NewByteArray(pub),
   810  			v,
   811  		})
   812  		neoCommitteeInvoker.Invoke(t, v, "getCandidateVote", pub)
   813  	}
   814  	sort.Slice(expected, func(i, j int) bool {
   815  		return bytes.Compare(expected[i].Value().([]stackitem.Item)[0].Value().([]byte), expected[j].Value().([]stackitem.Item)[0].Value().([]byte)) < 0
   816  	})
   817  	neoCommitteeInvoker.Invoke(t, stackitem.NewArray(expected), "getCandidates")
   818  
   819  	// Check that GetAllCandidates works the same way as GetCandidates.
   820  	checkGetAllCandidates := func(t *testing.T, expected []stackitem.Item) {
   821  		for i := 0; i < len(expected)+1; i++ {
   822  			w := io.NewBufBinWriter()
   823  			emit.AppCall(w.BinWriter, neoCommitteeInvoker.Hash, "getAllCandidates", callflag.All)
   824  			for j := 0; j < i+1; j++ {
   825  				emit.Opcodes(w.BinWriter, opcode.DUP)
   826  				emit.Syscall(w.BinWriter, interopnames.SystemIteratorNext)
   827  				emit.Opcodes(w.BinWriter, opcode.DROP) // drop the value returned from Next.
   828  			}
   829  			emit.Syscall(w.BinWriter, interopnames.SystemIteratorValue)
   830  			require.NoError(t, w.Err)
   831  			h := neoCommitteeInvoker.InvokeScript(t, w.Bytes(), neoCommitteeInvoker.Signers)
   832  			if i < len(expected) {
   833  				e.CheckHalt(t, h, expected[i])
   834  			} else {
   835  				e.CheckFault(t, h, "iterator index out of range") // ensure there are no extra elements.
   836  			}
   837  			w.Reset()
   838  		}
   839  	}
   840  	checkGetAllCandidates(t, expected)
   841  
   842  	// Block candidate and check it won't be returned from getCandidates and getAllCandidates.
   843  	unlucky := candidates[len(candidates)-1].(neotest.SingleSigner).Account().PublicKey()
   844  	policyInvoker.Invoke(t, true, "blockAccount", unlucky.GetScriptHash())
   845  	for i := range expected {
   846  		if bytes.Equal(expected[i].Value().([]stackitem.Item)[0].Value().([]byte), unlucky.Bytes()) {
   847  			if i != len(expected)-1 {
   848  				expected = append(expected[:i], expected[i+1:]...)
   849  			} else {
   850  				expected = expected[:i]
   851  			}
   852  			break
   853  		}
   854  	}
   855  	neoCommitteeInvoker.Invoke(t, expected, "getCandidates")
   856  	checkGetAllCandidates(t, expected)
   857  }