| 
									
										
										
										
											2015-01-02 12:09:38 +01:00
										 |  |  | package core | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"crypto/ecdsa" | 
					
						
							| 
									
										
										
										
											2015-04-04 21:41:24 +02:00
										 |  |  | 	"math/big" | 
					
						
							| 
									
										
										
										
											2015-01-02 12:09:38 +01:00
										 |  |  | 	"testing" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-18 13:38:47 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/common" | 
					
						
							| 
									
										
										
										
											2015-04-04 21:41:24 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/core/state" | 
					
						
							| 
									
										
										
										
											2015-01-02 12:09:38 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/core/types" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/crypto" | 
					
						
							| 
									
										
										
										
											2015-01-07 13:17:48 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/ethdb" | 
					
						
							| 
									
										
										
										
											2015-01-02 12:09:38 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/event" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func transaction() *types.Transaction { | 
					
						
							| 
									
										
										
										
											2015-04-08 20:47:32 +02:00
										 |  |  | 	return types.NewTransactionMessage(common.Address{}, big.NewInt(100), big.NewInt(100), big.NewInt(100), nil) | 
					
						
							| 
									
										
										
										
											2015-01-02 12:09:38 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-08 20:47:32 +02:00
										 |  |  | func setupTxPool() (*TxPool, *ecdsa.PrivateKey) { | 
					
						
							|  |  |  | 	db, _ := ethdb.NewMemDatabase() | 
					
						
							|  |  |  | 	statedb := state.New(common.Hash{}, db) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-02 12:09:38 +01:00
										 |  |  | 	var m event.TypeMux | 
					
						
							|  |  |  | 	key, _ := crypto.GenerateKey() | 
					
						
							| 
									
										
										
										
											2015-04-24 17:45:51 +02:00
										 |  |  | 	return NewTxPool(&m, func() *state.StateDB { return statedb }, func() *big.Int { return big.NewInt(1000000) }), key | 
					
						
							| 
									
										
										
										
											2015-01-02 12:09:38 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-08 20:47:32 +02:00
										 |  |  | func TestInvalidTransactions(t *testing.T) { | 
					
						
							|  |  |  | 	pool, key := setupTxPool() | 
					
						
							| 
									
										
										
										
											2015-01-02 12:09:38 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-08 20:47:32 +02:00
										 |  |  | 	tx := transaction() | 
					
						
							|  |  |  | 	tx.SignECDSA(key) | 
					
						
							|  |  |  | 	err := pool.Add(tx) | 
					
						
							|  |  |  | 	if err != ErrNonExistentAccount { | 
					
						
							|  |  |  | 		t.Error("expected", ErrNonExistentAccount) | 
					
						
							| 
									
										
										
										
											2015-01-02 12:09:38 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-08 20:47:32 +02:00
										 |  |  | 	from, _ := tx.From() | 
					
						
							| 
									
										
										
										
											2015-06-03 22:22:20 +02:00
										 |  |  | 	pool.state.AddBalance(from, big.NewInt(1)) | 
					
						
							| 
									
										
										
										
											2015-04-08 20:47:32 +02:00
										 |  |  | 	err = pool.Add(tx) | 
					
						
							|  |  |  | 	if err != ErrInsufficientFunds { | 
					
						
							|  |  |  | 		t.Error("expected", ErrInsufficientFunds) | 
					
						
							| 
									
										
										
										
											2015-01-02 12:09:38 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-26 11:19:40 +02:00
										 |  |  | 	balance := new(big.Int).Add(tx.Value(), new(big.Int).Mul(tx.Gas(), tx.GasPrice())) | 
					
						
							| 
									
										
										
										
											2015-06-03 22:22:20 +02:00
										 |  |  | 	pool.state.AddBalance(from, balance) | 
					
						
							| 
									
										
										
										
											2015-04-08 20:47:32 +02:00
										 |  |  | 	err = pool.Add(tx) | 
					
						
							|  |  |  | 	if err != ErrIntrinsicGas { | 
					
						
							| 
									
										
										
										
											2015-04-26 11:19:40 +02:00
										 |  |  | 		t.Error("expected", ErrIntrinsicGas, "got", err) | 
					
						
							| 
									
										
										
										
											2015-01-02 12:09:38 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-01-02 12:18:23 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-03 22:22:20 +02:00
										 |  |  | 	pool.state.SetNonce(from, 1) | 
					
						
							|  |  |  | 	pool.state.AddBalance(from, big.NewInt(0xffffffffffffff)) | 
					
						
							| 
									
										
										
										
											2015-04-08 20:47:32 +02:00
										 |  |  | 	tx.GasLimit = big.NewInt(100000) | 
					
						
							|  |  |  | 	tx.Price = big.NewInt(1) | 
					
						
							|  |  |  | 	tx.SignECDSA(key) | 
					
						
							| 
									
										
										
										
											2015-01-31 17:22:17 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-08 20:47:32 +02:00
										 |  |  | 	err = pool.Add(tx) | 
					
						
							| 
									
										
										
										
											2015-04-21 22:01:04 +02:00
										 |  |  | 	if err != ErrNonce { | 
					
						
							|  |  |  | 		t.Error("expected", ErrNonce) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestTransactionQueue(t *testing.T) { | 
					
						
							|  |  |  | 	pool, key := setupTxPool() | 
					
						
							|  |  |  | 	tx := transaction() | 
					
						
							|  |  |  | 	tx.SignECDSA(key) | 
					
						
							|  |  |  | 	from, _ := tx.From() | 
					
						
							| 
									
										
										
										
											2015-06-03 22:22:20 +02:00
										 |  |  | 	pool.state.AddBalance(from, big.NewInt(1)) | 
					
						
							| 
									
										
										
										
											2015-06-03 14:06:20 +02:00
										 |  |  | 	pool.queueTx(tx.Hash(), tx) | 
					
						
							| 
									
										
										
										
											2015-04-21 22:01:04 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	pool.checkQueue() | 
					
						
							| 
									
										
										
										
											2015-06-04 12:47:46 +02:00
										 |  |  | 	if len(pool.pending) != 1 { | 
					
						
							|  |  |  | 		t.Error("expected valid txs to be 1 is", len(pool.pending)) | 
					
						
							| 
									
										
										
										
											2015-04-21 22:01:04 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tx = transaction() | 
					
						
							| 
									
										
										
										
											2015-06-03 22:22:20 +02:00
										 |  |  | 	tx.SetNonce(1) | 
					
						
							| 
									
										
										
										
											2015-04-21 22:01:04 +02:00
										 |  |  | 	tx.SignECDSA(key) | 
					
						
							|  |  |  | 	from, _ = tx.From() | 
					
						
							| 
									
										
										
										
											2015-06-03 22:22:20 +02:00
										 |  |  | 	pool.state.SetNonce(from, 2) | 
					
						
							| 
									
										
										
										
											2015-06-03 14:06:20 +02:00
										 |  |  | 	pool.queueTx(tx.Hash(), tx) | 
					
						
							| 
									
										
										
										
											2015-04-21 22:01:04 +02:00
										 |  |  | 	pool.checkQueue() | 
					
						
							| 
									
										
										
										
											2015-06-04 12:47:46 +02:00
										 |  |  | 	if _, ok := pool.pending[tx.Hash()]; ok { | 
					
						
							| 
									
										
										
										
											2015-04-21 22:01:04 +02:00
										 |  |  | 		t.Error("expected transaction to be in tx pool") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-03 22:22:20 +02:00
										 |  |  | 	if len(pool.queue[from]) > 0 { | 
					
						
							| 
									
										
										
										
											2015-04-21 22:01:04 +02:00
										 |  |  | 		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) | 
					
						
							| 
									
										
										
										
											2015-06-03 14:06:20 +02:00
										 |  |  | 	pool.queueTx(tx1.Hash(), tx1) | 
					
						
							|  |  |  | 	pool.queueTx(tx2.Hash(), tx2) | 
					
						
							|  |  |  | 	pool.queueTx(tx3.Hash(), tx3) | 
					
						
							| 
									
										
										
										
											2015-04-21 22:01:04 +02:00
										 |  |  | 	from, _ = tx1.From() | 
					
						
							| 
									
										
										
										
											2015-06-03 14:06:20 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-21 22:01:04 +02:00
										 |  |  | 	pool.checkQueue() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-04 12:47:46 +02:00
										 |  |  | 	if len(pool.pending) != 1 { | 
					
						
							| 
									
										
										
										
											2015-04-21 22:01:04 +02:00
										 |  |  | 		t.Error("expected tx pool to be 1 =") | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-06-03 14:06:20 +02:00
										 |  |  | 	if len(pool.queue[from]) != 2 { | 
					
						
							|  |  |  | 		t.Error("expected len(queue) == 2, got", len(pool.queue[from])) | 
					
						
							| 
									
										
										
										
											2015-01-31 17:22:17 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-04-30 00:20:59 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | func TestRemoveTx(t *testing.T) { | 
					
						
							|  |  |  | 	pool, key := setupTxPool() | 
					
						
							|  |  |  | 	tx := transaction() | 
					
						
							|  |  |  | 	tx.SignECDSA(key) | 
					
						
							|  |  |  | 	from, _ := tx.From() | 
					
						
							| 
									
										
										
										
											2015-06-03 22:22:20 +02:00
										 |  |  | 	pool.state.AddBalance(from, big.NewInt(1)) | 
					
						
							| 
									
										
										
										
											2015-06-03 14:06:20 +02:00
										 |  |  | 	pool.queueTx(tx.Hash(), tx) | 
					
						
							| 
									
										
										
										
											2015-06-03 22:53:33 +02:00
										 |  |  | 	pool.addTx(tx.Hash(), from, tx) | 
					
						
							| 
									
										
										
										
											2015-04-30 00:20:59 +02:00
										 |  |  | 	if len(pool.queue) != 1 { | 
					
						
							|  |  |  | 		t.Error("expected queue to be 1, got", len(pool.queue)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-04 12:47:46 +02:00
										 |  |  | 	if len(pool.pending) != 1 { | 
					
						
							|  |  |  | 		t.Error("expected txs to be 1, got", len(pool.pending)) | 
					
						
							| 
									
										
										
										
											2015-04-30 00:20:59 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pool.removeTx(tx.Hash()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if len(pool.queue) > 0 { | 
					
						
							|  |  |  | 		t.Error("expected queue to be 0, got", len(pool.queue)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-04 12:47:46 +02:00
										 |  |  | 	if len(pool.pending) > 0 { | 
					
						
							|  |  |  | 		t.Error("expected txs to be 0, got", len(pool.pending)) | 
					
						
							| 
									
										
										
										
											2015-04-30 00:20:59 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-05-26 19:50:42 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | func TestNegativeValue(t *testing.T) { | 
					
						
							|  |  |  | 	pool, key := setupTxPool() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tx := transaction() | 
					
						
							|  |  |  | 	tx.Value().Set(big.NewInt(-1)) | 
					
						
							|  |  |  | 	tx.SignECDSA(key) | 
					
						
							|  |  |  | 	from, _ := tx.From() | 
					
						
							| 
									
										
										
										
											2015-06-03 22:22:20 +02:00
										 |  |  | 	pool.state.AddBalance(from, big.NewInt(1)) | 
					
						
							| 
									
										
										
										
											2015-05-26 19:50:42 +02:00
										 |  |  | 	err := pool.Add(tx) | 
					
						
							|  |  |  | 	if err != ErrNegativeValue { | 
					
						
							|  |  |  | 		t.Error("expected", ErrNegativeValue, "got", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-06-04 17:28:09 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | func TestTransactionChainFork(t *testing.T) { | 
					
						
							|  |  |  | 	pool, key := setupTxPool() | 
					
						
							|  |  |  | 	addr := crypto.PubkeyToAddress(key.PublicKey) | 
					
						
							|  |  |  | 	pool.currentState().AddBalance(addr, big.NewInt(100000000000000)) | 
					
						
							|  |  |  | 	tx := transaction() | 
					
						
							|  |  |  | 	tx.GasLimit = big.NewInt(100000) | 
					
						
							|  |  |  | 	tx.SignECDSA(key) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	err := pool.add(tx) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Error("didn't expect error", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	pool.RemoveTransactions([]*types.Transaction{tx}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// reset the pool's internal state | 
					
						
							|  |  |  | 	pool.resetState() | 
					
						
							|  |  |  | 	err = pool.add(tx) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Error("didn't expect error", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestTransactionDoubleNonce(t *testing.T) { | 
					
						
							|  |  |  | 	pool, key := setupTxPool() | 
					
						
							|  |  |  | 	addr := crypto.PubkeyToAddress(key.PublicKey) | 
					
						
							|  |  |  | 	pool.currentState().AddBalance(addr, big.NewInt(100000000000000)) | 
					
						
							|  |  |  | 	tx := transaction() | 
					
						
							|  |  |  | 	tx.GasLimit = big.NewInt(100000) | 
					
						
							|  |  |  | 	tx.SignECDSA(key) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	err := pool.add(tx) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Error("didn't expect error", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tx2 := transaction() | 
					
						
							|  |  |  | 	tx2.GasLimit = big.NewInt(1000000) | 
					
						
							|  |  |  | 	tx2.SignECDSA(key) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	err = pool.add(tx2) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Error("didn't expect error", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if len(pool.pending) != 2 { | 
					
						
							|  |  |  | 		t.Error("expected 2 pending txs. Got", len(pool.pending)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |