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 }