github.com/klaytn/klaytn@v1.10.2/tests/resend_nil_test.go (about) 1 // Copyright 2019 The klaytn Authors 2 // This file is part of the klaytn library. 3 // 4 // The klaytn library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The klaytn library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the klaytn library. If not, see <http://www.gnu.org/licenses/>. 16 17 package tests 18 19 import ( 20 "crypto/ecdsa" 21 "fmt" 22 "math/big" 23 "sync" 24 "testing" 25 "time" 26 27 "github.com/klaytn/klaytn/blockchain/types" 28 "github.com/klaytn/klaytn/common/profile" 29 "github.com/klaytn/klaytn/log" 30 "github.com/klaytn/klaytn/params" 31 ) 32 33 // BenchmarkResendNilDereference checks nil pointer dereferences while 34 // simultaneous execution of TxPool.AddRemotes() and TxPool.CachedPendingTxsByCount(). 35 // Since TxPool.CachedPendingTxsByCount() updates m.cache in the TxPool.TxList without 36 // obtaining TxPool.mu, m.cache can be updated in both execution of TxPool.AddRemotes() 37 // and TxPool.CachedPendingTxsByCount(). 38 // By obtaining TxPool.mu in TxPool.CachedPendingTxsByCount(), 39 // the nil pointer dereference errors disappeared. 40 // 41 // This does not need to be executed on CI, make this test a benchmark. 42 // To execute this, 43 // $ go test -run XXX -bench BenchmarkResendNilDereference 44 func BenchmarkResendNilDereference(t *testing.B) { 45 log.EnableLogForTest(log.LvlCrit, log.LvlTrace) 46 prof := profile.NewProfiler() 47 48 numTransactions := 20000 49 numAccounts := 2000 50 51 opt := testOption{numTransactions, numAccounts, 4, 1, []byte{}, makeNewTransactionsToRing} 52 53 // Initialize blockchain 54 start := time.Now() 55 bcdata, err := NewBCData(opt.numMaxAccounts, opt.numValidators) 56 if err != nil { 57 t.Fatal(err) 58 } 59 prof.Profile("main_init_blockchain", time.Now().Sub(start)) 60 defer bcdata.Shutdown() 61 62 // Initialize address-balance map for verification 63 start = time.Now() 64 accountMap := NewAccountMap() 65 if err := accountMap.Initialize(bcdata); err != nil { 66 t.Fatal(err) 67 } 68 prof.Profile("main_init_accountMap", time.Now().Sub(start)) 69 70 // make txpool 71 txpool := makeTxPool(bcdata, 50000) 72 signer := types.MakeSigner(bcdata.bc.Config(), bcdata.bc.CurrentHeader().Number) 73 74 wg := sync.WaitGroup{} 75 wg.Add(3) 76 77 gasPrice := new(big.Int).SetUint64(25 * params.Ston) 78 txAmount := big.NewInt(3) 79 // reservoir account 80 reservoir := &TestAccountType{ 81 Addr: *bcdata.addrs[0], 82 Keys: []*ecdsa.PrivateKey{bcdata.privKeys[0]}, 83 Nonce: uint64(0), 84 } 85 86 go func(num int) { 87 // fmt.Println("creating transaction start!") 88 time.Sleep(1 * time.Nanosecond) 89 // make ring transactions 90 for i := 0; i < num; i++ { 91 // fmt.Println("tx gen num", i) 92 93 tx, err := types.NewTransactionWithMap(types.TxTypeValueTransfer, map[types.TxValueKeyType]interface{}{ 94 types.TxValueKeyNonce: reservoir.Nonce, 95 types.TxValueKeyTo: reservoir.Addr, 96 types.TxValueKeyAmount: txAmount, 97 types.TxValueKeyGasLimit: gasLimit, 98 types.TxValueKeyGasPrice: gasPrice, 99 types.TxValueKeyFrom: reservoir.Addr, 100 }) 101 if err != nil { 102 fmt.Println("tx gen err", err) 103 t.Error(err) 104 return 105 } 106 107 signedTx, err := types.SignTx(tx, signer, bcdata.privKeys[0]) 108 if err != nil { 109 fmt.Println("sign err", err) 110 } 111 time.Sleep(1 * time.Nanosecond) 112 txpool.AddRemotes(types.Transactions{signedTx}) 113 114 reservoir.Nonce++ 115 } 116 // fmt.Println("creating transaction done!") 117 wg.Done() 118 }(100000) 119 120 go func(iter int) { 121 // fmt.Println("Thread1 start!") 122 for i := 0; i < iter; i++ { 123 // fmt.Println("CachedPendingTxsByCount num", i) 124 time.Sleep(1 * time.Nanosecond) 125 txpool.CachedPendingTxsByCount(20000) 126 } 127 wg.Done() 128 // fmt.Println("Thread1 done!") 129 }(100000) 130 131 go func(iter int) { 132 // fmt.Println("Thread2 start!") 133 for i := 0; i < iter; i++ { 134 // fmt.Println("Content num", i) 135 time.Sleep(1 * time.Nanosecond) 136 txpool.Content() 137 } 138 wg.Done() 139 // fmt.Println("Thread2 done!") 140 }(100000) 141 142 wg.Wait() 143 fmt.Println(txpool.Stats()) 144 145 if testing.Verbose() { 146 prof.PrintProfileInfo() 147 } 148 }