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  }