github.com/Bytom/bytom@v1.1.2-0.20210127130405-ae40204c0b09/test/bench_blockchain_test.go (about) 1 package test 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "os" 7 "testing" 8 "time" 9 10 "github.com/bytom/bytom/account" 11 "github.com/bytom/bytom/blockchain/pseudohsm" 12 "github.com/bytom/bytom/blockchain/signers" 13 "github.com/bytom/bytom/blockchain/txbuilder" 14 "github.com/bytom/bytom/consensus" 15 "github.com/bytom/bytom/consensus/difficulty" 16 "github.com/bytom/bytom/crypto/ed25519/chainkd" 17 "github.com/bytom/bytom/database" 18 "github.com/bytom/bytom/database/storage" 19 "github.com/bytom/bytom/event" 20 "github.com/bytom/bytom/mining" 21 "github.com/bytom/bytom/protocol" 22 "github.com/bytom/bytom/protocol/bc" 23 "github.com/bytom/bytom/protocol/bc/types" 24 "github.com/bytom/bytom/protocol/state" 25 dbm "github.com/bytom/bytom/database/leveldb" 26 ) 27 28 func BenchmarkChain_CoinBaseTx_NoAsset(b *testing.B) { 29 benchInsertChain(b, 0, 0, "") 30 } 31 32 func BenchmarkChain_BtmTx_NoAsset_BASE(b *testing.B) { 33 benchInsertChain(b, 1, 0, "") 34 } 35 36 func BenchmarkChain_5000BtmTx_NoAsset_BASE(b *testing.B) { 37 benchInsertChain(b, 5000, 0, "") 38 } 39 40 func BenchmarkChain_5000BtmTx_1Asset_BASE(b *testing.B) { 41 benchInsertChain(b, 5000, 1, "") 42 } 43 44 // standard Transaction 45 func BenchmarkChain_BtmTx_NoAsset_P2PKH(b *testing.B) { 46 benchInsertChain(b, 1000, 0, "P2PKH") 47 } 48 49 func BenchmarkChain_BtmTx_1Asset_P2PKH(b *testing.B) { 50 benchInsertChain(b, 1000, 1, "P2PKH") 51 } 52 53 func BenchmarkChain_BtmTx_NoAsset_P2SH(b *testing.B) { 54 benchInsertChain(b, 100, 0, "P2SH") 55 } 56 57 func BenchmarkChain_BtmTx_1Asset_P2SH(b *testing.B) { 58 benchInsertChain(b, 100, 1, "P2SH") 59 } 60 61 func BenchmarkChain_BtmTx_NoAsset_MultiSign(b *testing.B) { 62 benchInsertChain(b, 100, 0, "MultiSign") 63 } 64 65 func BenchmarkChain_BtmTx_1Asset_MultiSign(b *testing.B) { 66 benchInsertChain(b, 100, 1, "MultiSign") 67 } 68 69 func benchInsertChain(b *testing.B, blockTxNumber int, otherAssetNum int, txType string) { 70 b.StopTimer() 71 testNumber := b.N 72 totalTxNumber := testNumber * blockTxNumber 73 74 dirPath, err := ioutil.TempDir(".", "testDB") 75 if err != nil { 76 b.Fatal("create dirPath err:", err) 77 } 78 defer os.RemoveAll(dirPath) 79 80 testDB := dbm.NewDB("testdb", "leveldb", dirPath) 81 defer testDB.Close() 82 83 // Generate a chain test data. 84 chain, txs, txPool, err := GenerateChainData(dirPath, testDB, totalTxNumber, otherAssetNum, txType) 85 if err != nil { 86 b.Fatal("GenerateChainData err:", err) 87 } 88 89 b.ReportAllocs() 90 b.StartTimer() 91 92 for i := 0; i < b.N; i++ { 93 testTxs := txs[blockTxNumber*i : blockTxNumber*(i+1)] 94 if err := InsertChain(chain, txPool, testTxs); err != nil { 95 b.Fatal("Failed to insert block into chain:", err) 96 } 97 } 98 } 99 100 func GenerateChainData(dirPath string, testDB dbm.DB, txNumber, otherAssetNum int, txType string) (*protocol.Chain, []*types.Tx, *protocol.TxPool, error) { 101 var err error 102 103 // generate transactions 104 txs := []*types.Tx{} 105 switch txType { 106 case "P2PKH": 107 txs, err = MockTxsP2PKH(dirPath, testDB, txNumber, otherAssetNum) 108 if err != nil { 109 return nil, nil, nil, err 110 } 111 case "P2SH": 112 txs, err = MockTxsP2SH(dirPath, testDB, txNumber, otherAssetNum) 113 if err != nil { 114 return nil, nil, nil, err 115 } 116 case "MultiSign": 117 txs, err = MockTxsMultiSign(dirPath, testDB, txNumber, otherAssetNum) 118 if err != nil { 119 return nil, nil, nil, err 120 } 121 default: 122 txs, err = CreateTxbyNum(txNumber, otherAssetNum) 123 if err != nil { 124 return nil, nil, nil, err 125 } 126 } 127 128 // init UtxoViewpoint 129 utxoView := state.NewUtxoViewpoint() 130 utxoEntry := storage.NewUtxoEntry(false, 1, false) 131 for _, tx := range txs { 132 for _, id := range tx.SpentOutputIDs { 133 utxoView.Entries[id] = utxoEntry 134 } 135 } 136 137 if err := SetUtxoView(testDB, utxoView); err != nil { 138 return nil, nil, nil, err 139 } 140 141 store := database.NewStore(testDB) 142 dispatcher := event.NewDispatcher() 143 txPool := protocol.NewTxPool(store, dispatcher) 144 chain, err := protocol.NewChain(store, txPool) 145 if err != nil { 146 return nil, nil, nil, err 147 } 148 149 go processNewTxch(txPool) 150 151 return chain, txs, txPool, nil 152 } 153 154 func InsertChain(chain *protocol.Chain, txPool *protocol.TxPool, txs []*types.Tx) error { 155 for _, tx := range txs { 156 if err := txbuilder.FinalizeTx(nil, chain, tx); err != nil { 157 return err 158 } 159 } 160 161 block, err := mining.NewBlockTemplate(chain, txPool, nil) 162 if err != nil { 163 return err 164 } 165 166 blockSize, err := block.MarshalText() 167 if err != nil { 168 return err 169 } 170 171 fmt.Println("blocksize:", uint64(len(blockSize))) 172 fmt.Println("block tx count:", uint64(len(block.Transactions))) 173 fmt.Println("coinbase txsize:", uint64(block.Transactions[0].SerializedSize)) 174 if len(block.Transactions) > 1 { 175 fmt.Println("txsize:", uint64(block.Transactions[1].SerializedSize)) 176 } 177 178 seed, err := chain.CalcNextSeed(&block.PreviousBlockHash) 179 if err != nil { 180 return err 181 } 182 183 if err := SolveBlock(seed, block); err != nil { 184 return err 185 } 186 187 if _, err := chain.ProcessBlock(block); err != nil { 188 return err 189 } 190 191 return nil 192 } 193 194 func processNewTxch(txPool *protocol.TxPool) { 195 } 196 197 func SolveBlock(seed *bc.Hash, block *types.Block) error { 198 maxNonce := ^uint64(0) // 2^64 - 1 199 header := &block.BlockHeader 200 for i := uint64(0); i < maxNonce; i++ { 201 header.Nonce = i 202 headerHash := header.Hash() 203 if difficulty.CheckProofOfWork(&headerHash, seed, header.Bits) { 204 return nil 205 } 206 } 207 return nil 208 } 209 210 func MockSimpleUtxo(index uint64, assetID *bc.AssetID, amount uint64, ctrlProg *account.CtrlProgram) *account.UTXO { 211 if ctrlProg == nil { 212 ctrlProg = &account.CtrlProgram{ 213 AccountID: "", 214 Address: "", 215 KeyIndex: uint64(0), 216 ControlProgram: []byte{81}, 217 Change: false, 218 } 219 } 220 221 utxo := &account.UTXO{ 222 OutputID: bc.Hash{V0: 1}, 223 SourceID: bc.Hash{V0: 1}, 224 AssetID: *assetID, 225 Amount: amount, 226 SourcePos: index, 227 ControlProgram: ctrlProg.ControlProgram, 228 ControlProgramIndex: ctrlProg.KeyIndex, 229 AccountID: ctrlProg.AccountID, 230 Address: ctrlProg.Address, 231 ValidHeight: 0, 232 } 233 234 return utxo 235 } 236 237 func GenerateBaseUtxos(num int, amount uint64, ctrlProg *account.CtrlProgram) []*account.UTXO { 238 utxos := []*account.UTXO{} 239 for i := 0; i < num; i++ { 240 utxo := MockSimpleUtxo(uint64(i), consensus.BTMAssetID, amount, ctrlProg) 241 utxos = append(utxos, utxo) 242 } 243 244 return utxos 245 } 246 247 func GenerateOtherUtxos(typeCount, num int, amount uint64, ctrlProg *account.CtrlProgram) []*account.UTXO { 248 utxos := []*account.UTXO{} 249 250 assetID := &bc.AssetID{ 251 V0: uint64(typeCount), 252 V1: uint64(1), 253 V2: uint64(0), 254 V3: uint64(1), 255 } 256 257 for i := 0; i < num; i++ { 258 utxo := MockSimpleUtxo(uint64(typeCount*num+i), assetID, amount, ctrlProg) 259 utxos = append(utxos, utxo) 260 } 261 262 return utxos 263 } 264 265 func AddTxInputFromUtxo(utxo *account.UTXO, singer *signers.Signer) (*types.TxInput, *txbuilder.SigningInstruction, error) { 266 txInput, signInst, err := account.UtxoToInputs(singer, utxo) 267 if err != nil { 268 return nil, nil, err 269 } 270 271 return txInput, signInst, nil 272 } 273 274 func AddTxOutput(assetID bc.AssetID, amount uint64, controlProgram []byte) *types.TxOutput { 275 out := types.NewTxOutput(assetID, amount, controlProgram) 276 return out 277 } 278 279 func CreateTxBuilder(baseUtxo *account.UTXO, btmServiceFlag bool, signer *signers.Signer) (*txbuilder.TemplateBuilder, error) { 280 tplBuilder := txbuilder.NewBuilder(time.Now()) 281 282 // add input 283 txInput, signInst, err := AddTxInputFromUtxo(baseUtxo, signer) 284 if err != nil { 285 return nil, err 286 } 287 tplBuilder.AddInput(txInput, signInst) 288 289 // if the btm is the service charge, didn't need to add the output 290 if btmServiceFlag { 291 txOutput := AddTxOutput(baseUtxo.AssetID, 100, baseUtxo.ControlProgram) 292 tplBuilder.AddOutput(txOutput) 293 } 294 295 return tplBuilder, nil 296 } 297 298 func AddTxBuilder(tplBuilder *txbuilder.TemplateBuilder, utxo *account.UTXO, signer *signers.Signer) error { 299 txInput, signInst, err := AddTxInputFromUtxo(utxo, signer) 300 if err != nil { 301 return err 302 } 303 tplBuilder.AddInput(txInput, signInst) 304 305 txOutput := AddTxOutput(utxo.AssetID, utxo.Amount, utxo.ControlProgram) 306 tplBuilder.AddOutput(txOutput) 307 308 return nil 309 } 310 311 func BuildTx(baseUtxo *account.UTXO, otherUtxos []*account.UTXO, signer *signers.Signer) (*txbuilder.Template, error) { 312 btmServiceFlag := false 313 if otherUtxos == nil || len(otherUtxos) == 0 { 314 btmServiceFlag = true 315 } 316 317 tplBuilder, err := CreateTxBuilder(baseUtxo, btmServiceFlag, signer) 318 if err != nil { 319 return nil, err 320 } 321 322 for _, u := range otherUtxos { 323 if err := AddTxBuilder(tplBuilder, u, signer); err != nil { 324 return nil, err 325 } 326 } 327 328 tpl, _, err := tplBuilder.Build() 329 if err != nil { 330 return nil, err 331 } 332 333 return tpl, nil 334 } 335 336 func GenetrateTxbyUtxo(baseUtxo []*account.UTXO, otherUtxo [][]*account.UTXO) ([]*types.Tx, error) { 337 tmpUtxo := []*account.UTXO{} 338 txs := []*types.Tx{} 339 otherUtxoFlag := true 340 341 if len(otherUtxo) == 0 || len(otherUtxo) != len(baseUtxo) { 342 otherUtxoFlag = false 343 } 344 345 for i := 0; i < len(baseUtxo); i++ { 346 if otherUtxoFlag { 347 tmpUtxo = otherUtxo[i] 348 } else { 349 tmpUtxo = nil 350 } 351 352 tpl, err := BuildTx(baseUtxo[i], tmpUtxo, nil) 353 if err != nil { 354 return nil, err 355 } 356 357 txs = append(txs, tpl.Transaction) 358 } 359 360 return txs, nil 361 } 362 363 func CreateTxbyNum(txNumber, otherAssetNum int) ([]*types.Tx, error) { 364 baseUtxos := GenerateBaseUtxos(txNumber, 1000000000, nil) 365 otherUtxos := make([][]*account.UTXO, 0, txNumber) 366 if otherAssetNum != 0 { 367 for i := 0; i < txNumber; i++ { 368 utxos := GenerateOtherUtxos(i, otherAssetNum, 6000, nil) 369 otherUtxos = append(otherUtxos, utxos) 370 } 371 } 372 373 txs, err := GenetrateTxbyUtxo(baseUtxos, otherUtxos) 374 if err != nil { 375 return nil, err 376 } 377 378 return txs, nil 379 } 380 381 func SetUtxoView(db dbm.DB, view *state.UtxoViewpoint) error { 382 batch := db.NewBatch() 383 if err := database.SaveUtxoView(batch, view); err != nil { 384 return err 385 } 386 batch.Write() 387 return nil 388 } 389 390 //-------------------------Mock actual transaction---------------------------------- 391 func MockTxsP2PKH(keyDirPath string, testDB dbm.DB, txNumber, otherAssetNum int) ([]*types.Tx, error) { 392 accountManager := account.NewManager(testDB, nil) 393 hsm, err := pseudohsm.New(keyDirPath) 394 if err != nil { 395 return nil, err 396 } 397 398 xpub, _, err := hsm.XCreate("TestP2PKH", "password", "en") 399 if err != nil { 400 return nil, err 401 } 402 403 txs := []*types.Tx{} 404 for i := 0; i < txNumber; i++ { 405 testAccountAlias := fmt.Sprintf("testAccount%d", i) 406 testAccount, err := accountManager.Create([]chainkd.XPub{xpub.XPub}, 1, testAccountAlias, signers.BIP0044) 407 if err != nil { 408 return nil, err 409 } 410 411 controlProg, err := accountManager.CreateAddress(testAccount.ID, false) 412 if err != nil { 413 return nil, err 414 } 415 416 utxo := MockSimpleUtxo(0, consensus.BTMAssetID, 1000000000, controlProg) 417 otherUtxos := GenerateOtherUtxos(i, otherAssetNum, 6000, controlProg) 418 tpl, err := BuildTx(utxo, otherUtxos, testAccount.Signer) 419 if err != nil { 420 return nil, err 421 } 422 423 if _, err := MockSign(tpl, hsm, "password"); err != nil { 424 return nil, err 425 } 426 427 txs = append(txs, tpl.Transaction) 428 } 429 430 return txs, nil 431 } 432 433 func MockTxsP2SH(keyDirPath string, testDB dbm.DB, txNumber, otherAssetNum int) ([]*types.Tx, error) { 434 accountManager := account.NewManager(testDB, nil) 435 hsm, err := pseudohsm.New(keyDirPath) 436 if err != nil { 437 return nil, err 438 } 439 440 xpub1, _, err := hsm.XCreate("TestP2SH1", "password", "en") 441 if err != nil { 442 return nil, err 443 } 444 445 xpub2, _, err := hsm.XCreate("TestP2SH2", "password", "en") 446 if err != nil { 447 return nil, err 448 } 449 450 txs := []*types.Tx{} 451 for i := 0; i < txNumber; i++ { 452 testAccountAlias := fmt.Sprintf("testAccount%d", i) 453 testAccount, err := accountManager.Create([]chainkd.XPub{xpub1.XPub, xpub2.XPub}, 2, testAccountAlias, signers.BIP0044) 454 if err != nil { 455 return nil, err 456 } 457 458 controlProg, err := accountManager.CreateAddress(testAccount.ID, false) 459 if err != nil { 460 return nil, err 461 } 462 463 utxo := MockSimpleUtxo(0, consensus.BTMAssetID, 1000000000, controlProg) 464 otherUtxos := GenerateOtherUtxos(i, otherAssetNum, 6000, controlProg) 465 tpl, err := BuildTx(utxo, otherUtxos, testAccount.Signer) 466 if err != nil { 467 return nil, err 468 } 469 470 if _, err := MockSign(tpl, hsm, "password"); err != nil { 471 return nil, err 472 } 473 474 txs = append(txs, tpl.Transaction) 475 } 476 477 return txs, nil 478 } 479 480 func MockTxsMultiSign(keyDirPath string, testDB dbm.DB, txNumber, otherAssetNum int) ([]*types.Tx, error) { 481 accountManager := account.NewManager(testDB, nil) 482 hsm, err := pseudohsm.New(keyDirPath) 483 if err != nil { 484 return nil, err 485 } 486 487 xpub1, _, err := hsm.XCreate("TestMultilNodeSign1", "password1", "en") 488 if err != nil { 489 return nil, err 490 } 491 492 xpub2, _, err := hsm.XCreate("TestMultilNodeSign2", "password2", "en") 493 if err != nil { 494 return nil, err 495 } 496 txs := []*types.Tx{} 497 for i := 0; i < txNumber; i++ { 498 testAccountAlias := fmt.Sprintf("testAccount%d", i) 499 testAccount, err := accountManager.Create([]chainkd.XPub{xpub1.XPub, xpub2.XPub}, 2, testAccountAlias, signers.BIP0044) 500 if err != nil { 501 return nil, err 502 } 503 504 controlProg, err := accountManager.CreateAddress(testAccount.ID, false) 505 if err != nil { 506 return nil, err 507 } 508 509 utxo := MockSimpleUtxo(0, consensus.BTMAssetID, 1000000000, controlProg) 510 otherUtxos := GenerateOtherUtxos(i, otherAssetNum, 6000, controlProg) 511 tpl, err := BuildTx(utxo, otherUtxos, testAccount.Signer) 512 if err != nil { 513 return nil, err 514 } 515 516 if _, err := MockSign(tpl, hsm, "password1"); err != nil { 517 return nil, err 518 } 519 520 if _, err := MockSign(tpl, hsm, "password2"); err != nil { 521 return nil, err 522 } 523 524 txs = append(txs, tpl.Transaction) 525 } 526 527 return txs, nil 528 }