| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | package ethchain | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"bytes" | 
					
						
							|  |  |  | 	"container/list" | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2014-07-30 00:31:15 +02:00
										 |  |  | 	"math/big" | 
					
						
							|  |  |  | 	"sync" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-23 12:54:10 +01:00
										 |  |  | 	"github.com/ethereum/eth-go/ethlog" | 
					
						
							| 
									
										
										
										
											2014-07-24 12:04:15 +02:00
										 |  |  | 	"github.com/ethereum/eth-go/ethstate" | 
					
						
							| 
									
										
										
										
											2014-06-26 18:45:57 +01:00
										 |  |  | 	"github.com/ethereum/eth-go/ethwire" | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-23 12:54:10 +01:00
										 |  |  | var txplogger = ethlog.NewLogger("TXP") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | const ( | 
					
						
							|  |  |  | 	txPoolQueueSize = 50 | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type TxPoolHook chan *Transaction | 
					
						
							| 
									
										
										
										
											2014-02-25 11:22:27 +01:00
										 |  |  | type TxMsgTy byte | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const ( | 
					
						
							|  |  |  | 	TxPre = iota | 
					
						
							|  |  |  | 	TxPost | 
					
						
							| 
									
										
										
										
											2014-06-10 15:02:41 +02:00
										 |  |  | 	minGasPrice = 1000000 | 
					
						
							| 
									
										
										
										
											2014-02-25 11:22:27 +01:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type TxMsg struct { | 
					
						
							|  |  |  | 	Tx   *Transaction | 
					
						
							|  |  |  | 	Type TxMsgTy | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | func FindTx(pool *list.List, finder func(*Transaction, *list.Element) bool) *Transaction { | 
					
						
							|  |  |  | 	for e := pool.Front(); e != nil; e = e.Next() { | 
					
						
							|  |  |  | 		if tx, ok := e.Value.(*Transaction); ok { | 
					
						
							|  |  |  | 			if finder(tx, e) { | 
					
						
							|  |  |  | 				return tx | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-23 01:57:04 +01:00
										 |  |  | type TxProcessor interface { | 
					
						
							|  |  |  | 	ProcessTransaction(tx *Transaction) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							|  |  |  | 	queueChan chan *Transaction | 
					
						
							|  |  |  | 	// 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(), | 
					
						
							|  |  |  | 		queueChan: make(chan *Transaction, txPoolQueueSize), | 
					
						
							|  |  |  | 		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 | 
					
						
							|  |  |  | func (pool *TxPool) addTransaction(tx *Transaction) { | 
					
						
							|  |  |  | 	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-03-05 10:42:51 +01:00
										 |  |  | 	pool.Ethereum.Broadcast(ethwire.MsgTxTy, []interface{}{tx.RlpData()}) | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (pool *TxPool) ValidateTransaction(tx *Transaction) error { | 
					
						
							|  |  |  | 	// Get the last block so we can retrieve the sender and receiver from | 
					
						
							|  |  |  | 	// the merkle trie | 
					
						
							| 
									
										
										
										
											2014-03-05 10:42:51 +01:00
										 |  |  | 	block := pool.Ethereum.BlockChain().CurrentBlock | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | 	// Something has gone horribly wrong if this happens | 
					
						
							|  |  |  | 	if block == nil { | 
					
						
							| 
									
										
										
										
											2014-06-23 12:54:10 +01:00
										 |  |  | 		return fmt.Errorf("[TXPL] 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-06-12 10:07:27 +02:00
										 |  |  | 		return fmt.Errorf("[TXPL] Invalid recipient. len = %d", len(tx.Recipient)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | 	// Get the sender | 
					
						
							| 
									
										
										
										
											2014-05-17 14:07:52 +02:00
										 |  |  | 	//sender := pool.Ethereum.StateManager().procState.GetAccount(tx.Sender()) | 
					
						
							|  |  |  | 	sender := pool.Ethereum.StateManager().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-07-30 00:31:15 +02:00
										 |  |  | 	if sender.Balance.Cmp(totAmount) < 0 { | 
					
						
							| 
									
										
										
										
											2014-03-20 11:20:29 +01:00
										 |  |  | 		return fmt.Errorf("[TXPL] 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-06-23 12:54:10 +01:00
										 |  |  | 			return fmt.Errorf("[TXPL] 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 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (pool *TxPool) queueHandler() { | 
					
						
							|  |  |  | out: | 
					
						
							|  |  |  | 	for { | 
					
						
							|  |  |  | 		select { | 
					
						
							|  |  |  | 		case tx := <-pool.queueChan: | 
					
						
							|  |  |  | 			hash := tx.Hash() | 
					
						
							|  |  |  | 			foundTx := FindTx(pool.pool, func(tx *Transaction, e *list.Element) bool { | 
					
						
							|  |  |  | 				return bytes.Compare(tx.Hash(), hash) == 0 | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if foundTx != nil { | 
					
						
							|  |  |  | 				break | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Validate the transaction | 
					
						
							|  |  |  | 			err := pool.ValidateTransaction(tx) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							| 
									
										
										
										
											2014-06-23 12:54:10 +01:00
										 |  |  | 				txplogger.Debugln("Validating Tx failed", err) | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2014-04-30 17:13:32 +02:00
										 |  |  | 				// Call blocking version. | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | 				pool.addTransaction(tx) | 
					
						
							| 
									
										
										
										
											2014-03-10 11:53:02 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-14 12:02:35 +02:00
										 |  |  | 				tmp := make([]byte, 4) | 
					
						
							|  |  |  | 				copy(tmp, tx.Recipient) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				txplogger.Debugf("(t) %x => %x (%v) %x\n", tx.Sender()[:4], tmp, tx.Value, tx.Hash()) | 
					
						
							| 
									
										
										
										
											2014-06-12 10:07:27 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-10 11:53:02 +01:00
										 |  |  | 				// Notify the subscribers | 
					
						
							| 
									
										
										
										
											2014-05-15 14:05:15 +02:00
										 |  |  | 				pool.Ethereum.Reactor().Post("newTx:pre", tx) | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		case <-pool.quit: | 
					
						
							|  |  |  | 			break out | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (pool *TxPool) QueueTransaction(tx *Transaction) { | 
					
						
							|  |  |  | 	pool.queueChan <- tx | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-28 11:20:07 +01:00
										 |  |  | func (pool *TxPool) CurrentTransactions() []*Transaction { | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | 	pool.mutex.Lock() | 
					
						
							|  |  |  | 	defer pool.mutex.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	txList := make([]*Transaction, pool.pool.Len()) | 
					
						
							|  |  |  | 	i := 0 | 
					
						
							|  |  |  | 	for e := pool.pool.Front(); e != nil; e = e.Next() { | 
					
						
							| 
									
										
										
										
											2014-05-14 16:29:34 +02:00
										 |  |  | 		tx := e.Value.(*Transaction) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		txList[i] = tx | 
					
						
							| 
									
										
										
										
											2014-02-14 23:56:09 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		i++ | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-28 11:20:07 +01:00
										 |  |  | 	return txList | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-24 12:04:15 +02:00
										 |  |  | func (pool *TxPool) RemoveInvalid(state *ethstate.State) { | 
					
						
							| 
									
										
										
										
											2014-05-14 16:29:34 +02:00
										 |  |  | 	for e := pool.pool.Front(); e != nil; e = e.Next() { | 
					
						
							|  |  |  | 		tx := e.Value.(*Transaction) | 
					
						
							|  |  |  | 		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-03-28 11:20:07 +01:00
										 |  |  | func (pool *TxPool) Flush() []*Transaction { | 
					
						
							|  |  |  | 	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() { | 
					
						
							|  |  |  | 	go pool.queueHandler() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (pool *TxPool) Stop() { | 
					
						
							|  |  |  | 	close(pool.quit) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	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
										 |  |  | } |