@@ -15,22 +15,24 @@ class MempoolPackagesTest(BitcoinTestFramework):
15
15
16
16
def setup_network (self ):
17
17
self .nodes = []
18
- self .nodes .append (start_node (0 , self .options .tmpdir , ["-maxorphantx=1000" , "-relaypriority=0" ]))
18
+ self .nodes .append (start_node (0 , self .options .tmpdir , ["-maxorphantx=1000" , "-relaypriority=0" , "-debug" ]))
19
+ self .nodes .append (start_node (1 , self .options .tmpdir , ["-maxorphantx=1000" , "-relaypriority=0" , "-limitancestorcount=5" , "-debug" ]))
20
+ connect_nodes (self .nodes [0 ], 1 )
19
21
self .is_network_split = False
20
22
self .sync_all ()
21
23
22
24
# Build a transaction that spends parent_txid:vout
23
25
# Return amount sent
24
- def chain_transaction (self , parent_txid , vout , value , fee , num_outputs ):
26
+ def chain_transaction (self , node , parent_txid , vout , value , fee , num_outputs ):
25
27
send_value = satoshi_round ((value - fee )/ num_outputs )
26
28
inputs = [ {'txid' : parent_txid , 'vout' : vout } ]
27
29
outputs = {}
28
30
for i in xrange (num_outputs ):
29
- outputs [self . nodes [ 0 ] .getnewaddress ()] = send_value
30
- rawtx = self . nodes [ 0 ] .createrawtransaction (inputs , outputs )
31
- signedtx = self . nodes [ 0 ] .signrawtransaction (rawtx )
32
- txid = self . nodes [ 0 ] .sendrawtransaction (signedtx ['hex' ])
33
- fulltx = self . nodes [ 0 ] .getrawtransaction (txid , 1 )
31
+ outputs [node .getnewaddress ()] = send_value
32
+ rawtx = node .createrawtransaction (inputs , outputs )
33
+ signedtx = node .signrawtransaction (rawtx )
34
+ txid = node .sendrawtransaction (signedtx ['hex' ])
35
+ fulltx = node .getrawtransaction (txid , 1 )
34
36
assert (len (fulltx ['vout' ]) == num_outputs ) # make sure we didn't generate a change output
35
37
return (txid , send_value )
36
38
@@ -46,7 +48,7 @@ def run_test(self):
46
48
# 100 transactions off a confirmed tx should be fine
47
49
chain = []
48
50
for i in xrange (100 ):
49
- (txid , sent_value ) = self .chain_transaction (txid , 0 , value , fee , 1 )
51
+ (txid , sent_value ) = self .chain_transaction (self . nodes [ 0 ], txid , 0 , value , fee , 1 )
50
52
value = sent_value
51
53
chain .append (txid )
52
54
@@ -69,10 +71,12 @@ def run_test(self):
69
71
70
72
# Adding one more transaction on to the chain should fail.
71
73
try :
72
- self .chain_transaction (txid , vout , value , fee , 1 )
74
+ self .chain_transaction (self . nodes [ 0 ], txid , vout , value , fee , 1 )
73
75
except JSONRPCException as e :
74
76
print "too-long-ancestor-chain successfully rejected"
75
77
78
+ # TODO: check that node1's mempool is as expected
79
+
76
80
# TODO: test ancestor size limits
77
81
78
82
# Now test descendant chain limits
@@ -82,15 +86,15 @@ def run_test(self):
82
86
83
87
transaction_package = []
84
88
# First create one parent tx with 10 children
85
- (txid , sent_value ) = self .chain_transaction (txid , vout , value , fee , 10 )
89
+ (txid , sent_value ) = self .chain_transaction (self . nodes [ 0 ], txid , vout , value , fee , 10 )
86
90
parent_transaction = txid
87
91
for i in xrange (10 ):
88
92
transaction_package .append ({'txid' : txid , 'vout' : i , 'amount' : sent_value })
89
93
90
94
for i in xrange (1000 ):
91
95
utxo = transaction_package .pop (0 )
92
96
try :
93
- (txid , sent_value ) = self .chain_transaction (utxo ['txid' ], utxo ['vout' ], utxo ['amount' ], fee , 10 )
97
+ (txid , sent_value ) = self .chain_transaction (self . nodes [ 0 ], utxo ['txid' ], utxo ['vout' ], utxo ['amount' ], fee , 10 )
94
98
for j in xrange (10 ):
95
99
transaction_package .append ({'txid' : txid , 'vout' : j , 'amount' : sent_value })
96
100
if i == 998 :
@@ -101,7 +105,74 @@ def run_test(self):
101
105
assert_equal (i , 999 )
102
106
print "tx that would create too large descendant package successfully rejected"
103
107
108
+ # TODO: check that node1's mempool is as expected
109
+
104
110
# TODO: test descendant size limits
105
111
112
+ # Test reorg handling
113
+ # First, the basics:
114
+ self .nodes [0 ].generate (1 )
115
+ sync_blocks (self .nodes )
116
+ self .nodes [1 ].invalidateblock (self .nodes [0 ].getbestblockhash ())
117
+ self .nodes [1 ].reconsiderblock (self .nodes [0 ].getbestblockhash ())
118
+
119
+ # Now test the case where node1 has a transaction T in its mempool that
120
+ # depends on transactions A and B which are in a mined block, and the
121
+ # block containing A and B is disconnected, AND B is not accepted back
122
+ # into node1's mempool because its ancestor count is too high.
123
+
124
+ # Create 8 transactions, like so:
125
+ # Tx0 -> Tx1 (vout0)
126
+ # \--> Tx2 (vout1) -> Tx3 -> Tx4 -> Tx5 -> Tx6 -> Tx7
127
+ #
128
+ # Mine them in the next block, then generate a new tx8 that spends
129
+ # Tx1 and Tx7, and add to node1's mempool, then disconnect the
130
+ # last block.
131
+
132
+ # Create tx0 with 2 outputs
133
+ utxo = self .nodes [0 ].listunspent ()
134
+ txid = utxo [0 ]['txid' ]
135
+ value = utxo [0 ]['amount' ]
136
+ vout = utxo [0 ]['vout' ]
137
+
138
+ send_value = satoshi_round ((value - fee )/ 2 )
139
+ inputs = [ {'txid' : txid , 'vout' : vout } ]
140
+ outputs = {}
141
+ for i in xrange (2 ):
142
+ outputs [self .nodes [0 ].getnewaddress ()] = send_value
143
+ rawtx = self .nodes [0 ].createrawtransaction (inputs , outputs )
144
+ signedtx = self .nodes [0 ].signrawtransaction (rawtx )
145
+ txid = self .nodes [0 ].sendrawtransaction (signedtx ['hex' ])
146
+ tx0_id = txid
147
+ value = send_value
148
+
149
+ # Create tx1
150
+ (tx1_id , tx1_value ) = self .chain_transaction (self .nodes [0 ], tx0_id , 0 , value , fee , 1 )
151
+
152
+ # Create tx2-7
153
+ vout = 1
154
+ txid = tx0_id
155
+ for i in xrange (6 ):
156
+ (txid , sent_value ) = self .chain_transaction (self .nodes [0 ], txid , vout , value , fee , 1 )
157
+ vout = 0
158
+ value = sent_value
159
+
160
+ # Mine these in a block
161
+ self .nodes [0 ].generate (1 )
162
+ self .sync_all ()
163
+
164
+ # Now generate tx8, with a big fee
165
+ inputs = [ {'txid' : tx1_id , 'vout' : 0 }, {'txid' : txid , 'vout' : 0 } ]
166
+ outputs = { self .nodes [0 ].getnewaddress () : send_value + value - 4 * fee }
167
+ rawtx = self .nodes [0 ].createrawtransaction (inputs , outputs )
168
+ signedtx = self .nodes [0 ].signrawtransaction (rawtx )
169
+ txid = self .nodes [0 ].sendrawtransaction (signedtx ['hex' ])
170
+ sync_mempools (self .nodes )
171
+
172
+ # Now try to disconnect the tip on each node...
173
+ self .nodes [1 ].invalidateblock (self .nodes [1 ].getbestblockhash ())
174
+ self .nodes [0 ].invalidateblock (self .nodes [0 ].getbestblockhash ())
175
+ sync_blocks (self .nodes )
176
+
106
177
if __name__ == '__main__' :
107
178
MempoolPackagesTest ().main ()
0 commit comments