github.com/jeffallen/go-ethereum@v1.1.4-0.20150910155051-571d3236c49c/core/transaction_pool_test.go (about) 1 // Copyright 2015 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum 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 go-ethereum 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 go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package core 18 19 import ( 20 "crypto/ecdsa" 21 "math/big" 22 "testing" 23 24 "github.com/ethereum/go-ethereum/common" 25 "github.com/ethereum/go-ethereum/core/state" 26 "github.com/ethereum/go-ethereum/core/types" 27 "github.com/ethereum/go-ethereum/crypto" 28 "github.com/ethereum/go-ethereum/ethdb" 29 "github.com/ethereum/go-ethereum/event" 30 ) 31 32 func transaction(nonce uint64, gaslimit *big.Int, key *ecdsa.PrivateKey) *types.Transaction { 33 tx, _ := types.NewTransaction(nonce, common.Address{}, big.NewInt(100), gaslimit, big.NewInt(1), nil).SignECDSA(key) 34 return tx 35 } 36 37 func setupTxPool() (*TxPool, *ecdsa.PrivateKey) { 38 db, _ := ethdb.NewMemDatabase() 39 statedb := state.New(common.Hash{}, db) 40 41 var m event.TypeMux 42 key, _ := crypto.GenerateKey() 43 return NewTxPool(&m, func() *state.StateDB { return statedb }, func() *big.Int { return big.NewInt(1000000) }), key 44 } 45 46 func TestInvalidTransactions(t *testing.T) { 47 pool, key := setupTxPool() 48 49 tx := transaction(0, big.NewInt(100), key) 50 if err := pool.Add(tx); err != ErrNonExistentAccount { 51 t.Error("expected", ErrNonExistentAccount) 52 } 53 54 from, _ := tx.From() 55 pool.currentState().AddBalance(from, big.NewInt(1)) 56 if err := pool.Add(tx); err != ErrInsufficientFunds { 57 t.Error("expected", ErrInsufficientFunds) 58 } 59 60 balance := new(big.Int).Add(tx.Value(), new(big.Int).Mul(tx.Gas(), tx.GasPrice())) 61 pool.currentState().AddBalance(from, balance) 62 if err := pool.Add(tx); err != ErrIntrinsicGas { 63 t.Error("expected", ErrIntrinsicGas, "got", err) 64 } 65 66 pool.currentState().SetNonce(from, 1) 67 pool.currentState().AddBalance(from, big.NewInt(0xffffffffffffff)) 68 tx = transaction(0, big.NewInt(100000), key) 69 if err := pool.Add(tx); err != ErrNonce { 70 t.Error("expected", ErrNonce) 71 } 72 } 73 74 func TestTransactionQueue(t *testing.T) { 75 pool, key := setupTxPool() 76 tx := transaction(0, big.NewInt(100), key) 77 from, _ := tx.From() 78 pool.currentState().AddBalance(from, big.NewInt(1)) 79 pool.queueTx(tx.Hash(), tx) 80 81 pool.checkQueue() 82 if len(pool.pending) != 1 { 83 t.Error("expected valid txs to be 1 is", len(pool.pending)) 84 } 85 86 tx = transaction(1, big.NewInt(100), key) 87 from, _ = tx.From() 88 pool.currentState().SetNonce(from, 2) 89 pool.queueTx(tx.Hash(), tx) 90 pool.checkQueue() 91 if _, ok := pool.pending[tx.Hash()]; ok { 92 t.Error("expected transaction to be in tx pool") 93 } 94 95 if len(pool.queue[from]) > 0 { 96 t.Error("expected transaction queue to be empty. is", len(pool.queue[from])) 97 } 98 99 pool, key = setupTxPool() 100 tx1 := transaction(0, big.NewInt(100), key) 101 tx2 := transaction(10, big.NewInt(100), key) 102 tx3 := transaction(11, big.NewInt(100), key) 103 pool.queueTx(tx1.Hash(), tx1) 104 pool.queueTx(tx2.Hash(), tx2) 105 pool.queueTx(tx3.Hash(), tx3) 106 from, _ = tx1.From() 107 108 pool.checkQueue() 109 110 if len(pool.pending) != 1 { 111 t.Error("expected tx pool to be 1 =") 112 } 113 if len(pool.queue[from]) != 2 { 114 t.Error("expected len(queue) == 2, got", len(pool.queue[from])) 115 } 116 } 117 118 func TestRemoveTx(t *testing.T) { 119 pool, key := setupTxPool() 120 tx := transaction(0, big.NewInt(100), key) 121 from, _ := tx.From() 122 pool.currentState().AddBalance(from, big.NewInt(1)) 123 pool.queueTx(tx.Hash(), tx) 124 pool.addTx(tx.Hash(), from, tx) 125 if len(pool.queue) != 1 { 126 t.Error("expected queue to be 1, got", len(pool.queue)) 127 } 128 129 if len(pool.pending) != 1 { 130 t.Error("expected txs to be 1, got", len(pool.pending)) 131 } 132 133 pool.RemoveTx(tx.Hash()) 134 135 if len(pool.queue) > 0 { 136 t.Error("expected queue to be 0, got", len(pool.queue)) 137 } 138 139 if len(pool.pending) > 0 { 140 t.Error("expected txs to be 0, got", len(pool.pending)) 141 } 142 } 143 144 func TestNegativeValue(t *testing.T) { 145 pool, key := setupTxPool() 146 147 tx, _ := types.NewTransaction(0, common.Address{}, big.NewInt(-1), big.NewInt(100), big.NewInt(1), nil).SignECDSA(key) 148 from, _ := tx.From() 149 pool.currentState().AddBalance(from, big.NewInt(1)) 150 if err := pool.Add(tx); err != ErrNegativeValue { 151 t.Error("expected", ErrNegativeValue, "got", err) 152 } 153 } 154 155 func TestTransactionChainFork(t *testing.T) { 156 pool, key := setupTxPool() 157 addr := crypto.PubkeyToAddress(key.PublicKey) 158 resetState := func() { 159 db, _ := ethdb.NewMemDatabase() 160 statedb := state.New(common.Hash{}, db) 161 pool.currentState = func() *state.StateDB { return statedb } 162 pool.currentState().AddBalance(addr, big.NewInt(100000000000000)) 163 pool.resetState() 164 } 165 resetState() 166 167 tx := transaction(0, big.NewInt(100000), key) 168 if err := pool.add(tx); err != nil { 169 t.Error("didn't expect error", err) 170 } 171 pool.RemoveTransactions([]*types.Transaction{tx}) 172 173 // reset the pool's internal state 174 resetState() 175 if err := pool.add(tx); err != nil { 176 t.Error("didn't expect error", err) 177 } 178 } 179 180 func TestTransactionDoubleNonce(t *testing.T) { 181 pool, key := setupTxPool() 182 addr := crypto.PubkeyToAddress(key.PublicKey) 183 resetState := func() { 184 db, _ := ethdb.NewMemDatabase() 185 statedb := state.New(common.Hash{}, db) 186 pool.currentState = func() *state.StateDB { return statedb } 187 pool.currentState().AddBalance(addr, big.NewInt(100000000000000)) 188 pool.resetState() 189 } 190 resetState() 191 192 tx := transaction(0, big.NewInt(100000), key) 193 tx2 := transaction(0, big.NewInt(1000000), key) 194 if err := pool.add(tx); err != nil { 195 t.Error("didn't expect error", err) 196 } 197 if err := pool.add(tx2); err != nil { 198 t.Error("didn't expect error", err) 199 } 200 201 pool.checkQueue() 202 if len(pool.pending) != 2 { 203 t.Error("expected 2 pending txs. Got", len(pool.pending)) 204 } 205 } 206 207 func TestMissingNonce(t *testing.T) { 208 pool, key := setupTxPool() 209 addr := crypto.PubkeyToAddress(key.PublicKey) 210 pool.currentState().AddBalance(addr, big.NewInt(100000000000000)) 211 tx := transaction(1, big.NewInt(100000), key) 212 if err := pool.add(tx); err != nil { 213 t.Error("didn't expect error", err) 214 } 215 if len(pool.pending) != 0 { 216 t.Error("expected 0 pending transactions, got", len(pool.pending)) 217 } 218 if len(pool.queue[addr]) != 1 { 219 t.Error("expected 1 queued transaction, got", len(pool.queue[addr])) 220 } 221 }