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  }