go-ethereum/core/transaction_pool_test.go
obscuren d09a6e5421 core, eth, miner: moved nonce management to tx pool.
Removed the managed tx state from the chain manager to the transaction
pool where it's much easier to keep track of nonces (and manage them).
The transaction pool now also uses the queue and pending txs differently
where queued txs are now moved over to the pending queue (i.e. txs ready
for processing and propagation).
2015-06-03 22:43:23 +02:00

155 lines
3.6 KiB
Go

package core
import (
"crypto/ecdsa"
"math/big"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
)
func transaction() *types.Transaction {
return types.NewTransactionMessage(common.Address{}, big.NewInt(100), big.NewInt(100), big.NewInt(100), nil)
}
func setupTxPool() (*TxPool, *ecdsa.PrivateKey) {
db, _ := ethdb.NewMemDatabase()
statedb := state.New(common.Hash{}, db)
var m event.TypeMux
key, _ := crypto.GenerateKey()
return NewTxPool(&m, func() *state.StateDB { return statedb }, func() *big.Int { return big.NewInt(1000000) }), key
}
func TestInvalidTransactions(t *testing.T) {
pool, key := setupTxPool()
tx := transaction()
tx.SignECDSA(key)
err := pool.Add(tx)
if err != ErrNonExistentAccount {
t.Error("expected", ErrNonExistentAccount)
}
from, _ := tx.From()
pool.state.AddBalance(from, big.NewInt(1))
err = pool.Add(tx)
if err != ErrInsufficientFunds {
t.Error("expected", ErrInsufficientFunds)
}
balance := new(big.Int).Add(tx.Value(), new(big.Int).Mul(tx.Gas(), tx.GasPrice()))
pool.state.AddBalance(from, balance)
err = pool.Add(tx)
if err != ErrIntrinsicGas {
t.Error("expected", ErrIntrinsicGas, "got", err)
}
pool.state.SetNonce(from, 1)
pool.state.AddBalance(from, big.NewInt(0xffffffffffffff))
tx.GasLimit = big.NewInt(100000)
tx.Price = big.NewInt(1)
tx.SignECDSA(key)
err = pool.Add(tx)
if err != ErrNonce {
t.Error("expected", ErrNonce)
}
}
func TestTransactionQueue(t *testing.T) {
pool, key := setupTxPool()
tx := transaction()
tx.SignECDSA(key)
from, _ := tx.From()
pool.state.AddBalance(from, big.NewInt(1))
pool.queueTx(tx.Hash(), tx)
pool.checkQueue()
if len(pool.txs) != 1 {
t.Error("expected valid txs to be 1 is", len(pool.txs))
}
tx = transaction()
tx.SetNonce(1)
tx.SignECDSA(key)
from, _ = tx.From()
pool.state.SetNonce(from, 2)
pool.queueTx(tx.Hash(), tx)
pool.checkQueue()
if _, ok := pool.txs[tx.Hash()]; ok {
t.Error("expected transaction to be in tx pool")
}
if len(pool.queue[from]) > 0 {
t.Error("expected transaction queue to be empty. is", len(pool.queue[from]))
}
pool, key = setupTxPool()
tx1, tx2, tx3 := transaction(), transaction(), transaction()
tx2.SetNonce(10)
tx3.SetNonce(11)
tx1.SignECDSA(key)
tx2.SignECDSA(key)
tx3.SignECDSA(key)
pool.queueTx(tx1.Hash(), tx1)
pool.queueTx(tx2.Hash(), tx2)
pool.queueTx(tx3.Hash(), tx3)
from, _ = tx1.From()
pool.checkQueue()
if len(pool.txs) != 1 {
t.Error("expected tx pool to be 1 =")
}
if len(pool.queue[from]) != 2 {
t.Error("expected len(queue) == 2, got", len(pool.queue[from]))
}
}
func TestRemoveTx(t *testing.T) {
pool, key := setupTxPool()
tx := transaction()
tx.SignECDSA(key)
from, _ := tx.From()
pool.state.AddBalance(from, big.NewInt(1))
pool.queueTx(tx.Hash(), tx)
pool.addTx(tx.Hash(), tx)
if len(pool.queue) != 1 {
t.Error("expected queue to be 1, got", len(pool.queue))
}
if len(pool.txs) != 1 {
t.Error("expected txs to be 1, got", len(pool.txs))
}
pool.removeTx(tx.Hash())
if len(pool.queue) > 0 {
t.Error("expected queue to be 0, got", len(pool.queue))
}
if len(pool.txs) > 0 {
t.Error("expected txs to be 0, got", len(pool.txs))
}
}
func TestNegativeValue(t *testing.T) {
pool, key := setupTxPool()
tx := transaction()
tx.Value().Set(big.NewInt(-1))
tx.SignECDSA(key)
from, _ := tx.From()
pool.state.AddBalance(from, big.NewInt(1))
err := pool.Add(tx)
if err != ErrNegativeValue {
t.Error("expected", ErrNegativeValue, "got", err)
}
}