44	"errors" 
55	"fmt" 
66	"math/big" 
7+ 	"sort" 
78	"sync" 
9+ 	"time" 
810
911	"github.com/ethereum/go-ethereum/common" 
1012	"github.com/ethereum/go-ethereum/core/state" 
@@ -17,7 +19,7 @@ import (
1719
1820var  (
1921	ErrInvalidSender       =  errors .New ("Invalid sender" )
20- 	ErrImpossibleNonce     =  errors .New ("Impossible nonce " )
22+ 	ErrNonce                =  errors .New ("Nonce too low " )
2123	ErrNonExistentAccount  =  errors .New ("Account does not exist" )
2224	ErrInsufficientFunds   =  errors .New ("Insufficient funds" )
2325	ErrIntrinsicGas        =  errors .New ("Intrinsic gas too low" )
@@ -54,20 +56,43 @@ type TxPool struct {
5456	txs            map [common.Hash ]* types.Transaction 
5557	invalidHashes  * set.Set 
5658
59+ 	queue  map [common.Address ]types.Transactions 
60+ 
5761	subscribers  []chan  TxMsg 
5862
5963	eventMux  * event.TypeMux 
6064}
6165
6266func  NewTxPool (eventMux  * event.TypeMux , currentStateFn  stateFn ) * TxPool  {
63- 	return  & TxPool {
67+ 	txPool   :=  & TxPool {
6468		txs :           make (map [common.Hash ]* types.Transaction ),
69+ 		queue :         make (map [common.Address ]types.Transactions ),
6570		queueChan :     make (chan  * types.Transaction , txPoolQueueSize ),
6671		quit :          make (chan  bool ),
6772		eventMux :      eventMux ,
6873		invalidHashes : set .New (),
6974		currentState :  currentStateFn ,
7075	}
76+ 	return  txPool 
77+ }
78+ 
79+ func  (pool  * TxPool ) Start () {
80+ 	// Queue timer will tick so we can attempt to move items from the queue to the 
81+ 	// main transaction pool. 
82+ 	queueTimer  :=  time .NewTicker (300  *  time .Millisecond )
83+ 	// Removal timer will tick and attempt to remove bad transactions (account.nonce>tx.nonce) 
84+ 	removalTimer  :=  time .NewTicker (1  *  time .Second )
85+ done:
86+ 	for  {
87+ 		select  {
88+ 		case  <- queueTimer .C :
89+ 			pool .checkQueue ()
90+ 		case  <- removalTimer .C :
91+ 			pool .validatePool ()
92+ 		case  <- pool .quit :
93+ 			break  done
94+ 		}
95+ 	}
7196}
7297
7398func  (pool  * TxPool ) ValidateTransaction (tx  * types.Transaction ) error  {
@@ -100,16 +125,12 @@ func (pool *TxPool) ValidateTransaction(tx *types.Transaction) error {
100125	}
101126
102127	if  pool .currentState ().GetNonce (from ) >  tx .Nonce () {
103- 		return  ErrImpossibleNonce 
128+ 		return  ErrNonce 
104129	}
105130
106131	return  nil 
107132}
108133
109- func  (self  * TxPool ) addTx (tx  * types.Transaction ) {
110- 	self .txs [tx .Hash ()] =  tx 
111- }
112- 
113134func  (self  * TxPool ) add (tx  * types.Transaction ) error  {
114135	hash  :=  tx .Hash ()
115136
@@ -127,7 +148,7 @@ func (self *TxPool) add(tx *types.Transaction) error {
127148		return  err 
128149	}
129150
130- 	self .addTx (tx )
151+ 	self .queueTx (tx )
131152
132153	var  toname  string 
133154	if  to  :=  tx .To (); to  !=  nil  {
@@ -144,9 +165,6 @@ func (self *TxPool) add(tx *types.Transaction) error {
144165		glog .Infof ("(t) %x => %s (%v) %x\n " , from , toname , tx .Value , tx .Hash ())
145166	}
146167
147- 	// Notify the subscribers 
148- 	go  self .eventMux .Post (TxPreEvent {tx })
149- 
150168	return  nil 
151169}
152170
@@ -189,34 +207,108 @@ func (self *TxPool) GetTransactions() (txs types.Transactions) {
189207	return 
190208}
191209
192- func  (self  * TxPool ) RemoveSet (txs  types.Transactions ) {
193- 	self .mu .Lock ()
194- 	defer  self .mu .Unlock ()
195- 	for  _ , tx  :=  range  txs  {
196- 		delete (self .txs , tx .Hash ())
210+ func  (self  * TxPool ) GetQueuedTransactions () types.Transactions  {
211+ 	self .mu .RLock ()
212+ 	defer  self .mu .RUnlock ()
213+ 
214+ 	var  txs  types.Transactions 
215+ 	for  _ , ts  :=  range  self .queue  {
216+ 		txs  =  append (txs , ts ... )
197217	}
218+ 
219+ 	return  txs 
198220}
199221
200- func  (self  * TxPool ) InvalidateSet ( hashes   * set. Set ) {
222+ func  (self  * TxPool ) RemoveTransactions ( txs  types. Transactions ) {
201223	self .mu .Lock ()
202224	defer  self .mu .Unlock ()
203225
204- 	hashes .Each (func (v  interface {}) bool  {
205- 		delete (self .txs , v .(common.Hash ))
206- 		return  true 
207- 	})
208- 	self .invalidHashes .Merge (hashes )
226+ 	for  _ , tx  :=  range  txs  {
227+ 		delete (self .txs , tx .Hash ())
228+ 	}
209229}
210230
211231func  (pool  * TxPool ) Flush () {
212232	pool .txs  =  make (map [common.Hash ]* types.Transaction )
213233}
214234
215- func  (pool  * TxPool ) Start () {
216- }
217- 
218235func  (pool  * TxPool ) Stop () {
219236	pool .Flush ()
237+ 	close (pool .quit )
220238
221239	glog .V (logger .Info ).Infoln ("TX Pool stopped" )
222240}
241+ 
242+ func  (self  * TxPool ) queueTx (tx  * types.Transaction ) {
243+ 	from , _  :=  tx .From ()
244+ 	self .queue [from ] =  append (self .queue [from ], tx )
245+ }
246+ 
247+ func  (pool  * TxPool ) addTx (tx  * types.Transaction ) {
248+ 	if  _ , ok  :=  pool .txs [tx .Hash ()]; ! ok  {
249+ 		pool .txs [tx .Hash ()] =  tx 
250+ 		// Notify the subscribers. This event is posted in a goroutine 
251+ 		// because it's possible that somewhere during the post "Remove transaction" 
252+ 		// gets called which will then wait for the global tx pool lock and deadlock. 
253+ 		go  pool .eventMux .Post (TxPreEvent {tx })
254+ 	}
255+ }
256+ 
257+ // check queue will attempt to insert 
258+ func  (pool  * TxPool ) checkQueue () {
259+ 	pool .mu .Lock ()
260+ 	defer  pool .mu .Unlock ()
261+ 
262+ 	statedb  :=  pool .currentState ()
263+ 	for  address , txs  :=  range  pool .queue  {
264+ 		sort .Sort (types.TxByNonce {txs })
265+ 
266+ 		var  (
267+ 			nonce  =  statedb .GetNonce (address )
268+ 			start  int 
269+ 		)
270+ 		// Clean up the transactions first and determine the start of the nonces 
271+ 		for  _ , tx  :=  range  txs  {
272+ 			if  tx .Nonce () >=  nonce  {
273+ 				break 
274+ 			}
275+ 			start ++ 
276+ 		}
277+ 		pool .queue [address ] =  txs [start :]
278+ 
279+ 		// expected nonce 
280+ 		enonce  :=  nonce 
281+ 		for  _ , tx  :=  range  pool .queue [address ] {
282+ 			// If the expected nonce does not match up with the next one 
283+ 			// (i.e. a nonce gap), we stop the loop 
284+ 			if  enonce  !=  tx .Nonce () {
285+ 				break 
286+ 			}
287+ 			enonce ++ 
288+ 
289+ 			pool .addTx (tx )
290+ 		}
291+ 		//pool.queue[address] = txs[i:] 
292+ 		// delete the entire queue entry if it's empty. There's no need to keep it 
293+ 		if  len (pool .queue [address ]) ==  0  {
294+ 			delete (pool .queue , address )
295+ 		}
296+ 	}
297+ }
298+ 
299+ func  (pool  * TxPool ) validatePool () {
300+ 	pool .mu .Lock ()
301+ 	defer  pool .mu .Unlock ()
302+ 
303+ 	statedb  :=  pool .currentState ()
304+ 	for  hash , tx  :=  range  pool .txs  {
305+ 		from , _  :=  tx .From ()
306+ 		if  nonce  :=  statedb .GetNonce (from ); nonce  >  tx .Nonce () {
307+ 			if  glog .V (logger .Debug ) {
308+ 				glog .Infof ("removed tx (%x) from pool due to nonce error. state=%d tx=%d\n " , hash [:4 ], nonce , tx .Nonce ())
309+ 			}
310+ 
311+ 			delete (pool .txs , hash )
312+ 		}
313+ 	}
314+ }
0 commit comments