| 
									
										
										
										
											2014-12-04 10:28:02 +01:00
										 |  |  | package core | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"bytes" | 
					
						
							|  |  |  | 	"container/list" | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2014-07-30 00:31:15 +02:00
										 |  |  | 	"math/big" | 
					
						
							|  |  |  | 	"sync" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-04 10:28:02 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/core/types" | 
					
						
							| 
									
										
										
										
											2014-10-31 12:56:05 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/logger" | 
					
						
							| 
									
										
										
										
											2014-10-31 14:43:14 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/state" | 
					
						
							| 
									
										
										
										
											2014-10-31 14:53:42 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/wire" | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-31 12:56:05 +01:00
										 |  |  | var txplogger = logger.NewLogger("TXP") | 
					
						
							| 
									
										
										
										
											2014-06-23 12:54:10 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-29 03:50:20 +01:00
										 |  |  | const txPoolQueueSize = 50 | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-18 16:58:22 +01:00
										 |  |  | type TxPoolHook chan *types.Transaction | 
					
						
							| 
									
										
										
										
											2014-02-25 11:22:27 +01:00
										 |  |  | type TxMsgTy byte | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const ( | 
					
						
							| 
									
										
										
										
											2014-06-10 15:02:41 +02:00
										 |  |  | 	minGasPrice = 1000000 | 
					
						
							| 
									
										
										
										
											2014-02-25 11:22:27 +01:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-23 17:55:34 +02:00
										 |  |  | var MinGasPrice = big.NewInt(10000000000000) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-25 11:22:27 +01:00
										 |  |  | type TxMsg struct { | 
					
						
							| 
									
										
										
										
											2014-11-18 16:58:22 +01:00
										 |  |  | 	Tx   *types.Transaction | 
					
						
							| 
									
										
										
										
											2014-02-25 11:22:27 +01:00
										 |  |  | 	Type TxMsgTy | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-18 16:58:22 +01:00
										 |  |  | func EachTx(pool *list.List, it func(*types.Transaction, *list.Element) bool) { | 
					
						
							| 
									
										
										
										
											2014-10-27 16:52:58 +01:00
										 |  |  | 	for e := pool.Front(); e != nil; e = e.Next() { | 
					
						
							| 
									
										
										
										
											2014-11-18 16:58:22 +01:00
										 |  |  | 		if it(e.Value.(*types.Transaction), e) { | 
					
						
							| 
									
										
										
										
											2014-10-27 16:52:58 +01:00
										 |  |  | 			break | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-18 16:58:22 +01:00
										 |  |  | func FindTx(pool *list.List, finder func(*types.Transaction, *list.Element) bool) *types.Transaction { | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | 	for e := pool.Front(); e != nil; e = e.Next() { | 
					
						
							| 
									
										
										
										
											2014-11-18 16:58:22 +01:00
										 |  |  | 		if tx, ok := e.Value.(*types.Transaction); ok { | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | 			if finder(tx, e) { | 
					
						
							|  |  |  | 				return tx | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-23 01:57:04 +01:00
										 |  |  | type TxProcessor interface { | 
					
						
							| 
									
										
										
										
											2014-11-18 16:58:22 +01:00
										 |  |  | 	ProcessTransaction(tx *types.Transaction) | 
					
						
							| 
									
										
										
										
											2014-02-23 01:57:04 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | // The tx pool a thread safe transaction pool handler. In order to | 
					
						
							|  |  |  | // guarantee a non blocking pool we use a queue channel which can be | 
					
						
							|  |  |  | // independently read without needing access to the actual pool. If the | 
					
						
							|  |  |  | // pool is being drained or synced for whatever reason the transactions | 
					
						
							|  |  |  | // will simple queue up and handled when the mutex is freed. | 
					
						
							|  |  |  | type TxPool struct { | 
					
						
							| 
									
										
										
										
											2014-03-05 10:42:51 +01:00
										 |  |  | 	Ethereum EthManager | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | 	// The mutex for accessing the Tx pool. | 
					
						
							|  |  |  | 	mutex sync.Mutex | 
					
						
							|  |  |  | 	// Queueing channel for reading and writing incoming | 
					
						
							|  |  |  | 	// transactions to | 
					
						
							| 
									
										
										
										
											2014-11-18 16:58:22 +01:00
										 |  |  | 	queueChan chan *types.Transaction | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | 	// Quiting channel | 
					
						
							|  |  |  | 	quit chan bool | 
					
						
							|  |  |  | 	// The actual pool | 
					
						
							|  |  |  | 	pool *list.List | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-23 01:57:04 +01:00
										 |  |  | 	SecondaryProcessor TxProcessor | 
					
						
							| 
									
										
										
										
											2014-02-25 11:22:27 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	subscribers []chan TxMsg | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-05 10:42:51 +01:00
										 |  |  | func NewTxPool(ethereum EthManager) *TxPool { | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | 	return &TxPool{ | 
					
						
							|  |  |  | 		pool:      list.New(), | 
					
						
							| 
									
										
										
										
											2014-11-18 16:58:22 +01:00
										 |  |  | 		queueChan: make(chan *types.Transaction, txPoolQueueSize), | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | 		quit:      make(chan bool), | 
					
						
							| 
									
										
										
										
											2014-03-05 10:42:51 +01:00
										 |  |  | 		Ethereum:  ethereum, | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Blocking function. Don't use directly. Use QueueTransaction instead | 
					
						
							| 
									
										
										
										
											2014-11-18 16:58:22 +01:00
										 |  |  | func (pool *TxPool) addTransaction(tx *types.Transaction) { | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | 	pool.mutex.Lock() | 
					
						
							| 
									
										
										
										
											2014-05-21 12:38:56 +02:00
										 |  |  | 	defer pool.mutex.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | 	pool.pool.PushBack(tx) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Broadcast the transaction to the rest of the peers | 
					
						
							| 
									
										
										
										
											2014-10-31 14:53:42 +01:00
										 |  |  | 	pool.Ethereum.Broadcast(wire.MsgTxTy, []interface{}{tx.RlpData()}) | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-18 16:58:22 +01:00
										 |  |  | func (pool *TxPool) ValidateTransaction(tx *types.Transaction) error { | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | 	// Get the last block so we can retrieve the sender and receiver from | 
					
						
							|  |  |  | 	// the merkle trie | 
					
						
							| 
									
										
										
										
											2014-10-20 11:53:11 +02:00
										 |  |  | 	block := pool.Ethereum.ChainManager().CurrentBlock | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | 	// Something has gone horribly wrong if this happens | 
					
						
							|  |  |  | 	if block == nil { | 
					
						
							| 
									
										
										
										
											2014-12-02 00:14:34 +01:00
										 |  |  | 		return fmt.Errorf("No last block on the block chain") | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-14 12:02:35 +02:00
										 |  |  | 	if len(tx.Recipient) != 0 && len(tx.Recipient) != 20 { | 
					
						
							| 
									
										
										
										
											2014-12-02 00:14:34 +01:00
										 |  |  | 		return fmt.Errorf("Invalid recipient. len = %d", len(tx.Recipient)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-03 14:05:19 +01:00
										 |  |  | 	v, _, _ := tx.Curve() | 
					
						
							|  |  |  | 	if v > 28 || v < 27 { | 
					
						
							| 
									
										
										
										
											2014-12-02 00:14:34 +01:00
										 |  |  | 		return fmt.Errorf("tx.v != (28 || 27)") | 
					
						
							| 
									
										
										
										
											2014-06-12 10:07:27 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-23 18:19:51 +02:00
										 |  |  | 	if tx.GasPrice.Cmp(MinGasPrice) < 0 { | 
					
						
							| 
									
										
										
										
											2014-09-23 17:55:34 +02:00
										 |  |  | 		return fmt.Errorf("Gas price to low. Require %v > Got %v", MinGasPrice, tx.GasPrice) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | 	// Get the sender | 
					
						
							| 
									
										
										
										
											2014-11-04 10:57:02 +01:00
										 |  |  | 	sender := pool.Ethereum.BlockManager().CurrentState().GetAccount(tx.Sender()) | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-16 11:13:19 +02:00
										 |  |  | 	totAmount := new(big.Int).Set(tx.Value) | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | 	// Make sure there's enough in the sender's account. Having insufficient | 
					
						
							|  |  |  | 	// funds won't invalidate this transaction but simple ignores it. | 
					
						
							| 
									
										
										
										
											2014-10-23 01:01:26 +02:00
										 |  |  | 	if sender.Balance().Cmp(totAmount) < 0 { | 
					
						
							| 
									
										
										
										
											2014-12-02 00:14:34 +01:00
										 |  |  | 		return fmt.Errorf("Insufficient amount in sender's (%x) account", tx.Sender()) | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-10 15:02:41 +02:00
										 |  |  | 	if tx.IsContract() { | 
					
						
							|  |  |  | 		if tx.GasPrice.Cmp(big.NewInt(minGasPrice)) < 0 { | 
					
						
							| 
									
										
										
										
											2014-12-02 00:14:34 +01:00
										 |  |  | 			return fmt.Errorf("Gasprice too low, %s given should be at least %d.", tx.GasPrice, minGasPrice) | 
					
						
							| 
									
										
										
										
											2014-06-10 15:02:41 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | 	// Increment the nonce making each tx valid only once to prevent replay | 
					
						
							|  |  |  | 	// attacks | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-02 11:52:56 +01:00
										 |  |  | func (self *TxPool) Add(tx *types.Transaction) error { | 
					
						
							| 
									
										
										
										
											2014-12-01 20:18:09 +01:00
										 |  |  | 	hash := tx.Hash() | 
					
						
							| 
									
										
										
										
											2014-12-03 14:05:19 +01:00
										 |  |  | 	foundTx := FindTx(self.pool, func(tx *types.Transaction, e *list.Element) bool { | 
					
						
							| 
									
										
										
										
											2014-12-01 20:18:09 +01:00
										 |  |  | 		return bytes.Compare(tx.Hash(), hash) == 0 | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if foundTx != nil { | 
					
						
							|  |  |  | 		return fmt.Errorf("Known transaction (%x)", hash[0:4]) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	err := self.ValidateTransaction(tx) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	self.addTransaction(tx) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tmp := make([]byte, 4) | 
					
						
							|  |  |  | 	copy(tmp, tx.Recipient) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	txplogger.Debugf("(t) %x => %x (%v) %x\n", tx.Sender()[:4], tmp, tx.Value, tx.Hash()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Notify the subscribers | 
					
						
							|  |  |  | 	self.Ethereum.EventMux().Post(TxPreEvent{tx}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-18 16:58:22 +01:00
										 |  |  | func (pool *TxPool) CurrentTransactions() []*types.Transaction { | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | 	pool.mutex.Lock() | 
					
						
							|  |  |  | 	defer pool.mutex.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-18 16:58:22 +01:00
										 |  |  | 	txList := make([]*types.Transaction, pool.pool.Len()) | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | 	i := 0 | 
					
						
							|  |  |  | 	for e := pool.pool.Front(); e != nil; e = e.Next() { | 
					
						
							| 
									
										
										
										
											2014-11-18 16:58:22 +01:00
										 |  |  | 		tx := e.Value.(*types.Transaction) | 
					
						
							| 
									
										
										
										
											2014-05-14 16:29:34 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		txList[i] = tx | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		i++ | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-28 11:20:07 +01:00
										 |  |  | 	return txList | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-04 11:40:20 +01:00
										 |  |  | func (pool *TxPool) RemoveInvalid(state *state.StateDB) { | 
					
						
							| 
									
										
										
										
											2014-10-27 16:52:58 +01:00
										 |  |  | 	pool.mutex.Lock() | 
					
						
							|  |  |  | 	defer pool.mutex.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-14 16:29:34 +02:00
										 |  |  | 	for e := pool.pool.Front(); e != nil; e = e.Next() { | 
					
						
							| 
									
										
										
										
											2014-11-18 16:58:22 +01:00
										 |  |  | 		tx := e.Value.(*types.Transaction) | 
					
						
							| 
									
										
										
										
											2014-05-14 16:29:34 +02:00
										 |  |  | 		sender := state.GetAccount(tx.Sender()) | 
					
						
							|  |  |  | 		err := pool.ValidateTransaction(tx) | 
					
						
							| 
									
										
										
										
											2014-05-28 15:07:11 +02:00
										 |  |  | 		if err != nil || sender.Nonce >= tx.Nonce { | 
					
						
							| 
									
										
										
										
											2014-05-14 16:29:34 +02:00
										 |  |  | 			pool.pool.Remove(e) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-18 16:58:22 +01:00
										 |  |  | func (self *TxPool) RemoveSet(txs types.Transactions) { | 
					
						
							| 
									
										
										
										
											2014-10-27 16:52:58 +01:00
										 |  |  | 	self.mutex.Lock() | 
					
						
							|  |  |  | 	defer self.mutex.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, tx := range txs { | 
					
						
							| 
									
										
										
										
											2014-11-18 16:58:22 +01:00
										 |  |  | 		EachTx(self.pool, func(t *types.Transaction, element *list.Element) bool { | 
					
						
							| 
									
										
										
										
											2014-10-27 16:52:58 +01:00
										 |  |  | 			if t == tx { | 
					
						
							|  |  |  | 				self.pool.Remove(element) | 
					
						
							|  |  |  | 				return true // To stop the loop | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return false | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-18 16:58:22 +01:00
										 |  |  | func (pool *TxPool) Flush() []*types.Transaction { | 
					
						
							| 
									
										
										
										
											2014-03-28 11:20:07 +01:00
										 |  |  | 	txList := pool.CurrentTransactions() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | 	// Recreate a new list all together | 
					
						
							|  |  |  | 	// XXX Is this the fastest way? | 
					
						
							|  |  |  | 	pool.pool = list.New() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return txList | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (pool *TxPool) Start() { | 
					
						
							| 
									
										
										
										
											2014-12-03 14:05:19 +01:00
										 |  |  | 	//go pool.queueHandler() | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (pool *TxPool) Stop() { | 
					
						
							|  |  |  | 	pool.Flush() | 
					
						
							| 
									
										
										
										
											2014-03-17 10:33:03 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-23 12:54:10 +01:00
										 |  |  | 	txplogger.Infoln("Stopped") | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | } |