github.com/iotexproject/iotex-core@v1.14.1-rc1/blockchain/integrity/benchmark_test.go (about) 1 // Copyright (c) 2019 IoTeX Foundation 2 // This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability 3 // or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. 4 // This source code is governed by Apache License 2.0 that can be found in the LICENSE file. 5 6 package integrity 7 8 import ( 9 "context" 10 "encoding/hex" 11 "math/big" 12 "math/rand" 13 "testing" 14 "time" 15 16 "github.com/pkg/errors" 17 "github.com/stretchr/testify/require" 18 19 ethCrypto "github.com/iotexproject/go-pkgs/crypto" 20 "github.com/iotexproject/iotex-address/address" 21 22 "github.com/iotexproject/iotex-core/action" 23 "github.com/iotexproject/iotex-core/action/protocol" 24 "github.com/iotexproject/iotex-core/action/protocol/account" 25 accountutil "github.com/iotexproject/iotex-core/action/protocol/account/util" 26 "github.com/iotexproject/iotex-core/action/protocol/execution" 27 "github.com/iotexproject/iotex-core/action/protocol/rewarding" 28 "github.com/iotexproject/iotex-core/action/protocol/rolldpos" 29 "github.com/iotexproject/iotex-core/actpool" 30 "github.com/iotexproject/iotex-core/blockchain" 31 "github.com/iotexproject/iotex-core/blockchain/block" 32 "github.com/iotexproject/iotex-core/blockchain/blockdao" 33 "github.com/iotexproject/iotex-core/blockchain/filedao" 34 "github.com/iotexproject/iotex-core/blockchain/genesis" 35 "github.com/iotexproject/iotex-core/blockindex" 36 "github.com/iotexproject/iotex-core/config" 37 "github.com/iotexproject/iotex-core/db" 38 "github.com/iotexproject/iotex-core/pkg/unit" 39 "github.com/iotexproject/iotex-core/state/factory" 40 "github.com/iotexproject/iotex-core/test/identityset" 41 "github.com/iotexproject/iotex-core/testutil" 42 ) 43 44 var ( 45 _totalActionPair = 2000 46 _contractByteCode = "60806040526101f4600055603260015534801561001b57600080fd5b506102558061002b6000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c806358931c461461003b5780637f353d5514610045575b600080fd5b61004361004f565b005b61004d610097565b005b60006001905060005b6000548110156100935760028261006f9190610114565b915060028261007e91906100e3565b9150808061008b90610178565b915050610058565b5050565b60005b6001548110156100e057600281908060018154018082558091505060019003906000526020600020016000909190919091505580806100d890610178565b91505061009a565b50565b60006100ee8261016e565b91506100f98361016e565b925082610109576101086101f0565b5b828204905092915050565b600061011f8261016e565b915061012a8361016e565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615610163576101626101c1565b5b828202905092915050565b6000819050919050565b60006101838261016e565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214156101b6576101b56101c1565b5b600182019050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fdfea2646970667358221220cb9cada3f1d447c978af17aa3529d6fe4f25f9c5a174085443e371b6940ae99b64736f6c63430008070033" 47 _contractAddr string 48 49 _randAccountSize = 50 50 _randAccountsAddr = make([]address.Address, 0) 51 _randAccountsPvk = make([]ethCrypto.PrivateKey, 0) 52 userA = identityset.Address(28) 53 priKeyA = identityset.PrivateKey(28) 54 userB = identityset.Address(29) 55 priKeyB = identityset.PrivateKey(29) 56 57 opAppend, _ = hex.DecodeString("7f353d55") 58 opMul, _ = hex.DecodeString("58931c46") 59 ) 60 61 func init() { 62 for i := 0; i < _randAccountSize; i++ { 63 pvk, _ := ethCrypto.GenerateKey() 64 _randAccountsPvk = append(_randAccountsPvk, pvk) 65 _randAccountsAddr = append(_randAccountsAddr, pvk.PublicKey().Address()) 66 } 67 } 68 69 func BenchmarkMintAndCommitBlock(b *testing.B) { 70 require := require.New(b) 71 rand.Seed(time.Now().Unix()) 72 bc, ap, err := newChainInDB() 73 require.NoError(err) 74 nonceMap := make(map[string]uint64) 75 76 for n := 0; n < b.N; n++ { 77 err = injectMultipleAccountsTransfer(nonceMap, ap) 78 require.NoError(err) 79 80 blk, err := bc.MintNewBlock(testutil.TimestampNow()) 81 require.NoError(err) 82 err = bc.ValidateBlock(blk) 83 require.NoError(err) 84 err = bc.CommitBlock(blk) 85 require.NoError(err) 86 } 87 } 88 89 func BenchmarkMintBlock(b *testing.B) { 90 require := require.New(b) 91 rand.Seed(time.Now().Unix()) 92 bc, ap, err := newChainInDB() 93 require.NoError(err) 94 nonceMap := make(map[string]uint64) 95 96 err = injectMultipleAccountsTransfer(nonceMap, ap) 97 require.NoError(err) 98 99 for n := 0; n < b.N; n++ { 100 _, err := bc.MintNewBlock(testutil.TimestampNow()) 101 require.NoError(err) 102 } 103 } 104 105 func BenchmarkValidateBlock(b *testing.B) { 106 require := require.New(b) 107 rand.Seed(time.Now().Unix()) 108 bc, ap, err := newChainInDB() 109 require.NoError(err) 110 nonceMap := make(map[string]uint64) 111 112 err = injectTransfer(nonceMap, ap) 113 require.NoError(err) 114 115 blk, err := bc.MintNewBlock(testutil.TimestampNow()) 116 require.NoError(err) 117 118 for n := 0; n < b.N; n++ { 119 err = bc.ValidateBlock(blk) 120 require.NoError(err) 121 } 122 } 123 124 func injectTransfer(nonceMap map[string]uint64, ap actpool.ActPool) error { 125 for i := 0; i < _totalActionPair; i++ { 126 nonceMap[userA.String()]++ 127 tsf1, err := action.SignedTransfer(userB.String(), priKeyA, nonceMap[userA.String()], big.NewInt(int64(rand.Intn(2))), []byte{}, testutil.TestGasLimit, big.NewInt(testutil.TestGasPriceInt64)) 128 if err != nil { 129 return err 130 } 131 err = ap.Add(context.Background(), tsf1) 132 if err != nil { 133 return err 134 } 135 nonceMap[userB.String()]++ 136 tsf2, err := action.SignedTransfer(userA.String(), priKeyB, nonceMap[userB.String()], big.NewInt(int64(rand.Intn(2))), []byte{}, testutil.TestGasLimit, big.NewInt(testutil.TestGasPriceInt64)) 137 if err != nil { 138 return err 139 } 140 err = ap.Add(context.Background(), tsf2) 141 if err != nil { 142 return err 143 } 144 } 145 return nil 146 } 147 148 func injectMultipleAccountsTransfer(nonceMap map[string]uint64, ap actpool.ActPool) error { 149 rand.Seed(time.Now().UnixNano()) 150 for i := 0; i < 2*_totalActionPair; i++ { 151 senderIdx := rand.Intn(_randAccountSize) 152 recipientIdx := senderIdx 153 for ; recipientIdx != senderIdx; recipientIdx = rand.Intn(_randAccountSize) { 154 } 155 nonceMap[_randAccountsAddr[senderIdx].String()]++ 156 tsf, err := action.SignedTransfer( 157 _randAccountsAddr[recipientIdx].String(), 158 _randAccountsPvk[senderIdx], 159 nonceMap[_randAccountsAddr[senderIdx].String()], 160 big.NewInt(int64(rand.Intn(2))), 161 []byte{}, 162 testutil.TestGasLimit, 163 big.NewInt(testutil.TestGasPriceInt64)) 164 if err != nil { 165 return err 166 } 167 if err = ap.Add(context.Background(), tsf); err != nil { 168 return err 169 } 170 } 171 return nil 172 } 173 174 // Todo: get precise gaslimit by estimateGas 175 func injectExecution(nonceMap map[string]uint64, ap actpool.ActPool) error { 176 for i := 0; i < _totalActionPair; i++ { 177 nonceMap[userA.String()]++ 178 ex1, err := action.SignedExecution(_contractAddr, priKeyA, nonceMap[userA.String()], big.NewInt(0), 2e6, big.NewInt(testutil.TestGasPriceInt64), opAppend) 179 if err != nil { 180 return err 181 } 182 err = ap.Add(context.Background(), ex1) 183 if err != nil { 184 return err 185 } 186 nonceMap[userB.String()]++ 187 ex2, err := action.SignedExecution(_contractAddr, priKeyB, nonceMap[userB.String()], big.NewInt(0), 2e6, big.NewInt(testutil.TestGasPriceInt64), opAppend) 188 if err != nil { 189 return err 190 } 191 err = ap.Add(context.Background(), ex2) 192 if err != nil { 193 return err 194 } 195 } 196 return nil 197 } 198 199 func newChainInDB() (blockchain.Blockchain, actpool.ActPool, error) { 200 cfg := config.Default 201 testTriePath, err := testutil.PathOfTempFile("trie") 202 if err != nil { 203 return nil, nil, err 204 } 205 testDBPath, err := testutil.PathOfTempFile("db") 206 if err != nil { 207 return nil, nil, err 208 } 209 testIndexPath, err := testutil.PathOfTempFile("index") 210 if err != nil { 211 return nil, nil, err 212 } 213 defer func() { 214 testutil.CleanupPath(testTriePath) 215 testutil.CleanupPath(testDBPath) 216 testutil.CleanupPath(testIndexPath) 217 }() 218 219 cfg.DB.DbPath = testTriePath 220 cfg.Chain.ChainDBPath = testDBPath 221 cfg.Chain.IndexDBPath = testIndexPath 222 cfg.Chain.EnableArchiveMode = true 223 cfg.Consensus.Scheme = config.RollDPoSScheme 224 cfg.Genesis.BlockGasLimit = genesis.Default.BlockGasLimit * 100 225 cfg.ActPool.MinGasPriceStr = "0" 226 cfg.ActPool.MaxNumActsPerAcct = 10000 227 cfg.Genesis.EnableGravityChainVoting = false 228 registry := protocol.NewRegistry() 229 var sf factory.Factory 230 kv := db.NewBoltDB(cfg.DB) 231 factoryCfg := factory.GenerateConfig(cfg.Chain, cfg.Genesis) 232 sf, err = factory.NewStateDB(factoryCfg, kv, factory.RegistryStateDBOption(registry), factory.DisableWorkingSetCacheOption()) 233 if err != nil { 234 return nil, nil, err 235 } 236 237 ap, err := actpool.NewActPool(cfg.Genesis, sf, cfg.ActPool) 238 if err != nil { 239 return nil, nil, err 240 } 241 acc := account.NewProtocol(rewarding.DepositGas) 242 if err = acc.Register(registry); err != nil { 243 return nil, nil, err 244 } 245 rp := rolldpos.NewProtocol(cfg.Genesis.NumCandidateDelegates, cfg.Genesis.NumDelegates, cfg.Genesis.NumSubEpochs) 246 if err = rp.Register(registry); err != nil { 247 return nil, nil, err 248 } 249 var indexer blockindex.Indexer 250 indexers := []blockdao.BlockIndexer{sf} 251 if _, gateway := cfg.Plugins[config.GatewayPlugin]; gateway && !cfg.Chain.EnableAsyncIndexWrite { 252 // create indexer 253 cfg.DB.DbPath = cfg.Chain.IndexDBPath 254 indexer, err = blockindex.NewIndexer(db.NewBoltDB(cfg.DB), cfg.Genesis.Hash()) 255 if err != nil { 256 return nil, nil, err 257 } 258 indexers = append(indexers, indexer) 259 } 260 cfg.Genesis.InitBalanceMap[identityset.Address(27).String()] = unit.ConvertIotxToRau(1000000000000).String() 261 // create BlockDAO 262 cfg.DB.DbPath = cfg.Chain.ChainDBPath 263 deser := block.NewDeserializer(cfg.Chain.EVMNetworkID) 264 store, err := filedao.NewFileDAO(cfg.DB, deser) 265 if err != nil { 266 return nil, nil, err 267 } 268 dao := blockdao.NewBlockDAOWithIndexersAndCache(store, indexers, cfg.DB.MaxCacheSize) 269 if dao == nil { 270 return nil, nil, errors.New("pointer is nil") 271 } 272 bc := blockchain.NewBlockchain( 273 cfg.Chain, 274 cfg.Genesis, 275 dao, 276 factory.NewMinter(sf, ap), 277 blockchain.BlockValidatorOption(block.NewValidator( 278 sf, 279 protocol.NewGenericValidator(sf, accountutil.AccountState), 280 )), 281 ) 282 if bc == nil { 283 return nil, nil, errors.New("pointer is nil") 284 } 285 ep := execution.NewProtocol(dao.GetBlockHash, rewarding.DepositGasWithSGD, nil, fakeGetBlockTime) 286 if err = ep.Register(registry); err != nil { 287 return nil, nil, err 288 } 289 if err = bc.Start(context.Background()); err != nil { 290 return nil, nil, err 291 } 292 293 genesisPriKey := identityset.PrivateKey(27) 294 var genesisNonce uint64 = 1 295 296 // make a transfer from genesisAccount to a and b,because stateTX cannot store data in height 0 297 tsf, err := action.SignedTransfer(userA.String(), genesisPriKey, genesisNonce, big.NewInt(1e17), []byte{}, testutil.TestGasLimit, big.NewInt(testutil.TestGasPriceInt64)) 298 if err != nil { 299 return nil, nil, err 300 } 301 if err = ap.Add(context.Background(), tsf); err != nil { 302 return nil, nil, err 303 } 304 genesisNonce++ 305 tsf2, err := action.SignedTransfer(userB.String(), genesisPriKey, genesisNonce, big.NewInt(1e17), []byte{}, testutil.TestGasLimit, big.NewInt(testutil.TestGasPriceInt64)) 306 if err != nil { 307 return nil, nil, err 308 } 309 if err = ap.Add(context.Background(), tsf2); err != nil { 310 return nil, nil, err 311 } 312 for i := 0; i < _randAccountSize; i++ { 313 genesisNonce++ 314 tsf, err := action.SignedTransfer(_randAccountsAddr[i].String(), genesisPriKey, genesisNonce, big.NewInt(1e17), []byte{}, testutil.TestGasLimit, big.NewInt(testutil.TestGasPriceInt64)) 315 if err != nil { 316 return nil, nil, err 317 } 318 if err = ap.Add(context.Background(), tsf); err != nil { 319 return nil, nil, err 320 } 321 } 322 // deploy contract 323 data, err := hex.DecodeString(_contractByteCode) 324 if err != nil { 325 return nil, nil, err 326 } 327 genesisNonce++ 328 ex1, err := action.SignedExecution(action.EmptyAddress, genesisPriKey, genesisNonce, big.NewInt(0), 500000, big.NewInt(testutil.TestGasPriceInt64), data) 329 if err != nil { 330 return nil, nil, err 331 } 332 if err := ap.Add(context.Background(), ex1); err != nil { 333 return nil, nil, err 334 } 335 336 blk, err := bc.MintNewBlock(testutil.TimestampNow()) 337 if err != nil { 338 return nil, nil, err 339 } 340 if err = bc.CommitBlock(blk); err != nil { 341 return nil, nil, err 342 } 343 344 ex1Hash, err := ex1.Hash() 345 if err != nil { 346 return nil, nil, err 347 } 348 var receipt *action.Receipt 349 for _, r := range blk.Receipts { 350 if r.ActionHash == ex1Hash { 351 receipt = r 352 break 353 } 354 } 355 if receipt == nil { 356 return nil, nil, errors.Errorf("failed to find receipt for %x", ex1Hash) 357 } 358 _contractAddr = receipt.ContractAddress 359 360 return bc, ap, nil 361 }