2
2
heapq .heaptop = lambda x : x [0 ]
3
3
PRIO_INFINITY = - 2 ** 100
4
4
5
+ class OrderableTx (object ):
6
+
7
+ def __init__ (self , prio , counter , tx ):
8
+ self .prio = prio
9
+ self .counter = counter
10
+ self .tx = tx
11
+
12
+ def __lt__ (self , other ):
13
+ if self .prio < other .prio :
14
+ return True
15
+ elif self .prio == other .prio :
16
+ return self .counter < other .counter
17
+ else :
18
+ return False
19
+
20
+
5
21
class TransactionQueue ():
6
22
7
23
def __init__ (self ):
24
+ self .counter = 0
8
25
self .txs = []
9
26
self .aside = []
10
- self .last_max_gas = 2 ** 100
11
27
12
28
def __len__ (self ):
13
29
return len (self .txs )
14
30
15
31
def add_transaction (self , tx , force = False ):
16
32
prio = PRIO_INFINITY if force else - tx .gasprice
17
- heapq .heappush (self .txs , (prio , tx ))
33
+ heapq .heappush (self .txs , OrderableTx (prio , self .counter , tx ))
34
+ self .counter += 1
18
35
19
36
def pop_transaction (self , max_gas = 9999999999 , max_seek_depth = 16 , min_gasprice = 0 ):
20
- while len (self .aside ) and max_gas >= heapq .heaptop (self .aside )[0 ]:
21
- tx = heapq .heappop (self .aside )[1 ]
22
- heapq .heappush (self .txs , (- tx .gasprice , tx ))
37
+ while len (self .aside ) and max_gas >= heapq .heaptop (self .aside ).prio :
38
+ item = heapq .heappop (self .aside )
39
+ item .prio = - item .tx .gasprice
40
+ heapq .heappush (self .txs , item )
23
41
for i in range (min (len (self .txs ), max_seek_depth )):
24
- prio , tx = heapq .heaptop (self .txs )
25
- if tx .startgas > max_gas :
42
+ item = heapq .heaptop (self .txs )
43
+ if item . tx .startgas > max_gas :
26
44
heapq .heappop (self .txs )
27
- heapq .heappush (self .aside , (tx .startgas , tx ))
28
- elif tx .gasprice >= min_gasprice or prio == PRIO_INFINITY :
45
+ item .prio = item .tx .startgas
46
+ heapq .heappush (self .aside , item )
47
+ elif item .tx .gasprice >= min_gasprice or prio == PRIO_INFINITY :
29
48
heapq .heappop (self .txs )
30
- return tx
49
+ return item . tx
31
50
else :
32
51
return None
33
52
return None
@@ -40,15 +59,15 @@ def peek(self, num=None):
40
59
41
60
def diff (self , txs ):
42
61
remove_hashes = [tx .hash for tx in txs ]
43
- keep = [( prio , tx ) for ( prio , tx ) in self .txs if tx .hash not in remove_hashes ]
62
+ keep = [item for item in self .txs if item . tx .hash not in remove_hashes ]
44
63
q = TransactionQueue ()
45
64
q .txs = keep
46
65
return q
47
66
48
67
49
- def make_test_tx (s = 100000 , g = 50 , data = '' ):
68
+ def make_test_tx (s = 100000 , g = 50 , data = '' , nonce = 0 ):
50
69
from ethereum .transactions import Transaction
51
- return Transaction (nonce = 0 , startgas = s , gasprice = g ,
70
+ return Transaction (nonce = nonce , startgas = s , gasprice = g ,
52
71
value = 0 , data = data , to = '\x35 ' * 20 )
53
72
54
73
@@ -89,11 +108,36 @@ def test_diff():
89
108
q1 .add_transaction (tx )
90
109
q2 = q1 .diff ([tx2 ])
91
110
assert len (q2 ) == 3
92
- assert tx1 in [tx for ( _ , tx ) in q2 .txs ]
93
- assert tx3 in [tx for ( _ , tx ) in q2 .txs ]
94
- assert tx4 in [tx for ( _ , tx ) in q2 .txs ]
111
+ assert tx1 in [item . tx for item in q2 .txs ]
112
+ assert tx3 in [item . tx for item in q2 .txs ]
113
+ assert tx4 in [item . tx for item in q2 .txs ]
95
114
96
115
q3 = q2 .diff ([tx4 ])
97
116
assert len (q3 ) == 2
98
- assert tx1 in [tx for (_ , tx ) in q3 .txs ]
99
- assert tx3 in [tx for (_ , tx ) in q3 .txs ]
117
+ assert tx1 in [item .tx for item in q3 .txs ]
118
+ assert tx3 in [item .tx for item in q3 .txs ]
119
+
120
+
121
+ def test_orderable_tx ():
122
+ assert OrderableTx (- 1 , 0 , None ) < OrderableTx (0 , 0 , None )
123
+ assert OrderableTx (- 1 , 0 , None ) < OrderableTx (- 1 , 1 , None )
124
+ assert not OrderableTx (1 , 0 , None ) < OrderableTx (- 1 , 0 , None )
125
+ assert not OrderableTx (1 , 1 , None ) < OrderableTx (- 1 , 0 , None )
126
+
127
+
128
+ def test_ordering_for_same_prio ():
129
+ q = TransactionQueue ()
130
+ count = 10
131
+ # Add <count> transactions to the queue, all with the same
132
+ # startgas/gasprice but with sequential nonces.
133
+ for i in range (count ):
134
+ q .add_transaction (make_test_tx (nonce = i ))
135
+
136
+ expected_nonce_order = range (count )
137
+ nonces = []
138
+ for i in range (count ):
139
+ tx = q .pop_transaction ()
140
+ nonces .append (tx .nonce )
141
+ # Since they have the same gasprice they should have the same priority and
142
+ # thus be popped in the order they were inserted.
143
+ assert nonces == expected_nonce_order
0 commit comments