github.com/klaytn/klaytn@v1.12.1/blockchain/tx_list_test.go (about) 1 // Modifications Copyright 2018 The klaytn Authors 2 // Copyright 2016 The go-ethereum Authors 3 // This file is part of the go-ethereum library. 4 // 5 // The go-ethereum library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-ethereum library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 17 // 18 // This file is derived from core/tx_list_test.go (2018/06/04). 19 // Modified and improved for the klaytn development. 20 21 package blockchain 22 23 import ( 24 "math/big" 25 "math/rand" 26 "reflect" 27 "testing" 28 "time" 29 30 "github.com/klaytn/klaytn/blockchain/types" 31 "github.com/klaytn/klaytn/crypto" 32 "github.com/stretchr/testify/assert" 33 ) 34 35 // Tests that transactions can be added to strict lists and list contents and 36 // nonce boundaries are correctly maintained. 37 func TestStrictTxListAdd(t *testing.T) { 38 // Generate a list of transactions to insert 39 key, _ := crypto.GenerateKey() 40 41 txs := make(types.Transactions, 1024) 42 for i := 0; i < len(txs); i++ { 43 txs[i] = transaction(uint64(i), 0, key) 44 } 45 // Insert the transactions in a random order 46 list := newTxList(true) 47 for _, v := range rand.Perm(len(txs)) { 48 list.Add(txs[v], DefaultTxPoolConfig.PriceBump, false) 49 } 50 // Verify internal state 51 if len(list.txs.items) != len(txs) { 52 t.Errorf("transaction count mismatch: have %d, want %d", len(list.txs.items), len(txs)) 53 } 54 for i, tx := range txs { 55 if list.txs.items[tx.Nonce()] != tx { 56 t.Errorf("item %d: transaction mismatch: have %v, want %v", i, list.txs.items[tx.Nonce()], tx) 57 } 58 } 59 } 60 61 // TestTxListReadyWithGasPriceBasic check whether ReadyWithGasPrice() works well. 62 // It makes a slice of 10 transactions and executes ReadyWithGasPrice() with baseFee 30. 63 func TestTxListReadyWithGasPriceBasic(t *testing.T) { 64 // Start nonce : 3 65 // baseFee : 30 66 // Transaction[0:9] has gasPrice 50 67 // The result of executing ReadyWithGasPrice will be Transaction[0:9]. 68 startNonce := 3 69 expectedBaseFee := big.NewInt(30) 70 nTxs := 10 71 // Generate a list of transactions to insert 72 key, _ := crypto.GenerateKey() 73 74 txs := make(types.Transactions, nTxs) 75 nonce := startNonce 76 for i := 0; i < len(txs); i++ { 77 txs[i] = pricedTransaction(uint64(nonce), 0, big.NewInt(50), key) 78 nonce++ 79 } 80 81 // Insert the transactions in a random order 82 list := newTxList(true) 83 rand.Seed(time.Now().UnixNano()) 84 for _, v := range rand.Perm(len(txs)) { 85 list.Add(txs[v], DefaultTxPoolConfig.PriceBump, true) 86 } 87 88 ready := list.ReadyWithGasPrice(uint64(startNonce), expectedBaseFee) 89 90 if ready.Len() != nTxs { 91 t.Error("expected number of filtered txs", nTxs, "got", ready.Len()) 92 } 93 94 nonce = startNonce 95 for i := 0; i < len(ready); i++ { 96 if result := reflect.DeepEqual(ready[i], txs[i]); !result { 97 t.Error("ready hash : ", ready[i].Hash(), "tx[i] hash : ", txs[i].Hash()) 98 } 99 100 if list.txs.items[uint64(nonce)] != nil { 101 t.Error("Not deleted in txList. nonce : ", nonce, "tx hash : ", list.txs.items[uint64(nonce)].Hash()) 102 } 103 nonce++ 104 } 105 } 106 107 // TestTxListReadyWithGasPricePartialFilter check whether ReadyWithGasPrice() works well. 108 // It makes a slice has 10 transactions and executes ReadyWithGasPrice() with baseFee 20. 109 // 110 // It checks whether filtering works well if there is a transaction 111 // with a gasPrice lower than the baseFee among Tx. 112 func TestTxListReadyWithGasPricePartialFilter(t *testing.T) { 113 // Start nonce : 3 114 // baseFee : 20 115 // Transaction[0:6] has gasPrice 30 116 // Transaction[7] has gasPrice 10 117 // Transaction[8:9] has gasPrice 50 118 // The result of executing ReadyWithGasPrice will be Transaction[0:6]. 119 startNonce := 3 120 expectedBaseFee := big.NewInt(20) 121 nTxs := 10 122 123 // Generate a list of transactions to insert 124 key, _ := crypto.GenerateKey() 125 126 txs := make(types.Transactions, nTxs) 127 nonce := startNonce 128 for i := 0; i < len(txs); i++ { 129 // Set the gasPrice of transaction lower than expectedBaseFee. 130 if i == 7 { 131 txs[i] = pricedTransaction(uint64(nonce), 0, big.NewInt(10), key) 132 } else if i > 7 { 133 txs[i] = pricedTransaction(uint64(nonce), 0, big.NewInt(50), key) 134 } else { 135 txs[i] = pricedTransaction(uint64(nonce), 0, big.NewInt(30), key) 136 } 137 138 nonce++ 139 } 140 141 // Insert the transactions in a random order 142 list := newTxList(true) 143 for _, v := range rand.Perm(len(txs)) { 144 list.Add(txs[v], DefaultTxPoolConfig.PriceBump, true) 145 } 146 147 ready := list.ReadyWithGasPrice(uint64(startNonce), expectedBaseFee) 148 149 if ready.Len() != 7 { 150 t.Error("expected filtered txs length", 7, "got", ready.Len()) 151 } 152 153 nonce = startNonce 154 for i := 0; i < len(ready); i++ { 155 if result := reflect.DeepEqual(ready[i], txs[i]); result == false { 156 t.Error("ready hash : ", ready[i].Hash(), "tx[i] hash : ", txs[i].Hash()) 157 } 158 159 if list.txs.items[uint64(nonce)] != nil { 160 t.Error("Not deleted in txList. nonce : ", nonce, "tx hash : ", list.txs.items[uint64(nonce)].Hash()) 161 } 162 nonce++ 163 } 164 } 165 166 // TestSubstituteTxByGasPrice tests if the new tx has been successfully replaced 167 // if it has the same nonce and greater gas price as the old tx. 168 func TestSubstituteTxByGasPrice(t *testing.T) { 169 // Generate a list of transactions to insert 170 key, _ := crypto.GenerateKey() 171 txList := newTxList(false) 172 173 oldTx := pricedTransaction(0, 21000, big.NewInt(50), key) 174 newTx := pricedTransaction(0, 21000, big.NewInt(60), key) 175 176 if result, _ := txList.Add(oldTx, DefaultTxPoolConfig.PriceBump, true); !result { 177 t.Error("it cannot add tx in tx list.") 178 } 179 180 result, replaced := txList.Add(newTx, DefaultTxPoolConfig.PriceBump, true) 181 if !result { 182 t.Error("it cannot replace tx in tx list.") 183 } 184 185 assert.Equal(t, replaced, oldTx) 186 } 187 188 // TestSubstituteTransactionAbort checks if a new tx aborts a new transaction 189 // if it has the same nonce and lower gas price as the old tx. 190 func TestSubstituteTransactionAbort(t *testing.T) { 191 // Generate a list of transactions to insert 192 key, _ := crypto.GenerateKey() 193 txList := newTxList(false) 194 195 oldTx := pricedTransaction(0, 21000, big.NewInt(50), key) 196 newTx := pricedTransaction(0, 21000, big.NewInt(40), key) 197 198 if result, _ := txList.Add(oldTx, DefaultTxPoolConfig.PriceBump, true); !result { 199 t.Error("it cannot add tx in tx list.") 200 } 201 202 if result, replaced := txList.Add(newTx, DefaultTxPoolConfig.PriceBump, true); result || replaced != nil { 203 t.Error("Expected to not substitute by a tx with lower gas price") 204 } 205 }