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

     1  package core_test
     2  
     3  import (
     4  	"encoding/binary"
     5  	"errors"
     6  	"fmt"
     7  	"math/big"
     8  	"path/filepath"
     9  	"sort"
    10  	"strings"
    11  	"testing"
    12  	"time"
    13  
    14  	"github.com/nspcc-dev/neo-go/internal/basicchain"
    15  	"github.com/nspcc-dev/neo-go/internal/contracts"
    16  	"github.com/nspcc-dev/neo-go/internal/random"
    17  	"github.com/nspcc-dev/neo-go/internal/testchain"
    18  	"github.com/nspcc-dev/neo-go/pkg/compiler"
    19  	"github.com/nspcc-dev/neo-go/pkg/config"
    20  	"github.com/nspcc-dev/neo-go/pkg/config/netmode"
    21  	"github.com/nspcc-dev/neo-go/pkg/core"
    22  	"github.com/nspcc-dev/neo-go/pkg/core/block"
    23  	"github.com/nspcc-dev/neo-go/pkg/core/dao"
    24  	"github.com/nspcc-dev/neo-go/pkg/core/fee"
    25  	"github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames"
    26  	"github.com/nspcc-dev/neo-go/pkg/core/mempool"
    27  	"github.com/nspcc-dev/neo-go/pkg/core/native"
    28  	"github.com/nspcc-dev/neo-go/pkg/core/native/nativehashes"
    29  	"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
    30  	"github.com/nspcc-dev/neo-go/pkg/core/native/nativeprices"
    31  	"github.com/nspcc-dev/neo-go/pkg/core/native/noderoles"
    32  	"github.com/nspcc-dev/neo-go/pkg/core/state"
    33  	"github.com/nspcc-dev/neo-go/pkg/core/storage"
    34  	"github.com/nspcc-dev/neo-go/pkg/core/storage/dbconfig"
    35  	"github.com/nspcc-dev/neo-go/pkg/core/transaction"
    36  	"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
    37  	"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
    38  	"github.com/nspcc-dev/neo-go/pkg/encoding/address"
    39  	"github.com/nspcc-dev/neo-go/pkg/io"
    40  	"github.com/nspcc-dev/neo-go/pkg/neotest"
    41  	"github.com/nspcc-dev/neo-go/pkg/neotest/chain"
    42  	"github.com/nspcc-dev/neo-go/pkg/smartcontract"
    43  	"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
    44  	"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
    45  	"github.com/nspcc-dev/neo-go/pkg/util"
    46  	"github.com/nspcc-dev/neo-go/pkg/vm/emit"
    47  	"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
    48  	"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
    49  	"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
    50  	"github.com/nspcc-dev/neo-go/pkg/wallet"
    51  	"github.com/stretchr/testify/assert"
    52  	"github.com/stretchr/testify/require"
    53  )
    54  
    55  func newLevelDBForTestingWithPath(t testing.TB, dbPath string) (storage.Store, string) {
    56  	if dbPath == "" {
    57  		dbPath = t.TempDir()
    58  	}
    59  	dbOptions := dbconfig.LevelDBOptions{
    60  		DataDirectoryPath: dbPath,
    61  	}
    62  	newLevelStore, err := storage.NewLevelDBStore(dbOptions)
    63  	require.Nil(t, err, "NewLevelDBStore error")
    64  	return newLevelStore, dbPath
    65  }
    66  
    67  func TestBlockchain_StartFromExistingDB(t *testing.T) {
    68  	ps, path := newLevelDBForTestingWithPath(t, "")
    69  	customConfig := func(c *config.Blockchain) {
    70  		c.StateRootInHeader = true // Need for P2PStateExchangeExtensions check.
    71  		c.P2PSigExtensions = true  // Need for basic chain initializer.
    72  	}
    73  	bc, validators, committee, err := chain.NewMultiWithCustomConfigAndStoreNoCheck(t, customConfig, ps)
    74  	require.NoError(t, err)
    75  	go bc.Run()
    76  	e := neotest.NewExecutor(t, bc, validators, committee)
    77  	basicchain.Init(t, "../../", e)
    78  	require.True(t, bc.BlockHeight() > 5, "ensure that basic chain is correctly initialised")
    79  
    80  	// Information for further tests.
    81  	h := bc.BlockHeight()
    82  	cryptoLibHash, err := bc.GetNativeContractScriptHash(nativenames.CryptoLib)
    83  	require.NoError(t, err)
    84  	cryptoLibState := bc.GetContractState(cryptoLibHash)
    85  	require.NotNil(t, cryptoLibState)
    86  	var (
    87  		managementID             = -1
    88  		managementContractPrefix = 8
    89  	)
    90  
    91  	bc.Close() // Ensure persist is done and persistent store is properly closed.
    92  
    93  	newPS := func(t *testing.T) storage.Store {
    94  		ps, _ = newLevelDBForTestingWithPath(t, path)
    95  		t.Cleanup(func() { require.NoError(t, ps.Close()) })
    96  		return ps
    97  	}
    98  	t.Run("mismatch storage version", func(t *testing.T) {
    99  		ps = newPS(t)
   100  		cache := storage.NewMemCachedStore(ps) // Extra wrapper to avoid good DB corruption.
   101  		d := dao.NewSimple(cache, bc.GetConfig().StateRootInHeader)
   102  		d.PutVersion(dao.Version{
   103  			Value: "0.0.0",
   104  		})
   105  		_, err := d.Persist() // Persist to `cache` wrapper.
   106  		require.NoError(t, err)
   107  		_, _, _, err = chain.NewMultiWithCustomConfigAndStoreNoCheck(t, customConfig, cache)
   108  		require.Error(t, err)
   109  		require.True(t, strings.Contains(err.Error(), "storage version mismatch"), err)
   110  	})
   111  	t.Run("mismatch StateRootInHeader", func(t *testing.T) {
   112  		ps = newPS(t)
   113  		_, _, _, err := chain.NewMultiWithCustomConfigAndStoreNoCheck(t, func(c *config.Blockchain) {
   114  			customConfig(c)
   115  			c.StateRootInHeader = false
   116  		}, ps)
   117  		require.Error(t, err)
   118  		require.True(t, strings.Contains(err.Error(), "StateRootInHeader setting mismatch"), err)
   119  	})
   120  	t.Run("mismatch P2PSigExtensions", func(t *testing.T) {
   121  		ps = newPS(t)
   122  		_, _, _, err := chain.NewMultiWithCustomConfigAndStoreNoCheck(t, func(c *config.Blockchain) {
   123  			customConfig(c)
   124  			c.P2PSigExtensions = false
   125  		}, ps)
   126  		require.Error(t, err)
   127  		require.True(t, strings.Contains(err.Error(), "P2PSigExtensions setting mismatch"), err)
   128  	})
   129  	t.Run("mismatch P2PStateExchangeExtensions", func(t *testing.T) {
   130  		ps = newPS(t)
   131  		_, _, _, err := chain.NewMultiWithCustomConfigAndStoreNoCheck(t, func(c *config.Blockchain) {
   132  			customConfig(c)
   133  			c.StateRootInHeader = true
   134  			c.P2PStateExchangeExtensions = true
   135  		}, ps)
   136  		require.Error(t, err)
   137  		require.True(t, strings.Contains(err.Error(), "P2PStateExchangeExtensions setting mismatch"), err)
   138  	})
   139  	t.Run("mismatch KeepOnlyLatestState", func(t *testing.T) {
   140  		ps = newPS(t)
   141  		_, _, _, err := chain.NewMultiWithCustomConfigAndStoreNoCheck(t, func(c *config.Blockchain) {
   142  			customConfig(c)
   143  			c.Ledger.KeepOnlyLatestState = true
   144  		}, ps)
   145  		require.Error(t, err)
   146  		require.True(t, strings.Contains(err.Error(), "KeepOnlyLatestState setting mismatch"), err)
   147  	})
   148  	t.Run("Magic mismatch", func(t *testing.T) {
   149  		ps = newPS(t)
   150  		_, _, _, err := chain.NewMultiWithCustomConfigAndStoreNoCheck(t, func(c *config.Blockchain) {
   151  			customConfig(c)
   152  			c.Magic = 100500
   153  		}, ps)
   154  		require.Error(t, err)
   155  		require.True(t, strings.Contains(err.Error(), "protocol configuration Magic mismatch"), err)
   156  	})
   157  	t.Run("corrupted headers", func(t *testing.T) {
   158  		ps = newPS(t)
   159  
   160  		// Corrupt headers hashes batch.
   161  		cache := storage.NewMemCachedStore(ps) // Extra wrapper to avoid good DB corruption.
   162  		// Make the chain think we're at 2000+ which will trigger page 0 read.
   163  		buf := io.NewBufBinWriter()
   164  		buf.WriteBytes(util.Uint256{}.BytesLE())
   165  		buf.WriteU32LE(2000)
   166  		cache.Put([]byte{byte(storage.SYSCurrentHeader)}, buf.Bytes())
   167  
   168  		_, _, _, err := chain.NewMultiWithCustomConfigAndStoreNoCheck(t, customConfig, cache)
   169  		require.Error(t, err)
   170  		require.True(t, strings.Contains(err.Error(), "failed to retrieve header hash page"), err)
   171  	})
   172  	t.Run("corrupted current header height", func(t *testing.T) {
   173  		ps = newPS(t)
   174  
   175  		// Remove current header.
   176  		cache := storage.NewMemCachedStore(ps) // Extra wrapper to avoid good DB corruption.
   177  		cache.Delete([]byte{byte(storage.SYSCurrentHeader)})
   178  
   179  		_, _, _, err := chain.NewMultiWithCustomConfigAndStoreNoCheck(t, customConfig, cache)
   180  		require.Error(t, err)
   181  		require.True(t, strings.Contains(err.Error(), "failed to retrieve current header"), err)
   182  	})
   183  	t.Run("missing last batch of 2000 headers and missing last header", func(t *testing.T) {
   184  		ps = newPS(t)
   185  
   186  		// Remove latest headers hashes batch and current header.
   187  		cache := storage.NewMemCachedStore(ps) // Extra wrapper to avoid good DB corruption.
   188  		cache.Delete([]byte{byte(storage.IXHeaderHashList)})
   189  		currHeaderInfo, err := cache.Get([]byte{byte(storage.SYSCurrentHeader)})
   190  		require.NoError(t, err)
   191  		currHeaderHash, err := util.Uint256DecodeBytesLE(currHeaderInfo[:32])
   192  		require.NoError(t, err)
   193  		cache.Delete(append([]byte{byte(storage.DataExecutable)}, currHeaderHash.BytesBE()...))
   194  
   195  		_, _, _, err = chain.NewMultiWithCustomConfigAndStoreNoCheck(t, customConfig, cache)
   196  		require.Error(t, err)
   197  		require.True(t, strings.Contains(err.Error(), "could not get header"), err)
   198  	})
   199  	t.Run("missing last block", func(t *testing.T) {
   200  		ps = newPS(t)
   201  
   202  		// Remove current block from storage.
   203  		cache := storage.NewMemCachedStore(ps) // Extra wrapper to avoid good DB corruption.
   204  		cache.Delete([]byte{byte(storage.SYSCurrentBlock)})
   205  
   206  		_, _, _, err := chain.NewMultiWithCustomConfigAndStoreNoCheck(t, customConfig, cache)
   207  		require.Error(t, err)
   208  		require.True(t, strings.Contains(err.Error(), "failed to retrieve current block height"), err)
   209  	})
   210  	t.Run("missing last stateroot", func(t *testing.T) {
   211  		ps = newPS(t)
   212  
   213  		// Remove latest stateroot from storage.
   214  		cache := storage.NewMemCachedStore(ps) // Extra wrapper to avoid good DB corruption.
   215  		key := make([]byte, 5)
   216  		key[0] = byte(storage.DataMPTAux)
   217  		binary.BigEndian.PutUint32(key[1:], h)
   218  		cache.Delete(key)
   219  
   220  		_, _, _, err := chain.NewMultiWithCustomConfigAndStoreNoCheck(t, customConfig, cache)
   221  		require.Error(t, err)
   222  		require.True(t, strings.Contains(err.Error(), "can't init MPT at height"), err)
   223  	})
   224  	t.Run("failed native Management initialisation", func(t *testing.T) {
   225  		ps = newPS(t)
   226  
   227  		// Corrupt serialised CryptoLib state.
   228  		cache := storage.NewMemCachedStore(ps) // Extra wrapper to avoid good DB corruption.
   229  		key := make([]byte, 1+4+1+20)
   230  		key[0] = byte(storage.STStorage)
   231  		binary.LittleEndian.PutUint32(key[1:], uint32(managementID))
   232  		key[5] = byte(managementContractPrefix)
   233  		copy(key[6:], cryptoLibHash.BytesBE())
   234  		cache.Put(key, []byte{1, 2, 3})
   235  
   236  		_, _, _, err := chain.NewMultiWithCustomConfigAndStoreNoCheck(t, customConfig, cache)
   237  		require.Error(t, err)
   238  		require.True(t, strings.Contains(err.Error(), "can't init natives cache: failed to initialize cache for ContractManagement"), err)
   239  	})
   240  	t.Run("invalid native contract activation", func(t *testing.T) {
   241  		ps = newPS(t)
   242  
   243  		// Remove CryptoLib from storage.
   244  		cache := storage.NewMemCachedStore(ps) // Extra wrapper to avoid good DB corruption.
   245  		key := make([]byte, 1+4+1+20)
   246  		key[0] = byte(storage.STStorage)
   247  		binary.LittleEndian.PutUint32(key[1:], uint32(managementID))
   248  		key[5] = byte(managementContractPrefix)
   249  		copy(key[6:], cryptoLibHash.BytesBE())
   250  		cache.Delete(key)
   251  
   252  		_, _, _, err := chain.NewMultiWithCustomConfigAndStoreNoCheck(t, customConfig, cache)
   253  		require.Error(t, err)
   254  		require.True(t, strings.Contains(err.Error(), fmt.Sprintf("native contract %s is not stored, but should be active at height %d according to config", nativenames.CryptoLib, h)), err)
   255  	})
   256  	t.Run("stored and autogenerated native contract's states mismatch", func(t *testing.T) {
   257  		ps = newPS(t)
   258  
   259  		// Change stored CryptoLib state.
   260  		cache := storage.NewMemCachedStore(ps) // Extra wrapper to avoid good DB corruption.
   261  		key := make([]byte, 1+4+1+20)
   262  		key[0] = byte(storage.STStorage)
   263  		binary.LittleEndian.PutUint32(key[1:], uint32(managementID))
   264  		key[5] = byte(managementContractPrefix)
   265  		copy(key[6:], cryptoLibHash.BytesBE())
   266  		cs := *cryptoLibState
   267  		cs.ID = -123
   268  		csBytes, err := stackitem.SerializeConvertible(&cs)
   269  		require.NoError(t, err)
   270  		cache.Put(key, csBytes)
   271  
   272  		_, _, _, err = chain.NewMultiWithCustomConfigAndStoreNoCheck(t, customConfig, cache)
   273  		require.Error(t, err)
   274  		require.True(t, strings.Contains(err.Error(), fmt.Sprintf("native %s: version mismatch for the latest hardfork Cockatrice (stored contract state differs from autogenerated one)", nativenames.CryptoLib)), err)
   275  	})
   276  
   277  	t.Run("good", func(t *testing.T) {
   278  		ps = newPS(t)
   279  		_, _, _, err := chain.NewMultiWithCustomConfigAndStoreNoCheck(t, customConfig, ps)
   280  		require.NoError(t, err)
   281  	})
   282  }
   283  
   284  // TestBlockchain_InitializeNeoCache_Bug3181 is aimed to reproduce and check situation
   285  // when panic occures on native Neo cache initialization due to access to native Policy
   286  // cache when it's not yet initialized to recalculate candidates.
   287  func TestBlockchain_InitializeNeoCache_Bug3181(t *testing.T) {
   288  	ps, path := newLevelDBForTestingWithPath(t, "")
   289  	bc, validators, committee, err := chain.NewMultiWithCustomConfigAndStoreNoCheck(t, nil, ps)
   290  	require.NoError(t, err)
   291  	go bc.Run()
   292  	e := neotest.NewExecutor(t, bc, validators, committee)
   293  
   294  	// Add at least one registered candidate to enable candidates Policy check.
   295  	acc := e.NewAccount(t, 10000_0000_0000) // block #1
   296  	neo := e.NewInvoker(e.NativeHash(t, nativenames.Neo), acc)
   297  	neo.Invoke(t, true, "registerCandidate", acc.(neotest.SingleSigner).Account().PublicKey().Bytes()) // block #2
   298  
   299  	// Put some empty blocks to reach N-1 block height, so that newEpoch cached
   300  	// values of native Neo contract require an update on the subsequent cache
   301  	// initialization.
   302  	for i := 0; i < len(bc.GetConfig().StandbyCommittee)-1-2; i++ {
   303  		e.AddNewBlock(t)
   304  	}
   305  	bc.Close() // Ensure persist is done and persistent store is properly closed.
   306  
   307  	ps, _ = newLevelDBForTestingWithPath(t, path)
   308  	t.Cleanup(func() { require.NoError(t, ps.Close()) })
   309  
   310  	// Start chain from the existing database that should trigger an update of native
   311  	// Neo newEpoch* cached values during initializaition. This update requires candidates
   312  	// list recalculation and policies checks, thus, access to native Policy cache
   313  	// that is not yet initialized by that moment.
   314  	require.NotPanics(t, func() {
   315  		_, _, _, err = chain.NewMultiWithCustomConfigAndStoreNoCheck(t, nil, ps)
   316  		require.NoError(t, err)
   317  	})
   318  }
   319  
   320  // TestBlockchain_InitializeNeoCache_Bug3424 ensures that Neo cache (new epoch
   321  // committee and stand by validators) is properly initialized after node restart
   322  // at the dBFT epoch boundary.
   323  func TestBlockchain_InitializeNeoCache_Bug3424(t *testing.T) {
   324  	ps, path := newLevelDBForTestingWithPath(t, "")
   325  	bc, validators, committee, err := chain.NewMultiWithCustomConfigAndStoreNoCheck(t, nil, ps)
   326  	require.NoError(t, err)
   327  	go bc.Run()
   328  	e := neotest.NewExecutor(t, bc, validators, committee)
   329  	cfg := e.Chain.GetConfig()
   330  	committeeSize := cfg.GetCommitteeSize(0)
   331  	validatorsCount := cfg.GetNumOfCNs(0)
   332  
   333  	// Stand by committee drives the chain.
   334  	standBySorted, err := keys.NewPublicKeysFromStrings(e.Chain.GetConfig().StandbyCommittee)
   335  	require.NoError(t, err)
   336  	standBySorted = standBySorted[:validatorsCount]
   337  	sort.Sort(standBySorted)
   338  	pubs := e.Chain.ComputeNextBlockValidators()
   339  	require.Equal(t, standBySorted, keys.PublicKeys(pubs))
   340  
   341  	// Move from stand by committee to the elected nodes.
   342  	e.ValidatorInvoker(e.NativeHash(t, nativenames.Gas)).Invoke(t, true, "transfer", e.Validator.ScriptHash(), e.CommitteeHash, 100_0000_0000, nil)
   343  	neoCommitteeInvoker := e.CommitteeInvoker(e.NativeHash(t, nativenames.Neo))
   344  	neoValidatorsInvoker := neoCommitteeInvoker.WithSigners(neoCommitteeInvoker.Validator)
   345  	policyInvoker := neoCommitteeInvoker.CommitteeInvoker(neoCommitteeInvoker.NativeHash(t, nativenames.Policy))
   346  
   347  	advanceChain := func(t *testing.T) {
   348  		for int(e.Chain.BlockHeight())%committeeSize != 0 {
   349  			neoCommitteeInvoker.AddNewBlock(t)
   350  		}
   351  	}
   352  	advanceChainToEpochBoundary := func(t *testing.T) {
   353  		for int(e.Chain.BlockHeight()+1)%committeeSize != 0 {
   354  			neoCommitteeInvoker.AddNewBlock(t)
   355  		}
   356  	}
   357  
   358  	// voters vote for candidates.
   359  	voters := make([]neotest.Signer, committeeSize+1)
   360  	candidates := make([]neotest.Signer, committeeSize+1)
   361  	for i := 0; i < committeeSize+1; i++ {
   362  		voters[i] = e.NewAccount(t, 10_0000_0000)
   363  		candidates[i] = e.NewAccount(t, 2000_0000_0000) // enough for one registration
   364  	}
   365  	txes := make([]*transaction.Transaction, 0, committeeSize*3)
   366  	for i := 0; i < committeeSize+1; i++ {
   367  		transferTx := neoValidatorsInvoker.PrepareInvoke(t, "transfer", e.Validator.ScriptHash(), voters[i].(neotest.SingleSigner).Account().PrivateKey().GetScriptHash(), int64(committeeSize+1-i)*1000000, nil)
   368  		txes = append(txes, transferTx)
   369  		registerTx := neoValidatorsInvoker.WithSigners(candidates[i]).PrepareInvoke(t, "registerCandidate", candidates[i].(neotest.SingleSigner).Account().PublicKey().Bytes())
   370  		txes = append(txes, registerTx)
   371  		voteTx := neoValidatorsInvoker.WithSigners(voters[i]).PrepareInvoke(t, "vote", voters[i].(neotest.SingleSigner).Account().PrivateKey().GetScriptHash(), candidates[i].(neotest.SingleSigner).Account().PublicKey().Bytes())
   372  		txes = append(txes, voteTx)
   373  	}
   374  	txes = append(txes, policyInvoker.PrepareInvoke(t, "blockAccount", candidates[len(candidates)-1].(neotest.SingleSigner).Account().ScriptHash()))
   375  	neoValidatorsInvoker.AddNewBlock(t, txes...)
   376  	for _, tx := range txes {
   377  		e.CheckHalt(t, tx.Hash(), stackitem.Make(true)) // luckily, both `transfer`, `registerCandidate` and `vote` return boolean values
   378  	}
   379  
   380  	// Ensure validators are properly updated.
   381  	advanceChain(t)
   382  	pubs = e.Chain.ComputeNextBlockValidators()
   383  	sortedCandidates := make(keys.PublicKeys, validatorsCount)
   384  	for i := range candidates[:validatorsCount] {
   385  		sortedCandidates[i] = candidates[i].(neotest.SingleSigner).Account().PublicKey()
   386  	}
   387  	sort.Sort(sortedCandidates)
   388  	require.EqualValues(t, sortedCandidates, keys.PublicKeys(pubs))
   389  
   390  	// Move to the last block in the epoch and restart the node.
   391  	advanceChainToEpochBoundary(t)
   392  	bc.Close() // Ensure persist is done and persistent store is properly closed.
   393  	ps, _ = newLevelDBForTestingWithPath(t, path)
   394  	t.Cleanup(func() { require.NoError(t, ps.Close()) })
   395  
   396  	// Start chain from the existing database that should trigger an update of native
   397  	// Neo newEpoch* cached values during initializaition. This update requires candidates
   398  	// list recalculation and caldidates policies checks.
   399  	bc, _, _, err = chain.NewMultiWithCustomConfigAndStoreNoCheck(t, nil, ps)
   400  	require.NoError(t, err)
   401  
   402  	pubs = bc.ComputeNextBlockValidators()
   403  	require.EqualValues(t, sortedCandidates, keys.PublicKeys(pubs))
   404  }
   405  
   406  // This test enables Notary native contract at non-zero height and checks that no
   407  // Notary cache initialization is performed before that height on node restart.
   408  /*
   409  func TestBlockchain_InitializeNativeCacheWrtNativeActivations(t *testing.T) {
   410  	const notaryEnabledHeight = 3
   411  	ps, path := newLevelDBForTestingWithPath(t, "")
   412  	customConfig := func(c *config.Blockchain) {
   413  		c.P2PSigExtensions = true
   414  		c.NativeUpdateHistories = make(map[string][]uint32)
   415  		for _, n := range []string{
   416  			nativenames.Neo,
   417  			nativenames.Gas,
   418  			nativenames.Designation,
   419  			nativenames.Management,
   420  			nativenames.CryptoLib,
   421  			nativenames.Ledger,
   422  			nativenames.Management,
   423  			nativenames.Oracle,
   424  			nativenames.Policy,
   425  			nativenames.StdLib,
   426  			nativenames.Notary,
   427  		} {
   428  			if n == nativenames.Notary {
   429  				c.NativeUpdateHistories[n] = []uint32{notaryEnabledHeight}
   430  			} else {
   431  				c.NativeUpdateHistories[n] = []uint32{0}
   432  			}
   433  		}
   434  	}
   435  	bc, validators, committee, err := chain.NewMultiWithCustomConfigAndStoreNoCheck(t, customConfig, ps)
   436  	require.NoError(t, err)
   437  	go bc.Run()
   438  	e := neotest.NewExecutor(t, bc, validators, committee)
   439  	e.AddNewBlock(t)
   440  	bc.Close() // Ensure persist is done and persistent store is properly closed.
   441  
   442  	ps, _ = newLevelDBForTestingWithPath(t, path)
   443  
   444  	// If NativeActivations are not taken into account during native cache initialization,
   445  	// bs.init() will panic on Notary cache initialization as it's not deployed yet.
   446  	require.NotPanics(t, func() {
   447  		bc, _, _, err = chain.NewMultiWithCustomConfigAndStoreNoCheck(t, customConfig, ps)
   448  		require.NoError(t, err)
   449  	})
   450  	go bc.Run()
   451  	defer bc.Close()
   452  	e = neotest.NewExecutor(t, bc, validators, committee)
   453  	h := e.Chain.BlockHeight()
   454  
   455  	// Notary isn't initialized yet, so accessing Notary cache should return error.
   456  	_, err = e.Chain.GetMaxNotValidBeforeDelta()
   457  	require.Error(t, err)
   458  
   459  	// Ensure Notary will be properly initialized and accessing Notary cache works
   460  	// as expected.
   461  	for i := 0; i < notaryEnabledHeight; i++ {
   462  		require.NotPanics(t, func() {
   463  			e.AddNewBlock(t)
   464  		}, h+uint32(i)+1)
   465  	}
   466  	_, err = e.Chain.GetMaxNotValidBeforeDelta()
   467  	require.NoError(t, err)
   468  }
   469  */
   470  
   471  func TestBlockchain_AddHeaders(t *testing.T) {
   472  	bc, acc := chain.NewSingleWithCustomConfig(t, func(c *config.Blockchain) {
   473  		c.StateRootInHeader = true
   474  	})
   475  	e := neotest.NewExecutor(t, bc, acc, acc)
   476  
   477  	newHeader := func(t *testing.T, index uint32, prevHash util.Uint256, timestamp uint64) *block.Header {
   478  		b := e.NewUnsignedBlock(t)
   479  		b.Index = index
   480  		b.PrevHash = prevHash
   481  		b.PrevStateRoot = util.Uint256{}
   482  		b.Timestamp = timestamp
   483  		e.SignBlock(b)
   484  		return &b.Header
   485  	}
   486  	b1 := e.NewUnsignedBlock(t)
   487  	h1 := &e.SignBlock(b1).Header
   488  	h2 := newHeader(t, h1.Index+1, h1.Hash(), h1.Timestamp+1)
   489  	h3 := newHeader(t, h2.Index+1, h2.Hash(), h2.Timestamp+1)
   490  
   491  	require.NoError(t, bc.AddHeaders())
   492  	require.NoError(t, bc.AddHeaders(h1, h2))
   493  	require.NoError(t, bc.AddHeaders(h2, h3))
   494  
   495  	assert.Equal(t, h3.Index, bc.HeaderHeight())
   496  	assert.Equal(t, uint32(0), bc.BlockHeight())
   497  	assert.Equal(t, h3.Hash(), bc.CurrentHeaderHash())
   498  
   499  	// Add them again, they should not be added.
   500  	require.NoError(t, bc.AddHeaders(h3, h2, h1))
   501  
   502  	assert.Equal(t, h3.Index, bc.HeaderHeight())
   503  	assert.Equal(t, uint32(0), bc.BlockHeight())
   504  	assert.Equal(t, h3.Hash(), bc.CurrentHeaderHash())
   505  
   506  	h4Bad := newHeader(t, h3.Index+1, h3.Hash().Reverse(), h3.Timestamp+1)
   507  	h5Bad := newHeader(t, h4Bad.Index+1, h4Bad.Hash(), h4Bad.Timestamp+1)
   508  
   509  	assert.Error(t, bc.AddHeaders(h4Bad, h5Bad))
   510  	assert.Equal(t, h3.Index, bc.HeaderHeight())
   511  	assert.Equal(t, uint32(0), bc.BlockHeight())
   512  	assert.Equal(t, h3.Hash(), bc.CurrentHeaderHash())
   513  
   514  	h4Bad2 := newHeader(t, h3.Index+1, h3.Hash().Reverse(), h3.Timestamp+1)
   515  	h4Bad2.Script.InvocationScript = []byte{}
   516  	assert.Error(t, bc.AddHeaders(h4Bad2))
   517  	assert.Equal(t, h3.Index, bc.HeaderHeight())
   518  	assert.Equal(t, uint32(0), bc.BlockHeight())
   519  	assert.Equal(t, h3.Hash(), bc.CurrentHeaderHash())
   520  }
   521  
   522  func TestBlockchain_AddBlockStateRoot(t *testing.T) {
   523  	bc, acc := chain.NewSingleWithCustomConfig(t, func(c *config.Blockchain) {
   524  		c.StateRootInHeader = true
   525  	})
   526  	e := neotest.NewExecutor(t, bc, acc, acc)
   527  
   528  	sr, err := bc.GetStateModule().GetStateRoot(bc.BlockHeight())
   529  	require.NoError(t, err)
   530  
   531  	b := e.NewUnsignedBlock(t)
   532  	b.StateRootEnabled = false
   533  	b.PrevStateRoot = util.Uint256{}
   534  	e.SignBlock(b)
   535  	err = bc.AddBlock(b)
   536  	require.ErrorIs(t, err, core.ErrHdrStateRootSetting)
   537  
   538  	u := sr.Root
   539  	u[0] ^= 0xFF
   540  	b = e.NewUnsignedBlock(t)
   541  	b.PrevStateRoot = u
   542  	e.SignBlock(b)
   543  	err = bc.AddBlock(b)
   544  	require.ErrorIs(t, err, core.ErrHdrInvalidStateRoot)
   545  
   546  	b = e.NewUnsignedBlock(t)
   547  	e.SignBlock(b)
   548  	require.NoError(t, bc.AddBlock(b))
   549  }
   550  
   551  func TestBlockchain_AddHeadersStateRoot(t *testing.T) {
   552  	bc, acc := chain.NewSingleWithCustomConfig(t, func(c *config.Blockchain) {
   553  		c.StateRootInHeader = true
   554  	})
   555  	e := neotest.NewExecutor(t, bc, acc, acc)
   556  
   557  	b := e.NewUnsignedBlock(t)
   558  	e.SignBlock(b)
   559  	h1 := b.Header
   560  	r := bc.GetStateModule().CurrentLocalStateRoot()
   561  
   562  	// invalid stateroot
   563  	h1.PrevStateRoot[0] ^= 0xFF
   564  	require.ErrorIs(t, bc.AddHeaders(&h1), core.ErrHdrInvalidStateRoot)
   565  
   566  	// valid stateroot
   567  	h1.PrevStateRoot = r
   568  	require.NoError(t, bc.AddHeaders(&h1))
   569  
   570  	// unable to verify stateroot (stateroot is computed for block #0 only => can
   571  	// verify stateroot of header #1 only) => just store the header
   572  	b = e.NewUnsignedBlock(t)
   573  	b.PrevHash = h1.Hash()
   574  	b.Timestamp = h1.Timestamp + 1
   575  	b.PrevStateRoot = util.Uint256{}
   576  	b.Index = h1.Index + 1
   577  	e.SignBlock(b)
   578  	require.NoError(t, bc.AddHeaders(&b.Header))
   579  }
   580  
   581  func TestBlockchain_AddBadBlock(t *testing.T) {
   582  	check := func(t *testing.T, b *block.Block, cfg func(c *config.Blockchain)) {
   583  		bc, _ := chain.NewSingleWithCustomConfig(t, cfg)
   584  		err := bc.AddBlock(b)
   585  		if cfg == nil {
   586  			require.Error(t, err)
   587  		} else {
   588  			require.NoError(t, err)
   589  		}
   590  	}
   591  	bc, acc := chain.NewSingle(t)
   592  	e := neotest.NewExecutor(t, bc, acc, acc)
   593  	neoHash := e.NativeHash(t, nativenames.Neo)
   594  
   595  	tx := e.NewUnsignedTx(t, neoHash, "transfer", acc.ScriptHash(), util.Uint160{1, 2, 3}, 1, nil)
   596  	tx.ValidUntilBlock = 0 // Intentionally make the transaction invalid.
   597  	e.SignTx(t, tx, -1, acc)
   598  	b := e.NewUnsignedBlock(t, tx)
   599  	e.SignBlock(b)
   600  	check(t, b, nil)
   601  	check(t, b, func(c *config.Blockchain) {
   602  		c.SkipBlockVerification = true
   603  	})
   604  
   605  	b = e.NewUnsignedBlock(t)
   606  	b.PrevHash = util.Uint256{} // Intentionally make block invalid.
   607  	e.SignBlock(b)
   608  	check(t, b, nil)
   609  	check(t, b, func(c *config.Blockchain) {
   610  		c.SkipBlockVerification = true
   611  	})
   612  
   613  	tx = e.NewUnsignedTx(t, neoHash, "transfer", acc.ScriptHash(), util.Uint160{1, 2, 3}, 1, nil) // Check the good tx.
   614  	e.SignTx(t, tx, -1, acc)
   615  	b = e.NewUnsignedBlock(t, tx)
   616  	e.SignBlock(b)
   617  	check(t, b, func(c *config.Blockchain) {
   618  		c.VerifyTransactions = true
   619  		c.SkipBlockVerification = false
   620  	})
   621  }
   622  
   623  func TestBlockchain_GetHeader(t *testing.T) {
   624  	bc, acc := chain.NewSingle(t)
   625  	e := neotest.NewExecutor(t, bc, acc, acc)
   626  
   627  	block := e.AddNewBlock(t)
   628  	hash := block.Hash()
   629  	header, err := bc.GetHeader(hash)
   630  	require.NoError(t, err)
   631  	assert.Equal(t, &block.Header, header)
   632  
   633  	b2 := e.NewUnsignedBlock(t)
   634  	_, err = bc.GetHeader(b2.Hash())
   635  	assert.Error(t, err)
   636  }
   637  
   638  func TestBlockchain_GetBlock(t *testing.T) {
   639  	bc, acc := chain.NewSingle(t)
   640  	e := neotest.NewExecutor(t, bc, acc, acc)
   641  	blocks := e.GenerateNewBlocks(t, 10)
   642  	neoValidatorInvoker := e.ValidatorInvoker(e.NativeHash(t, nativenames.Neo))
   643  
   644  	for i := 0; i < len(blocks); i++ {
   645  		block, err := bc.GetBlock(blocks[i].Hash())
   646  		require.NoErrorf(t, err, "can't get block %d: %s", i, err)
   647  		assert.Equal(t, blocks[i].Index, block.Index)
   648  		assert.Equal(t, blocks[i].Hash(), block.Hash())
   649  	}
   650  
   651  	t.Run("store only header", func(t *testing.T) {
   652  		t.Run("non-empty block", func(t *testing.T) {
   653  			tx := neoValidatorInvoker.PrepareInvoke(t, "transfer", acc.ScriptHash(), util.Uint160{1, 2, 3}, 1, nil)
   654  			b := e.NewUnsignedBlock(t, tx)
   655  			e.SignBlock(b)
   656  			require.NoError(t, bc.AddHeaders(&b.Header))
   657  
   658  			_, err := bc.GetBlock(b.Hash())
   659  			require.Error(t, err)
   660  
   661  			_, err = bc.GetHeader(b.Hash())
   662  			require.NoError(t, err)
   663  
   664  			require.NoError(t, bc.AddBlock(b))
   665  
   666  			_, err = bc.GetBlock(b.Hash())
   667  			require.NoError(t, err)
   668  		})
   669  		t.Run("empty block", func(t *testing.T) {
   670  			b := e.NewUnsignedBlock(t)
   671  			e.SignBlock(b)
   672  
   673  			require.NoError(t, bc.AddHeaders(&b.Header))
   674  
   675  			_, err := bc.GetBlock(b.Hash())
   676  			require.NoError(t, err)
   677  		})
   678  	})
   679  }
   680  
   681  func TestBlockchain_VerifyHashAgainstScript(t *testing.T) {
   682  	bc, acc := chain.NewSingle(t)
   683  	e := neotest.NewExecutor(t, bc, acc, acc)
   684  
   685  	cs, csInvalid := contracts.GetTestContractState(t, pathToInternalContracts, 0, 1, acc.ScriptHash())
   686  	c1 := &neotest.Contract{
   687  		Hash:     cs.Hash,
   688  		NEF:      &cs.NEF,
   689  		Manifest: &cs.Manifest,
   690  	}
   691  	c2 := &neotest.Contract{
   692  		Hash:     csInvalid.Hash,
   693  		NEF:      &csInvalid.NEF,
   694  		Manifest: &csInvalid.Manifest,
   695  	}
   696  	e.DeployContract(t, c1, nil)
   697  	e.DeployContract(t, c2, nil)
   698  
   699  	gas := bc.GetMaxVerificationGAS()
   700  	t.Run("Contract", func(t *testing.T) {
   701  		t.Run("Missing", func(t *testing.T) {
   702  			newH := cs.Hash
   703  			newH[0] = ^newH[0]
   704  			w := &transaction.Witness{InvocationScript: []byte{byte(opcode.PUSH4)}}
   705  			_, err := bc.VerifyWitness(newH, nil, w, gas)
   706  			require.ErrorIs(t, err, core.ErrUnknownVerificationContract)
   707  		})
   708  		t.Run("Invalid", func(t *testing.T) {
   709  			w := &transaction.Witness{InvocationScript: []byte{byte(opcode.PUSH4)}}
   710  			_, err := bc.VerifyWitness(csInvalid.Hash, nil, w, gas)
   711  			require.ErrorIs(t, err, core.ErrInvalidVerificationContract)
   712  		})
   713  		t.Run("ValidSignature", func(t *testing.T) {
   714  			w := &transaction.Witness{InvocationScript: []byte{byte(opcode.PUSH4)}}
   715  			_, err := bc.VerifyWitness(cs.Hash, nil, w, gas)
   716  			require.NoError(t, err)
   717  		})
   718  		t.Run("InvalidSignature", func(t *testing.T) {
   719  			w := &transaction.Witness{InvocationScript: []byte{byte(opcode.PUSH3)}}
   720  			_, err := bc.VerifyWitness(cs.Hash, nil, w, gas)
   721  			require.ErrorIs(t, err, core.ErrVerificationFailed)
   722  		})
   723  	})
   724  	t.Run("NotEnoughGas", func(t *testing.T) {
   725  		verif := []byte{byte(opcode.PUSH1)}
   726  		w := &transaction.Witness{
   727  			InvocationScript:   []byte{byte(opcode.NOP)},
   728  			VerificationScript: verif,
   729  		}
   730  		_, err := bc.VerifyWitness(hash.Hash160(verif), nil, w, 1)
   731  		require.ErrorIs(t, err, core.ErrVerificationFailed)
   732  	})
   733  	t.Run("NoResult", func(t *testing.T) {
   734  		verif := []byte{byte(opcode.DROP)}
   735  		w := &transaction.Witness{
   736  			InvocationScript:   []byte{byte(opcode.PUSH1)},
   737  			VerificationScript: verif,
   738  		}
   739  		_, err := bc.VerifyWitness(hash.Hash160(verif), nil, w, gas)
   740  		require.ErrorIs(t, err, core.ErrVerificationFailed)
   741  	})
   742  	t.Run("BadResult", func(t *testing.T) {
   743  		verif := make([]byte, keys.SignatureLen+2)
   744  		verif[0] = byte(opcode.PUSHDATA1)
   745  		verif[1] = keys.SignatureLen
   746  		w := &transaction.Witness{
   747  			InvocationScript:   []byte{byte(opcode.NOP)},
   748  			VerificationScript: verif,
   749  		}
   750  		_, err := bc.VerifyWitness(hash.Hash160(verif), nil, w, gas)
   751  		require.ErrorIs(t, err, core.ErrVerificationFailed)
   752  	})
   753  	t.Run("TooManyResults", func(t *testing.T) {
   754  		verif := []byte{byte(opcode.NOP)}
   755  		w := &transaction.Witness{
   756  			InvocationScript:   []byte{byte(opcode.PUSH1), byte(opcode.PUSH1)},
   757  			VerificationScript: verif,
   758  		}
   759  		_, err := bc.VerifyWitness(hash.Hash160(verif), nil, w, gas)
   760  		require.ErrorIs(t, err, core.ErrVerificationFailed)
   761  	})
   762  }
   763  
   764  func TestBlockchain_IsTxStillRelevant(t *testing.T) {
   765  	bc, acc := chain.NewSingleWithCustomConfig(t, func(c *config.Blockchain) {
   766  		c.P2PSigExtensions = true
   767  	})
   768  	e := neotest.NewExecutor(t, bc, acc, acc)
   769  
   770  	mp := bc.GetMemPool()
   771  
   772  	t.Run("small ValidUntilBlock", func(t *testing.T) {
   773  		tx := e.PrepareInvocation(t, []byte{byte(opcode.PUSH1)}, []neotest.Signer{acc}, bc.BlockHeight()+1)
   774  
   775  		require.True(t, bc.IsTxStillRelevant(tx, nil, false))
   776  		e.AddNewBlock(t)
   777  		require.False(t, bc.IsTxStillRelevant(tx, nil, false))
   778  	})
   779  
   780  	t.Run("tx is already persisted", func(t *testing.T) {
   781  		tx := e.PrepareInvocation(t, []byte{byte(opcode.PUSH1)}, []neotest.Signer{acc}, bc.BlockHeight()+2)
   782  
   783  		require.True(t, bc.IsTxStillRelevant(tx, nil, false))
   784  		e.AddNewBlock(t, tx)
   785  		require.False(t, bc.IsTxStillRelevant(tx, nil, false))
   786  	})
   787  
   788  	t.Run("tx with Conflicts attribute", func(t *testing.T) {
   789  		tx1 := e.PrepareInvocation(t, []byte{byte(opcode.PUSH1)}, []neotest.Signer{acc}, bc.BlockHeight()+5)
   790  
   791  		tx2 := transaction.New([]byte{byte(opcode.PUSH1)}, 0)
   792  		tx2.Nonce = neotest.Nonce()
   793  		tx2.ValidUntilBlock = e.Chain.BlockHeight() + 5
   794  		tx2.Attributes = []transaction.Attribute{{
   795  			Type:  transaction.ConflictsT,
   796  			Value: &transaction.Conflicts{Hash: tx1.Hash()},
   797  		}}
   798  		e.SignTx(t, tx2, -1, acc)
   799  
   800  		require.True(t, bc.IsTxStillRelevant(tx1, mp, false))
   801  		require.NoError(t, bc.PoolTx(tx2))
   802  		require.False(t, bc.IsTxStillRelevant(tx1, mp, false))
   803  	})
   804  	t.Run("NotValidBefore", func(t *testing.T) {
   805  		tx3 := transaction.New([]byte{byte(opcode.PUSH1)}, 0)
   806  		tx3.Nonce = neotest.Nonce()
   807  		tx3.Attributes = []transaction.Attribute{{
   808  			Type:  transaction.NotValidBeforeT,
   809  			Value: &transaction.NotValidBefore{Height: bc.BlockHeight() + 1},
   810  		}}
   811  		tx3.ValidUntilBlock = bc.BlockHeight() + 2
   812  		e.SignTx(t, tx3, -1, acc)
   813  
   814  		require.False(t, bc.IsTxStillRelevant(tx3, nil, false))
   815  		e.AddNewBlock(t)
   816  		require.True(t, bc.IsTxStillRelevant(tx3, nil, false))
   817  	})
   818  	t.Run("contract witness check fails", func(t *testing.T) {
   819  		src := fmt.Sprintf(`package verify
   820  		import (
   821  			"github.com/nspcc-dev/neo-go/pkg/interop/contract"
   822  			"github.com/nspcc-dev/neo-go/pkg/interop/lib/address"
   823  		)
   824  		func Verify() bool {
   825  			addr := address.ToHash160("`+address.Uint160ToString(e.NativeHash(t, nativenames.Ledger))+`")
   826  			currentHeight := contract.Call(addr, "currentIndex", contract.ReadStates)
   827  			return currentHeight.(int) < %d
   828  		}`, bc.BlockHeight()+2) // deploy + next block
   829  		c := neotest.CompileSource(t, acc.ScriptHash(), strings.NewReader(src), &compiler.Options{
   830  			Name: "verification_contract",
   831  		})
   832  		e.DeployContract(t, c, nil)
   833  
   834  		tx := transaction.New([]byte{byte(opcode.PUSH1)}, 0)
   835  		tx.Nonce = neotest.Nonce()
   836  		tx.ValidUntilBlock = bc.BlockHeight() + 2
   837  		tx.Signers = []transaction.Signer{
   838  			{
   839  				Account: c.Hash,
   840  				Scopes:  transaction.None,
   841  			},
   842  		}
   843  		tx.NetworkFee += 10_000_000
   844  		tx.Scripts = []transaction.Witness{{}}
   845  
   846  		require.True(t, bc.IsTxStillRelevant(tx, mp, false))
   847  		e.AddNewBlock(t)
   848  		require.False(t, bc.IsTxStillRelevant(tx, mp, false))
   849  	})
   850  }
   851  
   852  func TestBlockchain_MemPoolRemoval(t *testing.T) {
   853  	const added = 16
   854  	const notAdded = 32
   855  	bc, acc := chain.NewSingle(t)
   856  	e := neotest.NewExecutor(t, bc, acc, acc)
   857  
   858  	addedTxes := make([]*transaction.Transaction, added)
   859  	notAddedTxes := make([]*transaction.Transaction, notAdded)
   860  	for i := range addedTxes {
   861  		addedTxes[i] = e.PrepareInvocation(t, []byte{byte(opcode.PUSH1)}, []neotest.Signer{acc}, 100)
   862  		require.NoError(t, bc.PoolTx(addedTxes[i]))
   863  	}
   864  	for i := range notAddedTxes {
   865  		notAddedTxes[i] = e.PrepareInvocation(t, []byte{byte(opcode.PUSH1)}, []neotest.Signer{acc}, 100)
   866  		require.NoError(t, bc.PoolTx(notAddedTxes[i]))
   867  	}
   868  	mempool := bc.GetMemPool()
   869  	e.AddNewBlock(t, addedTxes...)
   870  	for _, tx := range addedTxes {
   871  		require.False(t, mempool.ContainsKey(tx.Hash()))
   872  	}
   873  	for _, tx := range notAddedTxes {
   874  		require.True(t, mempool.ContainsKey(tx.Hash()))
   875  	}
   876  }
   877  
   878  func TestBlockchain_HasBlock(t *testing.T) {
   879  	bc, acc := chain.NewSingle(t)
   880  	e := neotest.NewExecutor(t, bc, acc, acc)
   881  
   882  	blocks := e.GenerateNewBlocks(t, 10)
   883  
   884  	for i := 0; i < len(blocks); i++ {
   885  		assert.True(t, bc.HasBlock(blocks[i].Hash()))
   886  	}
   887  	newBlock := e.NewUnsignedBlock(t)
   888  	assert.False(t, bc.HasBlock(newBlock.Hash()))
   889  }
   890  
   891  func TestBlockchain_GetTransaction(t *testing.T) {
   892  	bc, acc := chain.NewSingle(t)
   893  	e := neotest.NewExecutor(t, bc, acc, acc)
   894  
   895  	tx1 := e.PrepareInvocation(t, []byte{byte(opcode.PUSH1)}, []neotest.Signer{acc})
   896  	e.AddNewBlock(t, tx1)
   897  
   898  	tx2 := e.PrepareInvocation(t, []byte{byte(opcode.PUSH2)}, []neotest.Signer{acc})
   899  	tx2Size := io.GetVarSize(tx2)
   900  	b := e.AddNewBlock(t, tx2)
   901  
   902  	tx, height, err := bc.GetTransaction(tx2.Hash())
   903  	require.Nil(t, err)
   904  	assert.Equal(t, b.Index, height)
   905  	assert.Equal(t, tx2Size, tx.Size())
   906  	assert.Equal(t, b.Transactions[0], tx)
   907  }
   908  
   909  func TestBlockchain_GetClaimable(t *testing.T) {
   910  	bc, acc := chain.NewSingle(t)
   911  
   912  	t.Run("first generation period", func(t *testing.T) {
   913  		amount, err := bc.CalculateClaimable(acc.ScriptHash(), 1)
   914  		require.NoError(t, err)
   915  		require.EqualValues(t, big.NewInt(5*native.GASFactor/10), amount)
   916  	})
   917  }
   918  
   919  func TestBlockchain_Close(t *testing.T) {
   920  	st := storage.NewMemoryStore()
   921  	bc, acc := chain.NewSingleWithCustomConfigAndStore(t, nil, st, false)
   922  	e := neotest.NewExecutor(t, bc, acc, acc)
   923  	go bc.Run()
   924  	e.GenerateNewBlocks(t, 10)
   925  	bc.Close()
   926  	// It's a hack, but we use internal knowledge of MemoryStore
   927  	// implementation which makes it completely unusable (up to panicing)
   928  	// after Close().
   929  	require.Panics(t, func() {
   930  		_ = st.PutChangeSet(map[string][]byte{"0": {1}}, nil)
   931  	})
   932  }
   933  
   934  func TestBlockchain_Subscriptions(t *testing.T) {
   935  	// We use buffering here as a substitute for reader goroutines, events
   936  	// get queued up and we read them one by one here.
   937  	const chBufSize = 16
   938  	blockCh := make(chan *block.Block, chBufSize)
   939  	txCh := make(chan *transaction.Transaction, chBufSize)
   940  	notificationCh := make(chan *state.ContainedNotificationEvent, chBufSize)
   941  	executionCh := make(chan *state.AppExecResult, chBufSize)
   942  
   943  	bc, acc := chain.NewSingle(t)
   944  	e := neotest.NewExecutor(t, bc, acc, acc)
   945  	nativeGASHash := e.NativeHash(t, nativenames.Gas)
   946  	bc.SubscribeForBlocks(blockCh)
   947  	bc.SubscribeForTransactions(txCh)
   948  	bc.SubscribeForNotifications(notificationCh)
   949  	bc.SubscribeForExecutions(executionCh)
   950  
   951  	assert.Empty(t, notificationCh)
   952  	assert.Empty(t, executionCh)
   953  	assert.Empty(t, blockCh)
   954  	assert.Empty(t, txCh)
   955  
   956  	generatedB := e.AddNewBlock(t)
   957  	require.Eventually(t, func() bool { return len(blockCh) != 0 }, time.Second, 10*time.Millisecond)
   958  	assert.Len(t, notificationCh, 1) // validator bounty
   959  	assert.Len(t, executionCh, 2)
   960  	assert.Empty(t, txCh)
   961  
   962  	b := <-blockCh
   963  	assert.Equal(t, generatedB, b)
   964  	assert.Empty(t, blockCh)
   965  
   966  	aer := <-executionCh
   967  	assert.Equal(t, b.Hash(), aer.Container)
   968  	aer = <-executionCh
   969  	assert.Equal(t, b.Hash(), aer.Container)
   970  
   971  	notif := <-notificationCh
   972  	require.Equal(t, bc.UtilityTokenHash(), notif.ScriptHash)
   973  
   974  	script := io.NewBufBinWriter()
   975  	emit.Bytes(script.BinWriter, []byte("yay!"))
   976  	emit.Syscall(script.BinWriter, interopnames.SystemRuntimeNotify)
   977  	require.NoError(t, script.Err)
   978  	txGood1 := e.PrepareInvocation(t, script.Bytes(), []neotest.Signer{acc})
   979  
   980  	// Reset() reuses the script buffer and we need to keep scripts.
   981  	script = io.NewBufBinWriter()
   982  	emit.Bytes(script.BinWriter, []byte("nay!"))
   983  	emit.Syscall(script.BinWriter, interopnames.SystemRuntimeNotify)
   984  	emit.Opcodes(script.BinWriter, opcode.THROW)
   985  	require.NoError(t, script.Err)
   986  	txBad := e.PrepareInvocation(t, script.Bytes(), []neotest.Signer{acc})
   987  
   988  	script = io.NewBufBinWriter()
   989  	emit.Bytes(script.BinWriter, []byte("yay! yay! yay!"))
   990  	emit.Syscall(script.BinWriter, interopnames.SystemRuntimeNotify)
   991  	require.NoError(t, script.Err)
   992  	txGood2 := e.PrepareInvocation(t, script.Bytes(), []neotest.Signer{acc})
   993  
   994  	invBlock := e.AddNewBlock(t, txGood1, txBad, txGood2)
   995  
   996  	require.Eventually(t, func() bool {
   997  		return len(blockCh) != 0 && len(txCh) != 0 &&
   998  			len(notificationCh) != 0 && len(executionCh) != 0
   999  	}, time.Second, 10*time.Millisecond)
  1000  
  1001  	b = <-blockCh
  1002  	require.Equal(t, invBlock, b)
  1003  	assert.Empty(t, blockCh)
  1004  
  1005  	exec := <-executionCh
  1006  	require.Equal(t, b.Hash(), exec.Container)
  1007  	require.Equal(t, exec.VMState, vmstate.Halt)
  1008  
  1009  	// 3 burn events for every tx and 1 mint for primary node
  1010  	require.True(t, len(notificationCh) >= 4)
  1011  	for i := 0; i < 4; i++ {
  1012  		notif := <-notificationCh
  1013  		require.Equal(t, nativeGASHash, notif.ScriptHash)
  1014  	}
  1015  
  1016  	// Follow in-block transaction order.
  1017  	for _, txExpected := range invBlock.Transactions {
  1018  		tx := <-txCh
  1019  		require.Equal(t, txExpected, tx)
  1020  		exec := <-executionCh
  1021  		require.Equal(t, tx.Hash(), exec.Container)
  1022  		if exec.VMState == vmstate.Halt {
  1023  			notif := <-notificationCh
  1024  			require.Equal(t, hash.Hash160(tx.Script), notif.ScriptHash)
  1025  		}
  1026  	}
  1027  	assert.Empty(t, txCh)
  1028  	assert.Len(t, notificationCh, 1)
  1029  	assert.Len(t, executionCh, 1)
  1030  
  1031  	notif = <-notificationCh
  1032  	require.Equal(t, bc.UtilityTokenHash(), notif.ScriptHash)
  1033  
  1034  	exec = <-executionCh
  1035  	require.Equal(t, b.Hash(), exec.Container)
  1036  	require.Equal(t, exec.VMState, vmstate.Halt)
  1037  
  1038  	bc.UnsubscribeFromBlocks(blockCh)
  1039  	bc.UnsubscribeFromTransactions(txCh)
  1040  	bc.UnsubscribeFromNotifications(notificationCh)
  1041  	bc.UnsubscribeFromExecutions(executionCh)
  1042  
  1043  	// Ensure that new blocks are processed correctly after unsubscription.
  1044  	e.GenerateNewBlocks(t, 2*chBufSize)
  1045  }
  1046  
  1047  func TestBlockchain_RemoveUntraceable(t *testing.T) {
  1048  	neoCommitteeKey := []byte{0xfb, 0xff, 0xff, 0xff, 0x0e}
  1049  	check := func(t *testing.T, bc *core.Blockchain, tHash, bHash, sHash util.Uint256, errorExpected bool) {
  1050  		_, _, err := bc.GetTransaction(tHash)
  1051  		if errorExpected {
  1052  			require.Error(t, err)
  1053  		} else {
  1054  			require.NoError(t, err)
  1055  		}
  1056  		_, err = bc.GetAppExecResults(tHash, trigger.Application)
  1057  		if errorExpected {
  1058  			require.Error(t, err)
  1059  		} else {
  1060  			require.NoError(t, err)
  1061  		}
  1062  		_, err = bc.GetBlock(bHash)
  1063  		if errorExpected {
  1064  			require.Error(t, err)
  1065  		} else {
  1066  			require.NoError(t, err)
  1067  		}
  1068  		_, err = bc.GetHeader(bHash)
  1069  		require.NoError(t, err)
  1070  		if !sHash.Equals(util.Uint256{}) {
  1071  			sm := bc.GetStateModule()
  1072  			_, err = sm.GetState(sHash, neoCommitteeKey)
  1073  			if errorExpected {
  1074  				require.Error(t, err)
  1075  			} else {
  1076  				require.NoError(t, err)
  1077  			}
  1078  		}
  1079  	}
  1080  	t.Run("P2PStateExchangeExtensions off", func(t *testing.T) {
  1081  		bc, acc := chain.NewSingleWithCustomConfig(t, func(c *config.Blockchain) {
  1082  			c.MaxTraceableBlocks = 2
  1083  			c.Ledger.GarbageCollectionPeriod = 2
  1084  			c.Ledger.RemoveUntraceableBlocks = true
  1085  		})
  1086  		e := neotest.NewExecutor(t, bc, acc, acc)
  1087  		neoValidatorInvoker := e.ValidatorInvoker(e.NativeHash(t, nativenames.Neo))
  1088  
  1089  		tx1Hash := neoValidatorInvoker.Invoke(t, true, "transfer", acc.ScriptHash(), util.Uint160{1, 2, 3}, 1, nil)
  1090  		tx1Height := bc.BlockHeight()
  1091  		b1 := e.TopBlock(t)
  1092  		sRoot, err := bc.GetStateModule().GetStateRoot(tx1Height)
  1093  		require.NoError(t, err)
  1094  
  1095  		neoValidatorInvoker.Invoke(t, true, "transfer", acc.ScriptHash(), util.Uint160{1, 2, 3}, 1, nil)
  1096  
  1097  		_, h1, err := bc.GetTransaction(tx1Hash)
  1098  		require.NoError(t, err)
  1099  		require.Equal(t, tx1Height, h1)
  1100  
  1101  		check(t, bc, tx1Hash, b1.Hash(), sRoot.Root, false)
  1102  		e.GenerateNewBlocks(t, 4)
  1103  
  1104  		sm := bc.GetStateModule()
  1105  		require.Eventually(t, func() bool {
  1106  			_, err = sm.GetState(sRoot.Root, neoCommitteeKey)
  1107  			return err != nil
  1108  		}, 2*bcPersistInterval, 10*time.Millisecond)
  1109  		check(t, bc, tx1Hash, b1.Hash(), sRoot.Root, true)
  1110  	})
  1111  	t.Run("P2PStateExchangeExtensions on", func(t *testing.T) {
  1112  		bc, acc := chain.NewSingleWithCustomConfig(t, func(c *config.Blockchain) {
  1113  			c.MaxTraceableBlocks = 2
  1114  			c.Ledger.GarbageCollectionPeriod = 2
  1115  			c.Ledger.RemoveUntraceableBlocks = true
  1116  			c.P2PStateExchangeExtensions = true
  1117  			c.StateSyncInterval = 2
  1118  			c.StateRootInHeader = true
  1119  		})
  1120  		e := neotest.NewExecutor(t, bc, acc, acc)
  1121  		neoValidatorInvoker := e.ValidatorInvoker(e.NativeHash(t, nativenames.Neo))
  1122  
  1123  		tx1Hash := neoValidatorInvoker.Invoke(t, true, "transfer", acc.ScriptHash(), util.Uint160{1, 2, 3}, 1, nil)
  1124  		tx1Height := bc.BlockHeight()
  1125  		b1 := e.TopBlock(t)
  1126  		sRoot, err := bc.GetStateModule().GetStateRoot(tx1Height)
  1127  		require.NoError(t, err)
  1128  
  1129  		tx2Hash := neoValidatorInvoker.Invoke(t, true, "transfer", acc.ScriptHash(), util.Uint160{1, 2, 3}, 1, nil)
  1130  		tx2Height := bc.BlockHeight()
  1131  		b2 := e.TopBlock(t)
  1132  
  1133  		_, h1, err := bc.GetTransaction(tx1Hash)
  1134  		require.NoError(t, err)
  1135  		require.Equal(t, tx1Height, h1)
  1136  
  1137  		e.GenerateNewBlocks(t, 3)
  1138  
  1139  		check(t, bc, tx1Hash, b1.Hash(), sRoot.Root, false)
  1140  		check(t, bc, tx2Hash, b2.Hash(), sRoot.Root, false)
  1141  
  1142  		e.AddNewBlock(t)
  1143  
  1144  		check(t, bc, tx1Hash, b1.Hash(), util.Uint256{}, true)
  1145  		check(t, bc, tx2Hash, b2.Hash(), util.Uint256{}, false)
  1146  		_, h2, err := bc.GetTransaction(tx2Hash)
  1147  		require.NoError(t, err)
  1148  		require.Equal(t, tx2Height, h2)
  1149  	})
  1150  }
  1151  
  1152  func TestBlockchain_InvalidNotification(t *testing.T) {
  1153  	bc, acc := chain.NewSingle(t)
  1154  	e := neotest.NewExecutor(t, bc, acc, acc)
  1155  
  1156  	cs, _ := contracts.GetTestContractState(t, pathToInternalContracts, 0, 1, acc.ScriptHash())
  1157  	e.DeployContract(t, &neotest.Contract{
  1158  		Hash:     cs.Hash,
  1159  		NEF:      &cs.NEF,
  1160  		Manifest: &cs.Manifest,
  1161  	}, nil)
  1162  
  1163  	cValidatorInvoker := e.ValidatorInvoker(cs.Hash)
  1164  	cValidatorInvoker.InvokeAndCheck(t, func(t testing.TB, stack []stackitem.Item) {
  1165  		require.Equal(t, 1, len(stack))
  1166  		require.Nil(t, stack[0])
  1167  	}, "invalidStack1")
  1168  	cValidatorInvoker.Invoke(t, stackitem.NewInterop(nil), "invalidStack2")
  1169  }
  1170  
  1171  // Test that deletion of non-existent doesn't result in error in tx or block addition.
  1172  func TestBlockchain_MPTDeleteNoKey(t *testing.T) {
  1173  	bc, acc := chain.NewSingle(t)
  1174  	e := neotest.NewExecutor(t, bc, acc, acc)
  1175  
  1176  	cs, _ := contracts.GetTestContractState(t, pathToInternalContracts, 0, 1, acc.ScriptHash())
  1177  	e.DeployContract(t, &neotest.Contract{
  1178  		Hash:     cs.Hash,
  1179  		NEF:      &cs.NEF,
  1180  		Manifest: &cs.Manifest,
  1181  	}, nil)
  1182  
  1183  	cValidatorInvoker := e.ValidatorInvoker(cs.Hash)
  1184  	cValidatorInvoker.Invoke(t, stackitem.Null{}, "delValue", "non-existent-key")
  1185  }
  1186  
  1187  // Test that all default configurations are loadable.
  1188  func TestConfig_LoadDefaultConfigs(t *testing.T) {
  1189  	var prefixPath = filepath.Join("..", "..", "config")
  1190  	check := func(t *testing.T, cfgFileSuffix any) {
  1191  		cfgPath := filepath.Join(prefixPath, fmt.Sprintf("protocol.%s.yml", cfgFileSuffix))
  1192  		_, err := config.LoadFile(cfgPath)
  1193  		require.NoError(t, err, fmt.Errorf("failed to load %s", cfgPath))
  1194  	}
  1195  	testCases := []any{
  1196  		netmode.MainNet,
  1197  		netmode.PrivNet,
  1198  		netmode.TestNet,
  1199  		netmode.UnitTestNet,
  1200  		"privnet.docker.one",
  1201  		"privnet.docker.two",
  1202  		"privnet.docker.three",
  1203  		"privnet.docker.four",
  1204  		"privnet.docker.single",
  1205  		"unit_testnet.single",
  1206  	}
  1207  	for _, tc := range testCases {
  1208  		t.Run(fmt.Sprintf("%s", tc), func(t *testing.T) {
  1209  			check(t, tc)
  1210  		})
  1211  	}
  1212  }
  1213  
  1214  func TestBlockchain_VerifyTx(t *testing.T) {
  1215  	bc, validator, committee := chain.NewMultiWithCustomConfig(t, func(c *config.Blockchain) {
  1216  		c.P2PSigExtensions = true
  1217  		c.ReservedAttributes = true
  1218  	})
  1219  	e := neotest.NewExecutor(t, bc, validator, committee)
  1220  
  1221  	accs := make([]*wallet.Account, 5)
  1222  	for i := range accs {
  1223  		var err error
  1224  		accs[i], err = wallet.NewAccount()
  1225  		require.NoError(t, err)
  1226  	}
  1227  
  1228  	notaryServiceFeePerKey := bc.GetNotaryServiceFeePerKey()
  1229  
  1230  	oracleAcc := accs[2]
  1231  	oraclePubs := keys.PublicKeys{oracleAcc.PublicKey()}
  1232  	require.NoError(t, oracleAcc.ConvertMultisig(1, oraclePubs))
  1233  
  1234  	neoHash := e.NativeHash(t, nativenames.Neo)
  1235  	gasHash := e.NativeHash(t, nativenames.Gas)
  1236  	policyHash := e.NativeHash(t, nativenames.Policy)
  1237  	designateHash := e.NativeHash(t, nativenames.Designation)
  1238  	notaryHash := e.NativeHash(t, nativenames.Notary)
  1239  	oracleHash := e.NativeHash(t, nativenames.Oracle)
  1240  
  1241  	neoValidatorsInvoker := e.ValidatorInvoker(neoHash)
  1242  	gasValidatorsInvoker := e.ValidatorInvoker(gasHash)
  1243  	policySuperInvoker := e.NewInvoker(policyHash, validator, committee)
  1244  	designateSuperInvoker := e.NewInvoker(designateHash, validator, committee)
  1245  	neoOwner := validator.ScriptHash()
  1246  
  1247  	neoAmount := int64(1_000_000)
  1248  	gasAmount := int64(1_000_000_000)
  1249  	txs := make([]*transaction.Transaction, 0, 2*len(accs)+2)
  1250  	for _, a := range accs {
  1251  		txs = append(txs, neoValidatorsInvoker.PrepareInvoke(t, "transfer", neoOwner, a.Contract.ScriptHash(), neoAmount, nil))
  1252  		txs = append(txs, gasValidatorsInvoker.PrepareInvoke(t, "transfer", neoOwner, a.Contract.ScriptHash(), gasAmount, nil))
  1253  	}
  1254  	txs = append(txs, neoValidatorsInvoker.PrepareInvoke(t, "transfer", neoOwner, committee.ScriptHash(), neoAmount, nil))
  1255  	txs = append(txs, gasValidatorsInvoker.PrepareInvoke(t, "transfer", neoOwner, committee.ScriptHash(), gasAmount, nil))
  1256  	e.AddNewBlock(t, txs...)
  1257  	for _, tx := range txs {
  1258  		e.CheckHalt(t, tx.Hash(), stackitem.NewBool(true))
  1259  	}
  1260  	policySuperInvoker.Invoke(t, true, "blockAccount", accs[1].PrivateKey().GetScriptHash().BytesBE())
  1261  
  1262  	checkErr := func(t *testing.T, expectedErr error, tx *transaction.Transaction) {
  1263  		err := bc.VerifyTx(tx)
  1264  		require.ErrorIs(t, err, expectedErr)
  1265  	}
  1266  
  1267  	testScript := []byte{byte(opcode.PUSH1)}
  1268  	newTestTx := func(t *testing.T, signer util.Uint160, script []byte) *transaction.Transaction {
  1269  		tx := transaction.New(script, 1_000_000)
  1270  		tx.Nonce = neotest.Nonce()
  1271  		tx.ValidUntilBlock = e.Chain.BlockHeight() + 5
  1272  		tx.Signers = []transaction.Signer{{
  1273  			Account: signer,
  1274  			Scopes:  transaction.CalledByEntry,
  1275  		}}
  1276  		tx.NetworkFee = int64(io.GetVarSize(tx)+200 /* witness */) * bc.FeePerByte()
  1277  		tx.NetworkFee += 1_000_000 // verification cost
  1278  		return tx
  1279  	}
  1280  
  1281  	h := accs[0].PrivateKey().GetScriptHash()
  1282  	t.Run("Expired", func(t *testing.T) {
  1283  		tx := newTestTx(t, h, testScript)
  1284  		tx.ValidUntilBlock = 1
  1285  		require.NoError(t, accs[0].SignTx(netmode.UnitTestNet, tx))
  1286  		checkErr(t, core.ErrTxExpired, tx)
  1287  	})
  1288  	t.Run("BlockedAccount", func(t *testing.T) {
  1289  		tx := newTestTx(t, accs[1].PrivateKey().GetScriptHash(), testScript)
  1290  		require.NoError(t, accs[1].SignTx(netmode.UnitTestNet, tx))
  1291  		checkErr(t, core.ErrPolicy, tx)
  1292  	})
  1293  	t.Run("InsufficientGas", func(t *testing.T) {
  1294  		balance := bc.GetUtilityTokenBalance(h)
  1295  		tx := newTestTx(t, h, testScript)
  1296  		tx.SystemFee = balance.Int64() + 1
  1297  		require.NoError(t, accs[0].SignTx(netmode.UnitTestNet, tx))
  1298  		checkErr(t, core.ErrInsufficientFunds, tx)
  1299  	})
  1300  	t.Run("TooBigSystemFee", func(t *testing.T) {
  1301  		tx := newTestTx(t, h, testScript)
  1302  		tx.SystemFee = bc.GetConfig().MaxBlockSystemFee + 100500
  1303  		require.NoError(t, accs[0].SignTx(netmode.UnitTestNet, tx))
  1304  		checkErr(t, core.ErrPolicy, tx)
  1305  	})
  1306  	t.Run("TooBigTx", func(t *testing.T) {
  1307  		script := make([]byte, transaction.MaxTransactionSize)
  1308  		tx := newTestTx(t, h, script)
  1309  		require.NoError(t, accs[0].SignTx(netmode.UnitTestNet, tx))
  1310  		checkErr(t, core.ErrTxTooBig, tx)
  1311  	})
  1312  	t.Run("NetworkFee", func(t *testing.T) {
  1313  		t.Run("SmallNetworkFee", func(t *testing.T) {
  1314  			tx := newTestTx(t, h, testScript)
  1315  			tx.NetworkFee = 1
  1316  			require.NoError(t, accs[0].SignTx(netmode.UnitTestNet, tx))
  1317  			checkErr(t, core.ErrTxSmallNetworkFee, tx)
  1318  		})
  1319  		t.Run("AlmostEnoughNetworkFee", func(t *testing.T) {
  1320  			tx := newTestTx(t, h, testScript)
  1321  			verificationNetFee, calcultedScriptSize := fee.Calculate(bc.GetBaseExecFee(), accs[0].Contract.Script)
  1322  			expectedSize := io.GetVarSize(tx) + calcultedScriptSize
  1323  			calculatedNetFee := verificationNetFee + int64(expectedSize)*bc.FeePerByte()
  1324  			tx.NetworkFee = calculatedNetFee - 1
  1325  			require.NoError(t, accs[0].SignTx(netmode.UnitTestNet, tx))
  1326  			require.Equal(t, expectedSize, io.GetVarSize(tx))
  1327  			checkErr(t, core.ErrVerificationFailed, tx)
  1328  		})
  1329  		t.Run("EnoughNetworkFee", func(t *testing.T) {
  1330  			tx := newTestTx(t, h, testScript)
  1331  			verificationNetFee, calcultedScriptSize := fee.Calculate(bc.GetBaseExecFee(), accs[0].Contract.Script)
  1332  			expectedSize := io.GetVarSize(tx) + calcultedScriptSize
  1333  			calculatedNetFee := verificationNetFee + int64(expectedSize)*bc.FeePerByte()
  1334  			tx.NetworkFee = calculatedNetFee
  1335  			require.NoError(t, accs[0].SignTx(netmode.UnitTestNet, tx))
  1336  			require.Equal(t, expectedSize, io.GetVarSize(tx))
  1337  			require.NoError(t, bc.VerifyTx(tx))
  1338  		})
  1339  		t.Run("CalculateNetworkFee, signature script", func(t *testing.T) {
  1340  			tx := newTestTx(t, h, testScript)
  1341  			expectedSize := io.GetVarSize(tx)
  1342  			verificationNetFee, calculatedScriptSize := fee.Calculate(bc.GetBaseExecFee(), accs[0].Contract.Script)
  1343  			expectedSize += calculatedScriptSize
  1344  			expectedNetFee := verificationNetFee + int64(expectedSize)*bc.FeePerByte()
  1345  			tx.NetworkFee = expectedNetFee
  1346  			require.NoError(t, accs[0].SignTx(netmode.UnitTestNet, tx))
  1347  			actualSize := io.GetVarSize(tx)
  1348  			require.Equal(t, expectedSize, actualSize)
  1349  			gasConsumed, err := bc.VerifyWitness(h, tx, &tx.Scripts[0], -1)
  1350  			require.NoError(t, err)
  1351  			require.Equal(t, verificationNetFee, gasConsumed)
  1352  			require.Equal(t, expectedNetFee, bc.FeePerByte()*int64(actualSize)+gasConsumed)
  1353  		})
  1354  		t.Run("CalculateNetworkFee, multisignature script", func(t *testing.T) {
  1355  			multisigAcc := accs[4]
  1356  			pKeys := keys.PublicKeys{multisigAcc.PublicKey()}
  1357  			require.NoError(t, multisigAcc.ConvertMultisig(1, pKeys))
  1358  			multisigHash := hash.Hash160(multisigAcc.Contract.Script)
  1359  			tx := newTestTx(t, multisigHash, testScript)
  1360  			verificationNetFee, calculatedScriptSize := fee.Calculate(bc.GetBaseExecFee(), multisigAcc.Contract.Script)
  1361  			expectedSize := io.GetVarSize(tx) + calculatedScriptSize
  1362  			expectedNetFee := verificationNetFee + int64(expectedSize)*bc.FeePerByte()
  1363  			tx.NetworkFee = expectedNetFee
  1364  			require.NoError(t, multisigAcc.SignTx(netmode.UnitTestNet, tx))
  1365  			actualSize := io.GetVarSize(tx)
  1366  			require.Equal(t, expectedSize, actualSize)
  1367  			gasConsumed, err := bc.VerifyWitness(multisigHash, tx, &tx.Scripts[0], -1)
  1368  			require.NoError(t, err)
  1369  			require.Equal(t, verificationNetFee, gasConsumed)
  1370  			require.Equal(t, expectedNetFee, bc.FeePerByte()*int64(actualSize)+gasConsumed)
  1371  		})
  1372  	})
  1373  	t.Run("InvalidTxScript", func(t *testing.T) {
  1374  		tx := newTestTx(t, h, testScript)
  1375  		tx.Script = append(tx.Script, 0xff)
  1376  		require.NoError(t, accs[0].SignTx(netmode.UnitTestNet, tx))
  1377  		checkErr(t, core.ErrInvalidScript, tx)
  1378  	})
  1379  	t.Run("InvalidVerificationScript", func(t *testing.T) {
  1380  		tx := newTestTx(t, h, testScript)
  1381  		verif := []byte{byte(opcode.JMP), 3, 0xff, byte(opcode.PUSHT)}
  1382  		tx.Signers = append(tx.Signers, transaction.Signer{
  1383  			Account: hash.Hash160(verif),
  1384  			Scopes:  transaction.Global,
  1385  		})
  1386  		tx.NetworkFee += 1000000
  1387  		require.NoError(t, accs[0].SignTx(netmode.UnitTestNet, tx))
  1388  		tx.Scripts = append(tx.Scripts, transaction.Witness{
  1389  			InvocationScript:   []byte{},
  1390  			VerificationScript: verif,
  1391  		})
  1392  		checkErr(t, core.ErrInvalidVerificationScript, tx)
  1393  	})
  1394  	t.Run("InvalidInvocationScript", func(t *testing.T) {
  1395  		tx := newTestTx(t, h, testScript)
  1396  		verif := []byte{byte(opcode.PUSHT)}
  1397  		tx.Signers = append(tx.Signers, transaction.Signer{
  1398  			Account: hash.Hash160(verif),
  1399  			Scopes:  transaction.Global,
  1400  		})
  1401  		tx.NetworkFee += 1000000
  1402  		require.NoError(t, accs[0].SignTx(netmode.UnitTestNet, tx))
  1403  		tx.Scripts = append(tx.Scripts, transaction.Witness{
  1404  			InvocationScript:   []byte{byte(opcode.JMP), 3, 0xff},
  1405  			VerificationScript: verif,
  1406  		})
  1407  		checkErr(t, core.ErrInvalidInvocationScript, tx)
  1408  	})
  1409  	t.Run("Conflict", func(t *testing.T) {
  1410  		balance := bc.GetUtilityTokenBalance(h).Int64()
  1411  		tx := newTestTx(t, h, testScript)
  1412  		tx.NetworkFee = balance / 2
  1413  		require.NoError(t, accs[0].SignTx(netmode.UnitTestNet, tx))
  1414  		require.NoError(t, bc.PoolTx(tx))
  1415  
  1416  		tx2 := newTestTx(t, h, testScript)
  1417  		tx2.NetworkFee = balance / 2
  1418  		require.NoError(t, accs[0].SignTx(netmode.UnitTestNet, tx2))
  1419  		err := bc.PoolTx(tx2)
  1420  		require.ErrorIs(t, err, core.ErrMemPoolConflict)
  1421  	})
  1422  	t.Run("InvalidWitnessHash", func(t *testing.T) {
  1423  		tx := newTestTx(t, h, testScript)
  1424  		require.NoError(t, accs[0].SignTx(netmode.UnitTestNet, tx))
  1425  		tx.Scripts[0].VerificationScript = []byte{byte(opcode.PUSHT)}
  1426  		checkErr(t, core.ErrWitnessHashMismatch, tx)
  1427  	})
  1428  	t.Run("InvalidWitnessSignature", func(t *testing.T) {
  1429  		tx := newTestTx(t, h, testScript)
  1430  		require.NoError(t, accs[0].SignTx(netmode.UnitTestNet, tx))
  1431  		tx.Scripts[0].InvocationScript[10] = ^tx.Scripts[0].InvocationScript[10]
  1432  		checkErr(t, core.ErrVerificationFailed, tx)
  1433  	})
  1434  	t.Run("InsufficientNetworkFeeForSecondWitness", func(t *testing.T) {
  1435  		tx := newTestTx(t, h, testScript)
  1436  		tx.Signers = append(tx.Signers, transaction.Signer{
  1437  			Account: accs[3].PrivateKey().GetScriptHash(),
  1438  			Scopes:  transaction.Global,
  1439  		})
  1440  		require.NoError(t, accs[0].SignTx(netmode.UnitTestNet, tx))
  1441  		require.NoError(t, accs[3].SignTx(netmode.UnitTestNet, tx))
  1442  		checkErr(t, core.ErrVerificationFailed, tx)
  1443  	})
  1444  	t.Run("OldTX", func(t *testing.T) {
  1445  		tx := newTestTx(t, h, testScript)
  1446  		require.NoError(t, accs[0].SignTx(netmode.UnitTestNet, tx))
  1447  		e.AddNewBlock(t, tx)
  1448  
  1449  		checkErr(t, core.ErrAlreadyExists, tx)
  1450  	})
  1451  	t.Run("MemPooledTX", func(t *testing.T) {
  1452  		tx := newTestTx(t, h, testScript)
  1453  		require.NoError(t, accs[0].SignTx(netmode.UnitTestNet, tx))
  1454  		require.NoError(t, bc.PoolTx(tx))
  1455  
  1456  		err := bc.PoolTx(tx)
  1457  		require.ErrorIs(t, err, core.ErrAlreadyInPool)
  1458  	})
  1459  	t.Run("MemPoolOOM", func(t *testing.T) {
  1460  		mp := mempool.New(1, 0, false, nil)
  1461  		tx1 := newTestTx(t, h, testScript)
  1462  		tx1.NetworkFee += 10000 // Give it more priority.
  1463  		require.NoError(t, accs[0].SignTx(netmode.UnitTestNet, tx1))
  1464  		require.NoError(t, bc.PoolTx(tx1, mp))
  1465  
  1466  		tx2 := newTestTx(t, h, testScript)
  1467  		require.NoError(t, accs[0].SignTx(netmode.UnitTestNet, tx2))
  1468  		err := bc.PoolTx(tx2, mp)
  1469  		require.ErrorIs(t, err, core.ErrOOM)
  1470  	})
  1471  	t.Run("Attribute", func(t *testing.T) {
  1472  		t.Run("InvalidHighPriority", func(t *testing.T) {
  1473  			tx := newTestTx(t, h, testScript)
  1474  			tx.Attributes = append(tx.Attributes, transaction.Attribute{Type: transaction.HighPriority})
  1475  			require.NoError(t, accs[0].SignTx(netmode.UnitTestNet, tx))
  1476  			checkErr(t, core.ErrInvalidAttribute, tx)
  1477  		})
  1478  		t.Run("ValidHighPriority", func(t *testing.T) {
  1479  			tx := newTestTx(t, h, testScript)
  1480  			tx.Attributes = append(tx.Attributes, transaction.Attribute{Type: transaction.HighPriority})
  1481  			tx.NetworkFee += 4_000_000 // multisig check
  1482  			tx.Signers = []transaction.Signer{{
  1483  				Account: committee.ScriptHash(),
  1484  				Scopes:  transaction.None,
  1485  			}}
  1486  			rawScript := committee.Script()
  1487  			size := io.GetVarSize(tx)
  1488  			netFee, sizeDelta := fee.Calculate(bc.GetBaseExecFee(), rawScript)
  1489  			tx.NetworkFee += netFee
  1490  			tx.NetworkFee += int64(size+sizeDelta) * bc.FeePerByte()
  1491  			tx.Scripts = []transaction.Witness{{
  1492  				InvocationScript:   committee.SignHashable(uint32(netmode.UnitTestNet), tx),
  1493  				VerificationScript: rawScript,
  1494  			}}
  1495  			require.NoError(t, bc.VerifyTx(tx))
  1496  		})
  1497  		t.Run("Oracle", func(t *testing.T) {
  1498  			cs := contracts.GetOracleContractState(t, pathToInternalContracts, validator.ScriptHash(), 0)
  1499  			e.DeployContract(t, &neotest.Contract{
  1500  				Hash:     cs.Hash,
  1501  				NEF:      &cs.NEF,
  1502  				Manifest: &cs.Manifest,
  1503  			}, nil)
  1504  			cInvoker := e.ValidatorInvoker(cs.Hash)
  1505  
  1506  			const gasForResponse int64 = 10_000_000
  1507  			cInvoker.Invoke(t, stackitem.Null{}, "requestURL", "https://get.1234", "", "handle", []byte{}, gasForResponse)
  1508  
  1509  			oracleScript, err := smartcontract.CreateMajorityMultiSigRedeemScript(oraclePubs)
  1510  			require.NoError(t, err)
  1511  			oracleMultisigHash := hash.Hash160(oracleScript)
  1512  
  1513  			respScript := native.CreateOracleResponseScript(oracleHash)
  1514  
  1515  			// We need to create new transaction,
  1516  			// because hashes are cached after signing.
  1517  			getOracleTx := func(t *testing.T) *transaction.Transaction {
  1518  				tx := transaction.New(respScript, 1000_0000)
  1519  				tx.Nonce = neotest.Nonce()
  1520  				tx.ValidUntilBlock = bc.BlockHeight() + 1
  1521  				resp := &transaction.OracleResponse{
  1522  					ID:     0,
  1523  					Code:   transaction.Success,
  1524  					Result: []byte{1, 2, 3},
  1525  				}
  1526  				tx.Attributes = []transaction.Attribute{{
  1527  					Type:  transaction.OracleResponseT,
  1528  					Value: resp,
  1529  				}}
  1530  				tx.NetworkFee += 4_000_000 // multisig check
  1531  				tx.SystemFee = gasForResponse - tx.NetworkFee
  1532  				tx.Signers = []transaction.Signer{{
  1533  					Account: oracleMultisigHash,
  1534  					Scopes:  transaction.None,
  1535  				}}
  1536  				size := io.GetVarSize(tx)
  1537  				netFee, sizeDelta := fee.Calculate(bc.GetBaseExecFee(), oracleScript)
  1538  				tx.NetworkFee += netFee
  1539  				tx.NetworkFee += int64(size+sizeDelta) * bc.FeePerByte()
  1540  				return tx
  1541  			}
  1542  
  1543  			t.Run("NoOracleNodes", func(t *testing.T) {
  1544  				tx := getOracleTx(t)
  1545  				require.NoError(t, oracleAcc.SignTx(netmode.UnitTestNet, tx))
  1546  				checkErr(t, core.ErrInvalidAttribute, tx)
  1547  			})
  1548  
  1549  			keys := make([]any, 0, len(oraclePubs))
  1550  			for _, p := range oraclePubs {
  1551  				keys = append(keys, p.Bytes())
  1552  			}
  1553  			designateSuperInvoker.Invoke(t, stackitem.Null{}, "designateAsRole",
  1554  				int64(noderoles.Oracle), keys)
  1555  
  1556  			t.Run("Valid", func(t *testing.T) {
  1557  				tx := getOracleTx(t)
  1558  				require.NoError(t, oracleAcc.SignTx(netmode.UnitTestNet, tx))
  1559  				require.NoError(t, bc.VerifyTx(tx))
  1560  
  1561  				t.Run("NativeVerify", func(t *testing.T) {
  1562  					tx.Signers = append(tx.Signers, transaction.Signer{
  1563  						Account: oracleHash,
  1564  						Scopes:  transaction.None,
  1565  					})
  1566  					tx.Scripts = append(tx.Scripts, transaction.Witness{})
  1567  					t.Run("NonZeroVerification", func(t *testing.T) {
  1568  						w := io.NewBufBinWriter()
  1569  						emit.Opcodes(w.BinWriter, opcode.ABORT)
  1570  						emit.Bytes(w.BinWriter, util.Uint160{}.BytesBE())
  1571  						emit.Int(w.BinWriter, 0)
  1572  						emit.String(w.BinWriter, nativenames.Oracle)
  1573  						tx.Scripts[len(tx.Scripts)-1].VerificationScript = w.Bytes()
  1574  						err := bc.VerifyTx(tx)
  1575  						require.ErrorIs(t, err, core.ErrNativeContractWitness)
  1576  					})
  1577  					t.Run("Good", func(t *testing.T) {
  1578  						tx.Scripts[len(tx.Scripts)-1].VerificationScript = nil
  1579  						require.NoError(t, bc.VerifyTx(tx))
  1580  					})
  1581  				})
  1582  			})
  1583  			t.Run("InvalidRequestID", func(t *testing.T) {
  1584  				tx := getOracleTx(t)
  1585  				tx.Attributes[0].Value.(*transaction.OracleResponse).ID = 2
  1586  				require.NoError(t, oracleAcc.SignTx(netmode.UnitTestNet, tx))
  1587  				checkErr(t, core.ErrInvalidAttribute, tx)
  1588  			})
  1589  			t.Run("InvalidScope", func(t *testing.T) {
  1590  				tx := getOracleTx(t)
  1591  				tx.Signers[0].Scopes = transaction.Global
  1592  				require.NoError(t, oracleAcc.SignTx(netmode.UnitTestNet, tx))
  1593  				checkErr(t, core.ErrInvalidAttribute, tx)
  1594  			})
  1595  			t.Run("InvalidScript", func(t *testing.T) {
  1596  				tx := getOracleTx(t)
  1597  				tx.Script = append(tx.Script, byte(opcode.NOP))
  1598  				require.NoError(t, oracleAcc.SignTx(netmode.UnitTestNet, tx))
  1599  				checkErr(t, core.ErrInvalidAttribute, tx)
  1600  			})
  1601  			t.Run("InvalidSigner", func(t *testing.T) {
  1602  				tx := getOracleTx(t)
  1603  				tx.Signers[0].Account = accs[0].Contract.ScriptHash()
  1604  				require.NoError(t, accs[0].SignTx(netmode.UnitTestNet, tx))
  1605  				checkErr(t, core.ErrInvalidAttribute, tx)
  1606  			})
  1607  			t.Run("SmallFee", func(t *testing.T) {
  1608  				tx := getOracleTx(t)
  1609  				tx.SystemFee = 0
  1610  				require.NoError(t, oracleAcc.SignTx(netmode.UnitTestNet, tx))
  1611  				checkErr(t, core.ErrInvalidAttribute, tx)
  1612  			})
  1613  		})
  1614  		t.Run("NotValidBefore", func(t *testing.T) {
  1615  			getNVBTx := func(e *neotest.Executor, height uint32) *transaction.Transaction {
  1616  				tx := newTestTx(t, h, testScript)
  1617  				tx.Attributes = append(tx.Attributes, transaction.Attribute{Type: transaction.NotValidBeforeT, Value: &transaction.NotValidBefore{Height: height}})
  1618  				tx.NetworkFee += 4_000_000 // multisig check
  1619  				tx.Signers = []transaction.Signer{{
  1620  					Account: e.Validator.ScriptHash(),
  1621  					Scopes:  transaction.None,
  1622  				}}
  1623  				size := io.GetVarSize(tx)
  1624  				rawScript := e.Validator.Script()
  1625  				netFee, sizeDelta := fee.Calculate(e.Chain.GetBaseExecFee(), rawScript)
  1626  				tx.NetworkFee += netFee
  1627  				tx.NetworkFee += int64(size+sizeDelta) * e.Chain.FeePerByte()
  1628  				tx.Scripts = []transaction.Witness{{
  1629  					InvocationScript:   e.Validator.SignHashable(uint32(netmode.UnitTestNet), tx),
  1630  					VerificationScript: rawScript,
  1631  				}}
  1632  				return tx
  1633  			}
  1634  			t.Run("Disabled", func(t *testing.T) { // check that NVB attribute is not an extension anymore.
  1635  				bcBad, validatorBad, committeeBad := chain.NewMultiWithCustomConfig(t, func(c *config.Blockchain) {
  1636  					c.P2PSigExtensions = false
  1637  					c.ReservedAttributes = false
  1638  				})
  1639  				eBad := neotest.NewExecutor(t, bcBad, validatorBad, committeeBad)
  1640  				tx := getNVBTx(eBad, bcBad.BlockHeight())
  1641  				err := bcBad.VerifyTx(tx)
  1642  				require.NoError(t, err)
  1643  			})
  1644  			t.Run("Enabled", func(t *testing.T) {
  1645  				t.Run("NotYetValid", func(t *testing.T) {
  1646  					tx := getNVBTx(e, bc.BlockHeight()+1)
  1647  					require.ErrorIs(t, bc.VerifyTx(tx), core.ErrInvalidAttribute)
  1648  				})
  1649  				t.Run("positive", func(t *testing.T) {
  1650  					tx := getNVBTx(e, bc.BlockHeight())
  1651  					require.NoError(t, bc.VerifyTx(tx))
  1652  				})
  1653  			})
  1654  		})
  1655  		t.Run("Reserved", func(t *testing.T) {
  1656  			getReservedTx := func(e *neotest.Executor, attrType transaction.AttrType) *transaction.Transaction {
  1657  				tx := newTestTx(t, h, testScript)
  1658  				tx.Attributes = append(tx.Attributes, transaction.Attribute{Type: attrType, Value: &transaction.Reserved{Value: []byte{1, 2, 3}}})
  1659  				tx.NetworkFee += 4_000_000 // multisig check
  1660  				tx.Signers = []transaction.Signer{{
  1661  					Account: e.Validator.ScriptHash(),
  1662  					Scopes:  transaction.None,
  1663  				}}
  1664  				rawScript := e.Validator.Script()
  1665  				size := io.GetVarSize(tx)
  1666  				netFee, sizeDelta := fee.Calculate(e.Chain.GetBaseExecFee(), rawScript)
  1667  				tx.NetworkFee += netFee
  1668  				tx.NetworkFee += int64(size+sizeDelta) * e.Chain.FeePerByte()
  1669  				tx.Scripts = []transaction.Witness{{
  1670  					InvocationScript:   e.Validator.SignHashable(uint32(netmode.UnitTestNet), tx),
  1671  					VerificationScript: rawScript,
  1672  				}}
  1673  				return tx
  1674  			}
  1675  			t.Run("Disabled", func(t *testing.T) {
  1676  				bcBad, validatorBad, committeeBad := chain.NewMultiWithCustomConfig(t, func(c *config.Blockchain) {
  1677  					c.P2PSigExtensions = false
  1678  					c.ReservedAttributes = false
  1679  				})
  1680  				eBad := neotest.NewExecutor(t, bcBad, validatorBad, committeeBad)
  1681  				tx := getReservedTx(eBad, transaction.ReservedLowerBound+3)
  1682  				err := bcBad.VerifyTx(tx)
  1683  				require.Error(t, err)
  1684  				require.True(t, strings.Contains(err.Error(), "invalid attribute: attribute of reserved type was found, but ReservedAttributes are disabled"))
  1685  			})
  1686  			t.Run("Enabled", func(t *testing.T) {
  1687  				tx := getReservedTx(e, transaction.ReservedLowerBound+3)
  1688  				require.NoError(t, bc.VerifyTx(tx))
  1689  			})
  1690  		})
  1691  		t.Run("Conflicts", func(t *testing.T) {
  1692  			getConflictsTx := func(e *neotest.Executor, hashes ...util.Uint256) *transaction.Transaction {
  1693  				tx := newTestTx(t, h, testScript)
  1694  				tx.Attributes = make([]transaction.Attribute, len(hashes))
  1695  				for i, h := range hashes {
  1696  					tx.Attributes[i] = transaction.Attribute{
  1697  						Type: transaction.ConflictsT,
  1698  						Value: &transaction.Conflicts{
  1699  							Hash: h,
  1700  						},
  1701  					}
  1702  				}
  1703  				tx.NetworkFee += 4_000_000 // multisig check
  1704  				tx.Signers = []transaction.Signer{{
  1705  					Account: e.Validator.ScriptHash(),
  1706  					Scopes:  transaction.None,
  1707  				}}
  1708  				rawScript := e.Validator.Script()
  1709  				size := io.GetVarSize(tx)
  1710  				netFee, sizeDelta := fee.Calculate(e.Chain.GetBaseExecFee(), rawScript)
  1711  				tx.NetworkFee += netFee
  1712  				tx.NetworkFee += int64(size+sizeDelta) * e.Chain.FeePerByte()
  1713  				tx.Scripts = []transaction.Witness{{
  1714  					InvocationScript:   e.Validator.SignHashable(uint32(netmode.UnitTestNet), tx),
  1715  					VerificationScript: rawScript,
  1716  				}}
  1717  				return tx
  1718  			}
  1719  			t.Run("disabled", func(t *testing.T) { // check that Conflicts attribute is not an extension anymore.
  1720  				bcBad, validatorBad, committeeBad := chain.NewMultiWithCustomConfig(t, func(c *config.Blockchain) {
  1721  					c.P2PSigExtensions = false
  1722  					c.ReservedAttributes = false
  1723  				})
  1724  				eBad := neotest.NewExecutor(t, bcBad, validatorBad, committeeBad)
  1725  				tx := getConflictsTx(eBad, util.Uint256{1, 2, 3})
  1726  				err := bcBad.VerifyTx(tx)
  1727  				require.NoError(t, err)
  1728  			})
  1729  			t.Run("enabled", func(t *testing.T) {
  1730  				t.Run("dummy on-chain conflict", func(t *testing.T) {
  1731  					t.Run("on-chain conflict signed by malicious party", func(t *testing.T) {
  1732  						tx := newTestTx(t, h, testScript)
  1733  						require.NoError(t, accs[0].SignTx(netmode.UnitTestNet, tx))
  1734  						conflicting := transaction.New([]byte{byte(opcode.RET)}, 1000_0000)
  1735  						conflicting.ValidUntilBlock = bc.BlockHeight() + 1
  1736  						conflicting.Signers = []transaction.Signer{
  1737  							{
  1738  								Account: validator.ScriptHash(),
  1739  								Scopes:  transaction.CalledByEntry,
  1740  							},
  1741  						}
  1742  						conflicting.Attributes = []transaction.Attribute{
  1743  							{
  1744  								Type: transaction.ConflictsT,
  1745  								Value: &transaction.Conflicts{
  1746  									Hash: tx.Hash(),
  1747  								},
  1748  							},
  1749  						}
  1750  						conflicting.NetworkFee = 1000_0000
  1751  						require.NoError(t, validator.SignTx(netmode.UnitTestNet, conflicting))
  1752  						e.AddNewBlock(t, conflicting)
  1753  						// We expect `tx` to pass verification, because on-chained `conflicting` doesn't have
  1754  						// `tx`'s payer in the signers list, thus, `conflicting` should be considered as
  1755  						// malicious conflict.
  1756  						require.NoError(t, bc.VerifyTx(tx))
  1757  					})
  1758  					t.Run("multiple on-chain conflicts signed by malicious parties", func(t *testing.T) {
  1759  						m1 := e.NewAccount(t)
  1760  						m2 := e.NewAccount(t)
  1761  						m3 := e.NewAccount(t)
  1762  						good := e.NewAccount(t)
  1763  
  1764  						// txGood doesn't conflict with anyone and signed by good signer.
  1765  						txGood := newTestTx(t, good.ScriptHash(), testScript)
  1766  						require.NoError(t, good.SignTx(netmode.UnitTestNet, txGood))
  1767  
  1768  						// txM1 conflicts with txGood and signed by two malicious signers.
  1769  						txM1 := newTestTx(t, m1.ScriptHash(), testScript)
  1770  						txM1.Signers = append(txM1.Signers, transaction.Signer{Account: m2.ScriptHash()})
  1771  						txM1.Attributes = []transaction.Attribute{
  1772  							{
  1773  								Type: transaction.ConflictsT,
  1774  								Value: &transaction.Conflicts{
  1775  									Hash: txGood.Hash(),
  1776  								},
  1777  							},
  1778  						}
  1779  						txM1.NetworkFee = 1_000_0000
  1780  						require.NoError(t, m1.SignTx(netmode.UnitTestNet, txM1))
  1781  						require.NoError(t, m2.SignTx(netmode.UnitTestNet, txM1))
  1782  						e.AddNewBlock(t, txM1)
  1783  
  1784  						// txM2 conflicts with txGood and signed by one malicious signer.
  1785  						txM2 := newTestTx(t, m3.ScriptHash(), testScript)
  1786  						txM2.Attributes = []transaction.Attribute{
  1787  							{
  1788  								Type: transaction.ConflictsT,
  1789  								Value: &transaction.Conflicts{
  1790  									Hash: txGood.Hash(),
  1791  								},
  1792  							},
  1793  						}
  1794  						txM2.NetworkFee = 1_000_0000
  1795  						require.NoError(t, m3.SignTx(netmode.UnitTestNet, txM2))
  1796  						e.AddNewBlock(t, txM2)
  1797  
  1798  						// We expect `tx` to pass verification, because on-chained `conflicting` doesn't have
  1799  						// `tx`'s payer in the signers list, thus, `conflicting` should be considered as
  1800  						// malicious conflict.
  1801  						require.NoError(t, bc.VerifyTx(txGood))
  1802  
  1803  						// After that txGood can be added to the chain normally.
  1804  						e.AddNewBlock(t, txGood)
  1805  
  1806  						// And after that ErrAlreadyExist is expected on verification.
  1807  						require.ErrorIs(t, bc.VerifyTx(txGood), core.ErrAlreadyExists)
  1808  					})
  1809  
  1810  					t.Run("multiple on-chain conflicts signed by [valid+malicious] parties", func(t *testing.T) {
  1811  						m1 := e.NewAccount(t)
  1812  						m2 := e.NewAccount(t)
  1813  						m3 := e.NewAccount(t)
  1814  						good := e.NewAccount(t)
  1815  
  1816  						// txGood doesn't conflict with anyone and signed by good signer.
  1817  						txGood := newTestTx(t, good.ScriptHash(), testScript)
  1818  						require.NoError(t, good.SignTx(netmode.UnitTestNet, txGood))
  1819  
  1820  						// txM1 conflicts with txGood and signed by one malicious and one good signers.
  1821  						txM1 := newTestTx(t, m1.ScriptHash(), testScript)
  1822  						txM1.Signers = append(txM1.Signers, transaction.Signer{Account: good.ScriptHash()})
  1823  						txM1.Attributes = []transaction.Attribute{
  1824  							{
  1825  								Type: transaction.ConflictsT,
  1826  								Value: &transaction.Conflicts{
  1827  									Hash: txGood.Hash(),
  1828  								},
  1829  							},
  1830  						}
  1831  						txM1.NetworkFee = 1_000_0000
  1832  						require.NoError(t, m1.SignTx(netmode.UnitTestNet, txM1))
  1833  						require.NoError(t, good.SignTx(netmode.UnitTestNet, txM1))
  1834  						e.AddNewBlock(t, txM1)
  1835  
  1836  						// txM2 conflicts with txGood and signed by two malicious signers.
  1837  						txM2 := newTestTx(t, m2.ScriptHash(), testScript)
  1838  						txM2.Signers = append(txM2.Signers, transaction.Signer{Account: m3.ScriptHash()})
  1839  						txM2.Attributes = []transaction.Attribute{
  1840  							{
  1841  								Type: transaction.ConflictsT,
  1842  								Value: &transaction.Conflicts{
  1843  									Hash: txGood.Hash(),
  1844  								},
  1845  							},
  1846  						}
  1847  						txM2.NetworkFee = 1_000_0000
  1848  						require.NoError(t, m2.SignTx(netmode.UnitTestNet, txM2))
  1849  						require.NoError(t, m3.SignTx(netmode.UnitTestNet, txM2))
  1850  						e.AddNewBlock(t, txM2)
  1851  
  1852  						// We expect `tx` to fail verification, because one of the on-chained `conflicting`
  1853  						// transactions has common signers with `tx`, thus, `conflicting` should be
  1854  						// considered as a valid conflict.
  1855  						require.ErrorIs(t, bc.VerifyTx(txGood), core.ErrHasConflicts)
  1856  					})
  1857  
  1858  					t.Run("multiple on-chain conflicts signed by [malicious+valid] parties", func(t *testing.T) {
  1859  						m1 := e.NewAccount(t)
  1860  						m2 := e.NewAccount(t)
  1861  						m3 := e.NewAccount(t)
  1862  						good := e.NewAccount(t)
  1863  
  1864  						// txGood doesn't conflict with anyone and signed by good signer.
  1865  						txGood := newTestTx(t, good.ScriptHash(), testScript)
  1866  						require.NoError(t, good.SignTx(netmode.UnitTestNet, txGood))
  1867  
  1868  						// txM2 conflicts with txGood and signed by two malicious signers.
  1869  						txM2 := newTestTx(t, m2.ScriptHash(), testScript)
  1870  						txM2.Signers = append(txM2.Signers, transaction.Signer{Account: m3.ScriptHash()})
  1871  						txM2.Attributes = []transaction.Attribute{
  1872  							{
  1873  								Type: transaction.ConflictsT,
  1874  								Value: &transaction.Conflicts{
  1875  									Hash: txGood.Hash(),
  1876  								},
  1877  							},
  1878  						}
  1879  						txM2.NetworkFee = 1_000_0000
  1880  						require.NoError(t, m2.SignTx(netmode.UnitTestNet, txM2))
  1881  						require.NoError(t, m3.SignTx(netmode.UnitTestNet, txM2))
  1882  						e.AddNewBlock(t, txM2)
  1883  
  1884  						// txM1 conflicts with txGood and signed by one malicious and one good signers.
  1885  						txM1 := newTestTx(t, m1.ScriptHash(), testScript)
  1886  						txM1.Signers = append(txM1.Signers, transaction.Signer{Account: good.ScriptHash()})
  1887  						txM1.Attributes = []transaction.Attribute{
  1888  							{
  1889  								Type: transaction.ConflictsT,
  1890  								Value: &transaction.Conflicts{
  1891  									Hash: txGood.Hash(),
  1892  								},
  1893  							},
  1894  						}
  1895  						txM1.NetworkFee = 1_000_0000
  1896  						require.NoError(t, m1.SignTx(netmode.UnitTestNet, txM1))
  1897  						require.NoError(t, good.SignTx(netmode.UnitTestNet, txM1))
  1898  						e.AddNewBlock(t, txM1)
  1899  
  1900  						// We expect `tx` to fail verification, because one of the on-chained `conflicting`
  1901  						// transactions has common signers with `tx`, thus, `conflicting` should be
  1902  						// considered as a valid conflict.
  1903  						require.ErrorIs(t, bc.VerifyTx(txGood), core.ErrHasConflicts)
  1904  					})
  1905  
  1906  					t.Run("multiple on-chain conflicts signed by [valid + malicious + valid] parties", func(t *testing.T) {
  1907  						m1 := e.NewAccount(t)
  1908  						m2 := e.NewAccount(t)
  1909  						m3 := e.NewAccount(t)
  1910  						good := e.NewAccount(t)
  1911  
  1912  						// txGood doesn't conflict with anyone and signed by good signer.
  1913  						txGood := newTestTx(t, good.ScriptHash(), testScript)
  1914  						require.NoError(t, good.SignTx(netmode.UnitTestNet, txGood))
  1915  
  1916  						// txM1 conflicts with txGood and signed by one malicious and one good signers.
  1917  						txM1 := newTestTx(t, m1.ScriptHash(), testScript)
  1918  						txM1.Signers = append(txM1.Signers, transaction.Signer{Account: good.ScriptHash()})
  1919  						txM1.Attributes = []transaction.Attribute{
  1920  							{
  1921  								Type: transaction.ConflictsT,
  1922  								Value: &transaction.Conflicts{
  1923  									Hash: txGood.Hash(),
  1924  								},
  1925  							},
  1926  						}
  1927  						txM1.NetworkFee = 1_000_0000
  1928  						require.NoError(t, m1.SignTx(netmode.UnitTestNet, txM1))
  1929  						require.NoError(t, good.SignTx(netmode.UnitTestNet, txM1))
  1930  						e.AddNewBlock(t, txM1)
  1931  
  1932  						// txM2 conflicts with txGood and signed by two malicious signers.
  1933  						txM2 := newTestTx(t, m2.ScriptHash(), testScript)
  1934  						txM2.Signers = append(txM2.Signers, transaction.Signer{Account: m3.ScriptHash()})
  1935  						txM2.Attributes = []transaction.Attribute{
  1936  							{
  1937  								Type: transaction.ConflictsT,
  1938  								Value: &transaction.Conflicts{
  1939  									Hash: txGood.Hash(),
  1940  								},
  1941  							},
  1942  						}
  1943  						txM2.NetworkFee = 1_000_0000
  1944  						require.NoError(t, m2.SignTx(netmode.UnitTestNet, txM2))
  1945  						require.NoError(t, m3.SignTx(netmode.UnitTestNet, txM2))
  1946  						e.AddNewBlock(t, txM2)
  1947  
  1948  						// txM3 conflicts with txGood and signed by one good and one malicious signers.
  1949  						txM3 := newTestTx(t, good.ScriptHash(), testScript)
  1950  						txM3.Signers = append(txM3.Signers, transaction.Signer{Account: m1.ScriptHash()})
  1951  						txM3.Attributes = []transaction.Attribute{
  1952  							{
  1953  								Type: transaction.ConflictsT,
  1954  								Value: &transaction.Conflicts{
  1955  									Hash: txGood.Hash(),
  1956  								},
  1957  							},
  1958  						}
  1959  						txM3.NetworkFee = 1_000_0000
  1960  						require.NoError(t, good.SignTx(netmode.UnitTestNet, txM3))
  1961  						require.NoError(t, m1.SignTx(netmode.UnitTestNet, txM3))
  1962  						e.AddNewBlock(t, txM3)
  1963  
  1964  						// We expect `tx` to fail verification, because one of the on-chained `conflicting`
  1965  						// transactions has common signers with `tx`, thus, `conflicting` should be
  1966  						// considered as a valid conflict.
  1967  						require.ErrorIs(t, bc.VerifyTx(txGood), core.ErrHasConflicts)
  1968  					})
  1969  
  1970  					t.Run("on-chain conflict signed by single valid sender", func(t *testing.T) {
  1971  						tx := newTestTx(t, h, testScript)
  1972  						tx.Signers = []transaction.Signer{{Account: validator.ScriptHash()}}
  1973  						require.NoError(t, validator.SignTx(netmode.UnitTestNet, tx))
  1974  						conflicting := transaction.New([]byte{byte(opcode.RET)}, 1000_0000)
  1975  						conflicting.ValidUntilBlock = bc.BlockHeight() + 1
  1976  						conflicting.Signers = []transaction.Signer{
  1977  							{
  1978  								Account: validator.ScriptHash(),
  1979  								Scopes:  transaction.CalledByEntry,
  1980  							},
  1981  						}
  1982  						conflicting.Attributes = []transaction.Attribute{
  1983  							{
  1984  								Type: transaction.ConflictsT,
  1985  								Value: &transaction.Conflicts{
  1986  									Hash: tx.Hash(),
  1987  								},
  1988  							},
  1989  						}
  1990  						conflicting.NetworkFee = 1000_0000
  1991  						require.NoError(t, validator.SignTx(netmode.UnitTestNet, conflicting))
  1992  						e.AddNewBlock(t, conflicting)
  1993  						// We expect `tx` to fail verification, because on-chained `conflicting` has
  1994  						// `tx`'s payer as a signer.
  1995  						require.ErrorIs(t, bc.VerifyTx(tx), core.ErrHasConflicts)
  1996  					})
  1997  				})
  1998  				t.Run("attribute on-chain conflict", func(t *testing.T) {
  1999  					tx := neoValidatorsInvoker.Invoke(t, stackitem.NewBool(true), "transfer", neoOwner, neoOwner, 1, nil)
  2000  					txConflict := getConflictsTx(e, tx)
  2001  					require.Error(t, bc.VerifyTx(txConflict))
  2002  				})
  2003  				t.Run("positive", func(t *testing.T) {
  2004  					tx := getConflictsTx(e, random.Uint256())
  2005  					require.NoError(t, bc.VerifyTx(tx))
  2006  				})
  2007  			})
  2008  		})
  2009  		t.Run("NotaryAssisted", func(t *testing.T) {
  2010  			notary, err := wallet.NewAccount()
  2011  			require.NoError(t, err)
  2012  			designateSuperInvoker.Invoke(t, stackitem.Null{}, "designateAsRole",
  2013  				int64(noderoles.P2PNotary), []any{notary.PublicKey().Bytes()})
  2014  			txSetNotary := transaction.New([]byte{byte(opcode.RET)}, 0)
  2015  			txSetNotary.Signers = []transaction.Signer{
  2016  				{
  2017  					Account: committee.ScriptHash(),
  2018  					Scopes:  transaction.Global,
  2019  				},
  2020  			}
  2021  			txSetNotary.Scripts = []transaction.Witness{{
  2022  				InvocationScript:   e.Committee.SignHashable(uint32(netmode.UnitTestNet), txSetNotary),
  2023  				VerificationScript: e.Committee.Script(),
  2024  			}}
  2025  
  2026  			getNotaryAssistedTx := func(e *neotest.Executor, signaturesCount uint8, serviceFee int64) *transaction.Transaction {
  2027  				tx := newTestTx(t, h, testScript)
  2028  				tx.Attributes = append(tx.Attributes, transaction.Attribute{Type: transaction.NotaryAssistedT, Value: &transaction.NotaryAssisted{
  2029  					NKeys: signaturesCount,
  2030  				}})
  2031  				tx.NetworkFee += serviceFee // additional fee for NotaryAssisted attribute
  2032  				tx.NetworkFee += 4_000_000  // multisig check
  2033  				tx.Signers = []transaction.Signer{{
  2034  					Account: e.CommitteeHash,
  2035  					Scopes:  transaction.None,
  2036  				},
  2037  					{
  2038  						Account: notaryHash,
  2039  						Scopes:  transaction.None,
  2040  					},
  2041  				}
  2042  				rawScript := committee.Script()
  2043  				size := io.GetVarSize(tx)
  2044  				netFee, sizeDelta := fee.Calculate(e.Chain.GetBaseExecFee(), rawScript)
  2045  				tx.NetworkFee += netFee
  2046  				tx.NetworkFee += int64(size+sizeDelta) * e.Chain.FeePerByte()
  2047  				tx.Scripts = []transaction.Witness{
  2048  					{
  2049  						InvocationScript:   committee.SignHashable(uint32(netmode.UnitTestNet), tx),
  2050  						VerificationScript: rawScript,
  2051  					},
  2052  					{
  2053  						InvocationScript: append([]byte{byte(opcode.PUSHDATA1), keys.SignatureLen}, notary.PrivateKey().SignHashable(uint32(netmode.UnitTestNet), tx)...),
  2054  					},
  2055  				}
  2056  				return tx
  2057  			}
  2058  			t.Run("Disabled", func(t *testing.T) {
  2059  				bcBad, validatorBad, committeeBad := chain.NewMultiWithCustomConfig(t, func(c *config.Blockchain) {
  2060  					c.P2PSigExtensions = false
  2061  					c.ReservedAttributes = false
  2062  				})
  2063  				eBad := neotest.NewExecutor(t, bcBad, validatorBad, committeeBad)
  2064  				tx := transaction.New(testScript, 1_000_000)
  2065  				tx.Nonce = neotest.Nonce()
  2066  				tx.ValidUntilBlock = e.Chain.BlockHeight() + 5
  2067  				tx.Attributes = append(tx.Attributes, transaction.Attribute{Type: transaction.NotaryAssistedT, Value: &transaction.NotaryAssisted{NKeys: 0}})
  2068  				tx.NetworkFee = 1_0000_0000
  2069  				eBad.SignTx(t, tx, 1_0000_0000, eBad.Committee)
  2070  				err := bcBad.VerifyTx(tx)
  2071  				require.Error(t, err)
  2072  				require.True(t, strings.Contains(err.Error(), "invalid attribute: NotaryAssisted attribute was found, but P2PSigExtensions are disabled"))
  2073  			})
  2074  			t.Run("Enabled, insufficient network fee", func(t *testing.T) {
  2075  				tx := getNotaryAssistedTx(e, 1, 0)
  2076  				require.Error(t, bc.VerifyTx(tx))
  2077  			})
  2078  			t.Run("Test verify", func(t *testing.T) {
  2079  				t.Run("no NotaryAssisted attribute", func(t *testing.T) {
  2080  					tx := getNotaryAssistedTx(e, 1, (1+1)*notaryServiceFeePerKey)
  2081  					tx.Attributes = []transaction.Attribute{}
  2082  					tx.Signers = []transaction.Signer{
  2083  						{
  2084  							Account: committee.ScriptHash(),
  2085  							Scopes:  transaction.None,
  2086  						},
  2087  						{
  2088  							Account: notaryHash,
  2089  							Scopes:  transaction.None,
  2090  						},
  2091  					}
  2092  					tx.Scripts = []transaction.Witness{
  2093  						{
  2094  							InvocationScript:   committee.SignHashable(uint32(netmode.UnitTestNet), tx),
  2095  							VerificationScript: committee.Script(),
  2096  						},
  2097  						{
  2098  							InvocationScript: append([]byte{byte(opcode.PUSHDATA1), keys.SignatureLen}, notary.PrivateKey().SignHashable(uint32(netmode.UnitTestNet), tx)...),
  2099  						},
  2100  					}
  2101  					require.Error(t, bc.VerifyTx(tx))
  2102  				})
  2103  				t.Run("no deposit", func(t *testing.T) {
  2104  					tx := getNotaryAssistedTx(e, 1, (1+1)*notaryServiceFeePerKey)
  2105  					tx.Signers = []transaction.Signer{
  2106  						{
  2107  							Account: notaryHash,
  2108  							Scopes:  transaction.None,
  2109  						},
  2110  						{
  2111  							Account: committee.ScriptHash(),
  2112  							Scopes:  transaction.None,
  2113  						},
  2114  					}
  2115  					tx.Scripts = []transaction.Witness{
  2116  						{
  2117  							InvocationScript: append([]byte{byte(opcode.PUSHDATA1), keys.SignatureLen}, notary.PrivateKey().SignHashable(uint32(netmode.UnitTestNet), tx)...),
  2118  						},
  2119  						{
  2120  							InvocationScript:   committee.SignHashable(uint32(netmode.UnitTestNet), tx),
  2121  							VerificationScript: committee.Script(),
  2122  						},
  2123  					}
  2124  					require.Error(t, bc.VerifyTx(tx))
  2125  				})
  2126  				t.Run("bad Notary signer scope", func(t *testing.T) {
  2127  					tx := getNotaryAssistedTx(e, 1, (1+1)*notaryServiceFeePerKey)
  2128  					tx.Signers = []transaction.Signer{
  2129  						{
  2130  							Account: committee.ScriptHash(),
  2131  							Scopes:  transaction.None,
  2132  						},
  2133  						{
  2134  							Account: notaryHash,
  2135  							Scopes:  transaction.CalledByEntry,
  2136  						},
  2137  					}
  2138  					tx.Scripts = []transaction.Witness{
  2139  						{
  2140  							InvocationScript:   committee.SignHashable(uint32(netmode.UnitTestNet), tx),
  2141  							VerificationScript: committee.Script(),
  2142  						},
  2143  						{
  2144  							InvocationScript: append([]byte{byte(opcode.PUSHDATA1), keys.SignatureLen}, notary.PrivateKey().SignHashable(uint32(netmode.UnitTestNet), tx)...),
  2145  						},
  2146  					}
  2147  					require.Error(t, bc.VerifyTx(tx))
  2148  				})
  2149  				t.Run("not signed by Notary", func(t *testing.T) {
  2150  					tx := getNotaryAssistedTx(e, 1, (1+1)*notaryServiceFeePerKey)
  2151  					tx.Signers = []transaction.Signer{
  2152  						{
  2153  							Account: committee.ScriptHash(),
  2154  							Scopes:  transaction.None,
  2155  						},
  2156  					}
  2157  					tx.Scripts = []transaction.Witness{
  2158  						{
  2159  							InvocationScript:   committee.SignHashable(uint32(netmode.UnitTestNet), tx),
  2160  							VerificationScript: committee.Script(),
  2161  						},
  2162  					}
  2163  					require.Error(t, bc.VerifyTx(tx))
  2164  				})
  2165  				t.Run("bad Notary node witness", func(t *testing.T) {
  2166  					tx := getNotaryAssistedTx(e, 1, (1+1)*notaryServiceFeePerKey)
  2167  					tx.Signers = []transaction.Signer{
  2168  						{
  2169  							Account: committee.ScriptHash(),
  2170  							Scopes:  transaction.None,
  2171  						},
  2172  						{
  2173  							Account: notaryHash,
  2174  							Scopes:  transaction.None,
  2175  						},
  2176  					}
  2177  					acc, err := keys.NewPrivateKey()
  2178  					require.NoError(t, err)
  2179  					tx.Scripts = []transaction.Witness{
  2180  						{
  2181  							InvocationScript:   committee.SignHashable(uint32(netmode.UnitTestNet), tx),
  2182  							VerificationScript: committee.Script(),
  2183  						},
  2184  						{
  2185  							InvocationScript: append([]byte{byte(opcode.PUSHDATA1), keys.SignatureLen}, acc.SignHashable(uint32(netmode.UnitTestNet), tx)...),
  2186  						},
  2187  					}
  2188  					require.Error(t, bc.VerifyTx(tx))
  2189  				})
  2190  				t.Run("missing payer", func(t *testing.T) {
  2191  					tx := getNotaryAssistedTx(e, 1, (1+1)*notaryServiceFeePerKey)
  2192  					tx.Signers = []transaction.Signer{
  2193  						{
  2194  							Account: notaryHash,
  2195  							Scopes:  transaction.None,
  2196  						},
  2197  					}
  2198  					tx.Scripts = []transaction.Witness{
  2199  						{
  2200  							InvocationScript: append([]byte{byte(opcode.PUSHDATA1), keys.SignatureLen}, notary.PrivateKey().SignHashable(uint32(netmode.UnitTestNet), tx)...),
  2201  						},
  2202  					}
  2203  					require.Error(t, bc.VerifyTx(tx))
  2204  				})
  2205  				t.Run("positive", func(t *testing.T) {
  2206  					tx := getNotaryAssistedTx(e, 1, (1+1)*notaryServiceFeePerKey)
  2207  					require.NoError(t, bc.VerifyTx(tx))
  2208  				})
  2209  			})
  2210  		})
  2211  	})
  2212  	t.Run("Partially-filled transaction", func(t *testing.T) {
  2213  		getPartiallyFilledTx := func(nvb uint32, validUntil uint32) *transaction.Transaction {
  2214  			tx := newTestTx(t, h, testScript)
  2215  			tx.ValidUntilBlock = validUntil
  2216  			tx.Attributes = []transaction.Attribute{
  2217  				{
  2218  					Type:  transaction.NotValidBeforeT,
  2219  					Value: &transaction.NotValidBefore{Height: nvb},
  2220  				},
  2221  				{
  2222  					Type:  transaction.NotaryAssistedT,
  2223  					Value: &transaction.NotaryAssisted{NKeys: 0},
  2224  				},
  2225  			}
  2226  			tx.Signers = []transaction.Signer{
  2227  				{
  2228  					Account: notaryHash,
  2229  					Scopes:  transaction.None,
  2230  				},
  2231  				{
  2232  					Account: validator.ScriptHash(),
  2233  					Scopes:  transaction.None,
  2234  				},
  2235  			}
  2236  			size := io.GetVarSize(tx)
  2237  			netFee, sizeDelta := fee.Calculate(bc.GetBaseExecFee(), validator.Script())
  2238  			tx.NetworkFee = netFee + // multisig witness verification price
  2239  				int64(size)*bc.FeePerByte() + // fee for unsigned size
  2240  				int64(sizeDelta)*bc.FeePerByte() + // fee for multisig size
  2241  				66*bc.FeePerByte() + // fee for Notary signature size (66 bytes for Invocation script and 0 bytes for Verification script)
  2242  				2*bc.FeePerByte() + // fee for the length of each script in Notary witness (they are nil, so we did not take them into account during `size` calculation)
  2243  				notaryServiceFeePerKey + // fee for Notary attribute
  2244  				fee.Opcode(bc.GetBaseExecFee(), // Notary verification script
  2245  					opcode.PUSHDATA1, opcode.RET, // invocation script
  2246  					opcode.PUSH0, opcode.SYSCALL, opcode.RET) + // Neo.Native.Call
  2247  				nativeprices.NotaryVerificationPrice*bc.GetBaseExecFee() // Notary witness verification price
  2248  			tx.Scripts = []transaction.Witness{
  2249  				{
  2250  					InvocationScript:   append([]byte{byte(opcode.PUSHDATA1), keys.SignatureLen}, make([]byte, keys.SignatureLen)...),
  2251  					VerificationScript: []byte{},
  2252  				},
  2253  				{
  2254  					InvocationScript:   validator.SignHashable(uint32(netmode.UnitTestNet), tx),
  2255  					VerificationScript: validator.Script(),
  2256  				},
  2257  			}
  2258  			return tx
  2259  		}
  2260  
  2261  		mp := mempool.New(10, 1, false, nil)
  2262  		verificationF := func(tx *transaction.Transaction, data any) error {
  2263  			if data.(int) > 5 {
  2264  				return errors.New("bad data")
  2265  			}
  2266  			return nil
  2267  		}
  2268  		t.Run("failed pre-verification", func(t *testing.T) {
  2269  			tx := getPartiallyFilledTx(bc.BlockHeight(), bc.BlockHeight()+1)
  2270  			require.Error(t, bc.PoolTxWithData(tx, 6, mp, bc, verificationF)) // here and below let's use `bc` instead of proper NotaryFeer for the test simplicity.
  2271  		})
  2272  		t.Run("GasLimitExceeded during witness verification", func(t *testing.T) {
  2273  			tx := getPartiallyFilledTx(bc.BlockHeight(), bc.BlockHeight()+1)
  2274  			tx.NetworkFee-- // to check that NetworkFee was set correctly in getPartiallyFilledTx
  2275  			tx.Scripts = []transaction.Witness{
  2276  				{
  2277  					InvocationScript:   append([]byte{byte(opcode.PUSHDATA1), keys.SignatureLen}, make([]byte, keys.SignatureLen)...),
  2278  					VerificationScript: []byte{},
  2279  				},
  2280  				{
  2281  					InvocationScript:   validator.SignHashable(uint32(netmode.UnitTestNet), tx),
  2282  					VerificationScript: validator.Script(),
  2283  				},
  2284  			}
  2285  			require.Error(t, bc.PoolTxWithData(tx, 5, mp, bc, verificationF))
  2286  		})
  2287  		t.Run("bad NVB: too big", func(t *testing.T) {
  2288  			maxNVB, err := bc.GetMaxNotValidBeforeDelta()
  2289  			require.NoError(t, err)
  2290  			tx := getPartiallyFilledTx(bc.BlockHeight()+maxNVB+1, bc.BlockHeight()+1)
  2291  			require.ErrorIs(t, bc.PoolTxWithData(tx, 5, mp, bc, verificationF), core.ErrInvalidAttribute)
  2292  		})
  2293  		t.Run("bad ValidUntilBlock: too small", func(t *testing.T) {
  2294  			maxNVB, err := bc.GetMaxNotValidBeforeDelta()
  2295  			require.NoError(t, err)
  2296  			tx := getPartiallyFilledTx(bc.BlockHeight(), bc.BlockHeight()+maxNVB+1)
  2297  			require.ErrorIs(t, bc.PoolTxWithData(tx, 5, mp, bc, verificationF), core.ErrInvalidAttribute)
  2298  		})
  2299  		t.Run("good", func(t *testing.T) {
  2300  			tx := getPartiallyFilledTx(bc.BlockHeight(), bc.BlockHeight()+1)
  2301  			require.NoError(t, bc.PoolTxWithData(tx, 5, mp, bc, verificationF))
  2302  		})
  2303  	})
  2304  }
  2305  
  2306  func TestBlockchain_Bug1728(t *testing.T) {
  2307  	bc, acc := chain.NewSingle(t)
  2308  	e := neotest.NewExecutor(t, bc, acc, acc)
  2309  	managementInvoker := e.ValidatorInvoker(e.NativeHash(t, nativenames.Management))
  2310  
  2311  	src := `package example
  2312  	import "github.com/nspcc-dev/neo-go/pkg/interop/runtime"
  2313  	func init() { if true { } else { } }
  2314  	func _deploy(_ any, isUpdate bool) {
  2315  		runtime.Log("Deploy")
  2316  	}`
  2317  	c := neotest.CompileSource(t, acc.ScriptHash(), strings.NewReader(src), &compiler.Options{Name: "TestContract"})
  2318  	managementInvoker.DeployContract(t, c, nil)
  2319  }
  2320  
  2321  func TestBlockchain_ResetStateErrors(t *testing.T) {
  2322  	chainHeight := 3
  2323  	checkResetErr := func(t *testing.T, cfg func(c *config.Blockchain), h uint32, errText string) {
  2324  		db, path := newLevelDBForTestingWithPath(t, t.TempDir())
  2325  		bc, validators, committee := chain.NewMultiWithCustomConfigAndStore(t, cfg, db, false)
  2326  		e := neotest.NewExecutor(t, bc, validators, committee)
  2327  		go bc.Run()
  2328  		for i := 0; i < chainHeight; i++ {
  2329  			e.AddNewBlock(t) // get some height
  2330  		}
  2331  		bc.Close()
  2332  
  2333  		db, _ = newLevelDBForTestingWithPath(t, path)
  2334  		defer db.Close()
  2335  		bc, _, _ = chain.NewMultiWithCustomConfigAndStore(t, cfg, db, false)
  2336  		err := bc.Reset(h)
  2337  		if errText != "" {
  2338  			require.Error(t, err)
  2339  			require.True(t, strings.Contains(err.Error(), errText), err)
  2340  		} else {
  2341  			require.NoError(t, err)
  2342  		}
  2343  	}
  2344  	t.Run("large height", func(t *testing.T) {
  2345  		checkResetErr(t, nil, uint32(chainHeight+1), "can't reset state to height 4")
  2346  	})
  2347  	t.Run("already at height", func(t *testing.T) {
  2348  		checkResetErr(t, nil, uint32(chainHeight), "")
  2349  	})
  2350  	t.Run("KeepOnlyLatestState is enabled", func(t *testing.T) {
  2351  		checkResetErr(t, func(c *config.Blockchain) {
  2352  			c.Ledger.KeepOnlyLatestState = true
  2353  		}, uint32(chainHeight-1), "KeepOnlyLatestState is enabled")
  2354  	})
  2355  	t.Run("some blocks where removed", func(t *testing.T) {
  2356  		checkResetErr(t, func(c *config.Blockchain) {
  2357  			c.Ledger.RemoveUntraceableBlocks = true
  2358  			c.MaxTraceableBlocks = 2
  2359  		}, uint32(chainHeight-3), "RemoveUntraceableBlocks is enabled, a necessary batch of traceable blocks has already been removed")
  2360  	})
  2361  }
  2362  
  2363  // TestBlockchain_ResetState is based on knowledge about basic chain transactions,
  2364  // it performs basic chain reset and checks that reset chain has proper state.
  2365  func TestBlockchain_ResetState(t *testing.T) {
  2366  	// Create the DB.
  2367  	db, path := newLevelDBForTestingWithPath(t, t.TempDir())
  2368  	bc, validators, committee := chain.NewMultiWithCustomConfigAndStore(t, func(cfg *config.Blockchain) {
  2369  		cfg.P2PSigExtensions = true
  2370  	}, db, false)
  2371  	go bc.Run()
  2372  	e := neotest.NewExecutor(t, bc, validators, committee)
  2373  	basicchain.Init(t, "../../", e)
  2374  
  2375  	// Gather some reference information.
  2376  	resetBlockIndex := uint32(15)
  2377  	staleID := basicchain.NFSOContractID // NEP11
  2378  	rublesH := e.ContractHash(t, basicchain.RublesContractID)
  2379  	nnsH := e.ContractHash(t, basicchain.NNSContractID)
  2380  	staleH := e.ContractHash(t, staleID)
  2381  	gasH := e.NativeHash(t, nativenames.Gas)
  2382  	neoH := e.NativeHash(t, nativenames.Neo)
  2383  	gasID := e.NativeID(t, nativenames.Gas)
  2384  	neoID := e.NativeID(t, nativenames.Neo)
  2385  	resetBlockHash := bc.GetHeaderHash(resetBlockIndex)
  2386  	resetBlockHeader, err := bc.GetHeader(resetBlockHash)
  2387  	require.NoError(t, err)
  2388  	topBlockHeight := bc.BlockHeight()
  2389  	topBH := bc.GetHeaderHash(bc.BlockHeight())
  2390  	staleBH := bc.GetHeaderHash(resetBlockIndex + 1)
  2391  	staleB, err := bc.GetBlock(staleBH)
  2392  	require.NoError(t, err)
  2393  	staleTx := staleB.Transactions[0]
  2394  	_, err = bc.GetAppExecResults(staleTx.Hash(), trigger.Application)
  2395  	require.NoError(t, err)
  2396  	sr, err := bc.GetStateModule().GetStateRoot(resetBlockIndex)
  2397  	require.NoError(t, err)
  2398  	staleSR, err := bc.GetStateModule().GetStateRoot(resetBlockIndex + 1)
  2399  	require.NoError(t, err)
  2400  	rublesKey := []byte("testkey")
  2401  	rublesStaleKey := []byte("aa")
  2402  	rublesStaleValue := bc.GetStorageItem(basicchain.RublesContractID, rublesKey) // check value is there
  2403  	require.Equal(t, []byte(basicchain.RublesNewTestvalue), []byte(rublesStaleValue))
  2404  	acc0 := e.Validator.(neotest.MultiSigner).Single(2) // priv0 index->order and order->index conversion
  2405  	priv0ScriptHash := acc0.ScriptHash()
  2406  	var (
  2407  		expectedNEP11t []*state.NEP11Transfer
  2408  		expectedNEP17t []*state.NEP17Transfer
  2409  	)
  2410  	require.NoError(t, bc.ForEachNEP11Transfer(priv0ScriptHash, resetBlockHeader.Timestamp, func(t *state.NEP11Transfer) (bool, error) {
  2411  		if t.Block <= resetBlockIndex {
  2412  			expectedNEP11t = append(expectedNEP11t, t)
  2413  		}
  2414  		return true, nil
  2415  	}))
  2416  	require.NoError(t, bc.ForEachNEP17Transfer(priv0ScriptHash, resetBlockHeader.Timestamp, func(t *state.NEP17Transfer) (bool, error) {
  2417  		if t.Block <= resetBlockIndex {
  2418  			expectedNEP17t = append(expectedNEP17t, t)
  2419  		}
  2420  		return true, nil
  2421  	}))
  2422  
  2423  	// checkProof checks that some stale proof is reachable
  2424  	checkProof := func() {
  2425  		rublesStaleFullKey := make([]byte, 4)
  2426  		binary.LittleEndian.PutUint32(rublesStaleFullKey, uint32(basicchain.RublesContractID))
  2427  		rublesStaleFullKey = append(rublesStaleFullKey, rublesStaleKey...)
  2428  		proof, err := bc.GetStateModule().GetStateProof(staleSR.Root, rublesStaleFullKey)
  2429  		require.NoError(t, err)
  2430  		require.NotEmpty(t, proof)
  2431  	}
  2432  	checkProof()
  2433  
  2434  	// Ensure all changes were persisted.
  2435  	bc.Close()
  2436  
  2437  	// Start new chain with existing DB, but do not run it.
  2438  	db, _ = newLevelDBForTestingWithPath(t, path)
  2439  	bc, _, _ = chain.NewMultiWithCustomConfigAndStore(t, func(cfg *config.Blockchain) {
  2440  		cfg.P2PSigExtensions = true
  2441  	}, db, false)
  2442  	defer db.Close()
  2443  	require.Equal(t, topBlockHeight, bc.BlockHeight()) // ensure DB was properly initialized.
  2444  
  2445  	// Reset state.
  2446  	require.NoError(t, bc.Reset(resetBlockIndex))
  2447  
  2448  	// Check that state was properly reset.
  2449  	require.Equal(t, resetBlockIndex, bc.BlockHeight())
  2450  	require.Equal(t, resetBlockIndex, bc.HeaderHeight())
  2451  	require.Equal(t, resetBlockHash, bc.CurrentHeaderHash())
  2452  	require.Equal(t, resetBlockHash, bc.CurrentBlockHash())
  2453  	require.Equal(t, resetBlockIndex, bc.GetStateModule().CurrentLocalHeight())
  2454  	require.Equal(t, sr.Root, bc.GetStateModule().CurrentLocalStateRoot())
  2455  	require.Equal(t, uint32(0), bc.GetStateModule().CurrentValidatedHeight())
  2456  
  2457  	// Try to get the latest block\header.
  2458  	bh := bc.GetHeaderHash(resetBlockIndex)
  2459  	require.Equal(t, resetBlockHash, bh)
  2460  	h, err := bc.GetHeader(bh)
  2461  	require.NoError(t, err)
  2462  	require.Equal(t, resetBlockHeader, h)
  2463  	actualRublesHash, err := bc.GetContractScriptHash(basicchain.RublesContractID)
  2464  	require.NoError(t, err)
  2465  	require.Equal(t, rublesH, actualRublesHash)
  2466  
  2467  	// Check that stale blocks/headers/txs/aers/sr are not reachable.
  2468  	for i := resetBlockIndex + 1; i <= topBlockHeight; i++ {
  2469  		hHash := bc.GetHeaderHash(i)
  2470  		require.Equal(t, util.Uint256{}, hHash)
  2471  		_, err = bc.GetStateRoot(i)
  2472  		require.Error(t, err)
  2473  	}
  2474  	for _, h := range []util.Uint256{staleBH, topBH} {
  2475  		_, err = bc.GetHeader(h)
  2476  		require.Error(t, err)
  2477  		_, err = bc.GetHeader(h)
  2478  		require.Error(t, err)
  2479  	}
  2480  	_, _, err = bc.GetTransaction(staleTx.Hash())
  2481  	require.Error(t, err)
  2482  	_, err = bc.GetAppExecResults(staleTx.Hash(), trigger.Application)
  2483  	require.Error(t, err)
  2484  
  2485  	// However, proofs and everything related to stale MPT nodes still should work properly,
  2486  	// because we don't remove stale MPT nodes.
  2487  	checkProof()
  2488  
  2489  	// Check NEP-compatible contracts.
  2490  	nep11 := bc.GetNEP11Contracts()
  2491  	require.Equal(t, 1, len(nep11)) // NNS
  2492  	require.Equal(t, nnsH, nep11[0])
  2493  	nep17 := bc.GetNEP17Contracts()
  2494  	require.Equal(t, 3, len(nep17)) // Neo, Gas, Rubles
  2495  	require.ElementsMatch(t, []util.Uint160{gasH, neoH, rublesH}, nep17)
  2496  
  2497  	// Retrieve stale contract.
  2498  	cs := bc.GetContractState(staleH)
  2499  	require.Nil(t, cs)
  2500  
  2501  	// Retrieve stale storage item.
  2502  	rublesValue := bc.GetStorageItem(basicchain.RublesContractID, rublesKey)
  2503  	require.Equal(t, []byte(basicchain.RublesOldTestvalue), []byte(rublesValue))   // the one with historic state
  2504  	require.Nil(t, bc.GetStorageItem(basicchain.RublesContractID, rublesStaleKey)) // the one that was added after target reset block
  2505  	db.Seek(storage.SeekRange{
  2506  		Prefix: []byte{byte(storage.STStorage)}, // no items with old prefix
  2507  	}, func(k, v []byte) bool {
  2508  		t.Fatal("no stale items must be left in storage")
  2509  		return false
  2510  	})
  2511  
  2512  	// Check transfers.
  2513  	var (
  2514  		actualNEP11t []*state.NEP11Transfer
  2515  		actualNEP17t []*state.NEP17Transfer
  2516  	)
  2517  	require.NoError(t, bc.ForEachNEP11Transfer(priv0ScriptHash, e.TopBlock(t).Timestamp, func(t *state.NEP11Transfer) (bool, error) {
  2518  		actualNEP11t = append(actualNEP11t, t)
  2519  		return true, nil
  2520  	}))
  2521  	require.NoError(t, bc.ForEachNEP17Transfer(priv0ScriptHash, e.TopBlock(t).Timestamp, func(t *state.NEP17Transfer) (bool, error) {
  2522  		actualNEP17t = append(actualNEP17t, t)
  2523  		return true, nil
  2524  	}))
  2525  	assert.Equal(t, expectedNEP11t, actualNEP11t)
  2526  	assert.Equal(t, expectedNEP17t, actualNEP17t)
  2527  	lub, err := bc.GetTokenLastUpdated(priv0ScriptHash)
  2528  	require.NoError(t, err)
  2529  	expectedLUB := map[int32]uint32{ // this information is extracted from basic chain initialization code
  2530  		basicchain.NNSContractID:    resetBlockIndex - 1, // `neo.com` registration
  2531  		basicchain.RublesContractID: 6,                   // transfer of 123 RUR to priv1
  2532  		gasID:                       resetBlockIndex,     // fee for `1.2.3.4` A record registration
  2533  		neoID:                       4,                   // transfer of 1000 NEO to priv1
  2534  	}
  2535  	require.Equal(t, expectedLUB, lub)
  2536  }
  2537  
  2538  func TestBlockchain_GenesisTransactionExtension(t *testing.T) {
  2539  	priv0 := testchain.PrivateKeyByID(0)
  2540  	acc0 := wallet.NewAccountFromPrivateKey(priv0)
  2541  	require.NoError(t, acc0.ConvertMultisig(1, []*keys.PublicKey{priv0.PublicKey()}))
  2542  	from := acc0.ScriptHash()
  2543  	to := util.Uint160{1, 2, 3}
  2544  	amount := 1
  2545  
  2546  	script := io.NewBufBinWriter()
  2547  	emit.Bytes(script.BinWriter, from.BytesBE())
  2548  	emit.Syscall(script.BinWriter, interopnames.SystemRuntimeCheckWitness)
  2549  	emit.Bytes(script.BinWriter, to.BytesBE())
  2550  	emit.Syscall(script.BinWriter, interopnames.SystemRuntimeCheckWitness)
  2551  	emit.AppCall(script.BinWriter, nativehashes.NeoToken, "transfer", callflag.All, from, to, amount, nil)
  2552  	emit.Opcodes(script.BinWriter, opcode.ASSERT)
  2553  
  2554  	var sysFee int64 = 1_0000_0000
  2555  	bc, acc := chain.NewSingleWithCustomConfig(t, func(blockchain *config.Blockchain) {
  2556  		blockchain.Genesis.Transaction = &config.GenesisTransaction{
  2557  			Script:    script.Bytes(),
  2558  			SystemFee: sysFee,
  2559  		}
  2560  	})
  2561  	e := neotest.NewExecutor(t, bc, acc, acc)
  2562  	b := e.GetBlockByIndex(t, 0)
  2563  	tx := b.Transactions[0]
  2564  	e.CheckHalt(t, tx.Hash(), stackitem.NewBool(true), stackitem.NewBool(false))
  2565  	e.CheckGASBalance(t, e.Validator.ScriptHash(), big.NewInt(core.DefaultInitialGAS-sysFee))
  2566  	actualNeo, lub := e.Chain.GetGoverningTokenBalance(to)
  2567  	require.Equal(t, int64(amount), actualNeo.Int64())
  2568  	require.Equal(t, 0, int(lub))
  2569  }
  2570  
  2571  // TestNativenames ensures that nativenames.All contains all expected native contract names
  2572  // in the right order.
  2573  func TestNativenames(t *testing.T) {
  2574  	bc, _ := chain.NewSingleWithCustomConfig(t, func(cfg *config.Blockchain) {
  2575  		cfg.Hardforks = map[string]uint32{}
  2576  		cfg.P2PSigExtensions = true
  2577  	})
  2578  	natives := bc.GetNatives()
  2579  	require.Equal(t, len(natives), len(nativenames.All))
  2580  	for i, cs := range natives {
  2581  		require.Equal(t, cs.Manifest.Name, nativenames.All[i], i)
  2582  	}
  2583  }
  2584  
  2585  // TestBlockchain_StoreAsTransaction_ExecutableConflict ensures that transaction conflicting with
  2586  // some on-chain block can be properly stored and doesn't break the database.
  2587  func TestBlockchain_StoreAsTransaction_ExecutableConflict(t *testing.T) {
  2588  	bc, acc := chain.NewSingleWithCustomConfig(t, nil)
  2589  	e := neotest.NewExecutor(t, bc, acc, acc)
  2590  	genesisH := bc.GetHeaderHash(0)
  2591  	currHeight := bc.BlockHeight()
  2592  
  2593  	// Ensure AER can be retrieved for genesis block.
  2594  	aer, err := bc.GetAppExecResults(genesisH, trigger.All)
  2595  	require.NoError(t, err)
  2596  	require.Equal(t, 2, len(aer))
  2597  
  2598  	tx := transaction.New([]byte{byte(opcode.PUSHT)}, 0)
  2599  	tx.Nonce = 5
  2600  	tx.ValidUntilBlock = e.Chain.BlockHeight() + 1
  2601  	tx.Attributes = []transaction.Attribute{{Type: transaction.ConflictsT, Value: &transaction.Conflicts{Hash: genesisH}}}
  2602  	e.SignTx(t, tx, -1, acc)
  2603  	e.AddNewBlock(t, tx)
  2604  	e.CheckHalt(t, tx.Hash(), stackitem.Make(true))
  2605  
  2606  	// Ensure original tx can be retrieved.
  2607  	actual, actualHeight, err := bc.GetTransaction(tx.Hash())
  2608  	require.NoError(t, err)
  2609  	require.Equal(t, currHeight+1, actualHeight)
  2610  	require.Equal(t, tx, actual, tx)
  2611  
  2612  	// Ensure conflict stub is not stored. This check doesn't give us 100% sure that
  2613  	// there's no specific conflict record since GetTransaction doesn't return conflict records,
  2614  	// but at least it allows to ensure that no transaction record is present.
  2615  	_, _, err = bc.GetTransaction(genesisH)
  2616  	require.ErrorIs(t, err, storage.ErrKeyNotFound)
  2617  
  2618  	// Ensure AER still can be retrieved for genesis block.
  2619  	aer, err = bc.GetAppExecResults(genesisH, trigger.All)
  2620  	require.NoError(t, err)
  2621  	require.Equal(t, 2, len(aer))
  2622  }