github.com/klaytn/klaytn@v1.12.1/tests/race_test.go (about) 1 // Copyright 2021 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 //go:build race 18 // +build race 19 20 package tests 21 22 import ( 23 "fmt" 24 "math/big" 25 "os" 26 "testing" 27 "time" 28 29 "github.com/klaytn/klaytn/blockchain" 30 "github.com/klaytn/klaytn/blockchain/state" 31 "github.com/klaytn/klaytn/blockchain/types" 32 "github.com/klaytn/klaytn/common" 33 "github.com/klaytn/klaytn/log" 34 "github.com/klaytn/klaytn/params" 35 "github.com/klaytn/klaytn/storage/database" 36 ) 37 38 // TestRaceBetweenTxpoolAddAndCommitNewWork tests race conditions between `Txpool.add` and `commitNewWork`. 39 // Since both access to txpool pending concurrently, critical sections should be protected by mutex lock. 40 // This race test may need multiple trials and additional flags to avoid false alarms from sha3 package. 41 // For example, `go test -gcflags=all=-d=checkptr=0 -race -run TestRaceBetweenTxpoolAddAndCommitNewWork`. 42 func TestRaceBetweenTxpoolAddAndCommitNewWork(t *testing.T) { 43 log.EnableLogForTest(log.LvlCrit, log.LvlTrace) 44 45 numAccounts := 2 46 fullNode, node, validator, chainId, workspace := newBlockchain(t) 47 defer os.RemoveAll(workspace) 48 49 // create account 50 richAccount, accounts, _ := createAccount(t, numAccounts, validator) 51 52 quitCh := make(chan struct{}) 53 iterNum := 1000 54 55 go func() { 56 var txList []*types.Transaction 57 for i := 0; i < iterNum; i++ { 58 { 59 tx, _, err := generateDefaultTx(richAccount, accounts[1], types.TxTypeValueTransfer, common.Address{}) 60 if err != nil { 61 t.Fatal(err) 62 } 63 signer := types.LatestSignerForChainID(chainId) 64 if err := tx.Sign(signer, richAccount.Keys[0]); err != nil { 65 t.Fatal(err) 66 } 67 txList = append(txList, tx) 68 } 69 { 70 tx, _, err := generateDefaultTx(richAccount, accounts[1], types.TxTypeCancel, common.Address{}) 71 if err != nil { 72 t.Fatal(err) 73 } 74 signer := types.LatestSignerForChainID(chainId) 75 if err := tx.Sign(signer, richAccount.Keys[0]); err != nil { 76 t.Fatal(err) 77 } 78 txList = append(txList, tx) 79 } 80 richAccount.AddNonce() 81 } 82 83 for _, tx := range txList { 84 if err := node.TxPool().AddLocal(tx); err != nil { 85 t.Fatal(err) 86 } 87 } 88 quitCh <- struct{}{} 89 }() 90 91 <-quitCh 92 time.Sleep(time.Second) 93 94 // stop node before ending the test code 95 if err := fullNode.Stop(); err != nil { 96 t.Fatal(err) 97 } 98 } 99 100 // TestRaceAsMessageWithAccountPickerForFeePayer tests calling AsMessageWithAccountPicker of a fee delegated transaction 101 // where a fee payer may be inserted wrongly due to concurrent issue. 102 func TestRaceAsMessageWithAccountPickerForFeePayer(t *testing.T) { 103 log.EnableLogForTest(log.LvlCrit, log.LvlTrace) 104 105 // Configure and generate a sample block chain 106 var ( 107 gendb = database.NewMemoryDBManager() 108 109 // create a sender and a feepayer 110 from, _ = createAnonymousAccount("a5c9a50938a089618167c9d67dbebc0deaffc3c76ddc6b40c2777ae594389999") 111 feePayer, _ = createAnonymousAccount("ed580f5bd71a2ee4dae5cb43e331b7d0318596e561e6add7844271ed94156b20") 112 113 funds = new(big.Int).Mul(big.NewInt(1e16), big.NewInt(params.KLAY)) 114 gspec = &blockchain.Genesis{ 115 Config: params.TestChainConfig, 116 Alloc: blockchain.GenesisAlloc{ 117 from.GetAddr(): {Balance: funds}, 118 feePayer.GetAddr(): {Balance: funds}, 119 }, 120 } 121 genesis = gspec.MustCommit(gendb) 122 signer = types.LatestSignerForChainID(gspec.Config.ChainID) 123 ) 124 125 iterNum := 10000 126 errCh := make(chan error, 2*iterNum) 127 128 for i := 0; i < iterNum; i++ { 129 tx, _ := genFeeDelegatedChainDataAnchoring(t, signer, from, nil, feePayer, big.NewInt(1234)) 130 for i := 0; i < 2; i++ { 131 go func() { 132 stateDB, err := state.New(genesis.Root(), state.NewDatabase(gendb)) 133 if err != nil { 134 panic(err) 135 } 136 137 msg, err := tx.AsMessageWithAccountKeyPicker(signer, stateDB, 0) 138 if err != nil { 139 panic(err) 140 } 141 142 if msg.ValidatedFeePayer() != feePayer.GetAddr() { 143 errCh <- fmt.Errorf("expected: %v, actual: %v", feePayer.GetAddr().String(), msg.ValidatedFeePayer().String()) 144 } else { 145 errCh <- nil 146 } 147 }() 148 } 149 } 150 151 for i := 0; i < 2*iterNum; i++ { 152 if err := <-errCh; err != nil { 153 t.Fatal(err) 154 } 155 } 156 }