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

     1  package core_test
     2  
     3  import (
     4  	"fmt"
     5  	"math/big"
     6  	"path/filepath"
     7  	"testing"
     8  
     9  	"github.com/nspcc-dev/neo-go/internal/random"
    10  	"github.com/nspcc-dev/neo-go/pkg/config/netmode"
    11  	"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
    12  	"github.com/nspcc-dev/neo-go/pkg/core/state"
    13  	"github.com/nspcc-dev/neo-go/pkg/core/storage"
    14  	"github.com/nspcc-dev/neo-go/pkg/core/storage/dbconfig"
    15  	"github.com/nspcc-dev/neo-go/pkg/core/transaction"
    16  	"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
    17  	"github.com/nspcc-dev/neo-go/pkg/neotest"
    18  	"github.com/nspcc-dev/neo-go/pkg/neotest/chain"
    19  	"github.com/nspcc-dev/neo-go/pkg/smartcontract"
    20  	"github.com/nspcc-dev/neo-go/pkg/wallet"
    21  	"github.com/stretchr/testify/require"
    22  )
    23  
    24  func BenchmarkBlockchain_VerifyWitness(t *testing.B) {
    25  	bc, acc := chain.NewSingle(t)
    26  	e := neotest.NewExecutor(t, bc, acc, acc)
    27  	tx := e.NewTx(t, []neotest.Signer{acc}, e.NativeHash(t, nativenames.Gas), "transfer", acc.ScriptHash(), acc.Script(), 1, nil)
    28  
    29  	t.ResetTimer()
    30  	for n := 0; n < t.N; n++ {
    31  		_, err := bc.VerifyWitness(tx.Signers[0].Account, tx, &tx.Scripts[0], 100000000)
    32  		require.NoError(t, err)
    33  	}
    34  }
    35  
    36  func BenchmarkBlockchain_ForEachNEP17Transfer(t *testing.B) {
    37  	var stores = map[string]func(testing.TB) storage.Store{
    38  		"MemPS": func(t testing.TB) storage.Store {
    39  			return storage.NewMemoryStore()
    40  		},
    41  		"BoltPS":  newBoltStoreForTesting,
    42  		"LevelPS": newLevelDBForTesting,
    43  	}
    44  	startFrom := []int{1, 100, 1000}
    45  	blocksToTake := []int{100, 1000}
    46  	for psName, newPS := range stores {
    47  		for _, startFromBlock := range startFrom {
    48  			for _, nBlocksToTake := range blocksToTake {
    49  				t.Run(fmt.Sprintf("%s_StartFromBlockN-%d_Take%dBlocks", psName, startFromBlock, nBlocksToTake), func(t *testing.B) {
    50  					ps := newPS(t)
    51  					t.Cleanup(func() { ps.Close() })
    52  					benchmarkForEachNEP17Transfer(t, ps, startFromBlock, nBlocksToTake)
    53  				})
    54  			}
    55  		}
    56  	}
    57  }
    58  
    59  func BenchmarkNEO_GetGASPerVote(t *testing.B) {
    60  	var stores = map[string]func(testing.TB) storage.Store{
    61  		"MemPS": func(t testing.TB) storage.Store {
    62  			return storage.NewMemoryStore()
    63  		},
    64  		"BoltPS":  newBoltStoreForTesting,
    65  		"LevelPS": newLevelDBForTesting,
    66  	}
    67  	for psName, newPS := range stores {
    68  		for nRewardRecords := 10; nRewardRecords <= 1000; nRewardRecords *= 10 {
    69  			for rewardDistance := 1; rewardDistance <= 1000; rewardDistance *= 10 {
    70  				t.Run(fmt.Sprintf("%s_%dRewardRecords_%dRewardDistance", psName, nRewardRecords, rewardDistance), func(t *testing.B) {
    71  					ps := newPS(t)
    72  					t.Cleanup(func() { ps.Close() })
    73  					benchmarkGasPerVote(t, ps, nRewardRecords, rewardDistance)
    74  				})
    75  			}
    76  		}
    77  	}
    78  }
    79  
    80  func benchmarkForEachNEP17Transfer(t *testing.B, ps storage.Store, startFromBlock, nBlocksToTake int) {
    81  	var (
    82  		chainHeight       = 2_100                            // constant chain height to be able to compare paging results
    83  		transfersPerBlock = state.TokenTransferBatchSize/4 + // 4 blocks per batch
    84  			state.TokenTransferBatchSize/32 // shift
    85  	)
    86  
    87  	bc, validators, committee := chain.NewMultiWithCustomConfigAndStore(t, nil, ps, true)
    88  
    89  	e := neotest.NewExecutor(t, bc, validators, committee)
    90  	gasHash := e.NativeHash(t, nativenames.Gas)
    91  
    92  	acc := random.Uint160()
    93  	from := e.Validator.ScriptHash()
    94  
    95  	for j := 0; j < chainHeight; j++ {
    96  		b := smartcontract.NewBuilder()
    97  		for i := 0; i < transfersPerBlock; i++ {
    98  			b.InvokeWithAssert(gasHash, "transfer", from, acc, 1, nil)
    99  		}
   100  		script, err := b.Script()
   101  		require.NoError(t, err)
   102  		tx := transaction.New(script, int64(1100_0000*transfersPerBlock))
   103  		tx.NetworkFee = 1_0000_000
   104  		tx.ValidUntilBlock = bc.BlockHeight() + 1
   105  		tx.Nonce = neotest.Nonce()
   106  		tx.Signers = []transaction.Signer{{Account: from, Scopes: transaction.CalledByEntry}}
   107  		require.NoError(t, validators.SignTx(netmode.UnitTestNet, tx))
   108  		e.AddNewBlock(t, tx)
   109  		e.CheckHalt(t, tx.Hash())
   110  	}
   111  
   112  	newestB, err := bc.GetBlock(bc.GetHeaderHash(bc.BlockHeight() - uint32(startFromBlock) + 1))
   113  	require.NoError(t, err)
   114  	newestTimestamp := newestB.Timestamp
   115  	oldestB, err := bc.GetBlock(bc.GetHeaderHash(newestB.Index - uint32(nBlocksToTake)))
   116  	require.NoError(t, err)
   117  	oldestTimestamp := oldestB.Timestamp
   118  
   119  	t.ResetTimer()
   120  	t.ReportAllocs()
   121  	t.StartTimer()
   122  	for i := 0; i < t.N; i++ {
   123  		require.NoError(t, bc.ForEachNEP17Transfer(acc, newestTimestamp, func(t *state.NEP17Transfer) (bool, error) {
   124  			if t.Timestamp < oldestTimestamp {
   125  				// iterating from newest to oldest, already have reached the needed height
   126  				return false, nil
   127  			}
   128  			return true, nil
   129  		}))
   130  	}
   131  	t.StopTimer()
   132  }
   133  
   134  func newLevelDBForTesting(t testing.TB) storage.Store {
   135  	dbPath := t.TempDir()
   136  	dbOptions := dbconfig.LevelDBOptions{
   137  		DataDirectoryPath: dbPath,
   138  	}
   139  	newLevelStore, err := storage.NewLevelDBStore(dbOptions)
   140  	require.Nil(t, err, "NewLevelDBStore error")
   141  	return newLevelStore
   142  }
   143  
   144  func newBoltStoreForTesting(t testing.TB) storage.Store {
   145  	d := t.TempDir()
   146  	dbPath := filepath.Join(d, "test_bolt_db")
   147  	boltDBStore, err := storage.NewBoltDBStore(dbconfig.BoltDBOptions{FilePath: dbPath})
   148  	require.NoError(t, err)
   149  	return boltDBStore
   150  }
   151  
   152  func benchmarkGasPerVote(t *testing.B, ps storage.Store, nRewardRecords int, rewardDistance int) {
   153  	bc, validators, committee := chain.NewMultiWithCustomConfigAndStore(t, nil, ps, true)
   154  	cfg := bc.GetConfig()
   155  
   156  	e := neotest.NewExecutor(t, bc, validators, committee)
   157  	neoHash := e.NativeHash(t, nativenames.Neo)
   158  	gasHash := e.NativeHash(t, nativenames.Gas)
   159  	neoSuperInvoker := e.NewInvoker(neoHash, validators, committee)
   160  	neoValidatorsInvoker := e.ValidatorInvoker(neoHash)
   161  	gasValidatorsInvoker := e.ValidatorInvoker(gasHash)
   162  
   163  	// Vote for new committee.
   164  	sz := len(cfg.StandbyCommittee)
   165  	voters := make([]*wallet.Account, sz)
   166  	candidates := make(keys.PublicKeys, sz)
   167  	txs := make([]*transaction.Transaction, 0, len(voters)*3)
   168  	for i := 0; i < sz; i++ {
   169  		priv, err := keys.NewPrivateKey()
   170  		require.NoError(t, err)
   171  		candidates[i] = priv.PublicKey()
   172  		voters[i], err = wallet.NewAccount()
   173  		require.NoError(t, err)
   174  		registerTx := neoSuperInvoker.PrepareInvoke(t, "registerCandidate", candidates[i].Bytes())
   175  		txs = append(txs, registerTx)
   176  
   177  		to := voters[i].Contract.ScriptHash()
   178  		transferNeoTx := neoValidatorsInvoker.PrepareInvoke(t, "transfer", e.Validator.ScriptHash(), to, big.NewInt(int64(sz-i)*1000000).Int64(), nil)
   179  		txs = append(txs, transferNeoTx)
   180  
   181  		transferGasTx := gasValidatorsInvoker.PrepareInvoke(t, "transfer", e.Validator.ScriptHash(), to, int64(1_000_000_000), nil)
   182  		txs = append(txs, transferGasTx)
   183  	}
   184  	e.AddNewBlock(t, txs...)
   185  	for _, tx := range txs {
   186  		e.CheckHalt(t, tx.Hash())
   187  	}
   188  	voteTxs := make([]*transaction.Transaction, 0, sz)
   189  	for i := 0; i < sz; i++ {
   190  		priv := voters[i].PrivateKey()
   191  		h := priv.GetScriptHash()
   192  		voteTx := e.NewTx(t, []neotest.Signer{neotest.NewSingleSigner(voters[i])}, neoHash, "vote", h, candidates[i].Bytes())
   193  		voteTxs = append(voteTxs, voteTx)
   194  	}
   195  	e.AddNewBlock(t, voteTxs...)
   196  	for _, tx := range voteTxs {
   197  		e.CheckHalt(t, tx.Hash())
   198  	}
   199  
   200  	// Collect set of nRewardRecords reward records for each voter.
   201  	e.GenerateNewBlocks(t, len(cfg.StandbyCommittee))
   202  
   203  	// Transfer some more NEO to first voter to update his balance height.
   204  	to := voters[0].Contract.ScriptHash()
   205  	neoValidatorsInvoker.Invoke(t, true, "transfer", e.Validator.ScriptHash(), to, int64(1), nil)
   206  
   207  	// Advance chain one more time to avoid same start/end rewarding bounds.
   208  	e.GenerateNewBlocks(t, rewardDistance)
   209  	end := bc.BlockHeight()
   210  
   211  	t.ResetTimer()
   212  	t.ReportAllocs()
   213  	t.StartTimer()
   214  	for i := 0; i < t.N; i++ {
   215  		_, err := bc.CalculateClaimable(to, end)
   216  		require.NoError(t, err)
   217  	}
   218  	t.StopTimer()
   219  }