77
88from test_framework .test_framework import ComparisonTestFramework
99from test_framework .util import *
10- from test_framework .comptool import TestManager , TestInstance
10+ from test_framework .comptool import TestManager , TestInstance , RejectResult
1111from test_framework .mininode import *
1212from test_framework .blocktools import *
1313import logging
1414import copy
1515import time
1616import numbers
1717from test_framework .key import CECKey
18- from test_framework .script import CScript , CScriptOp , SignatureHash , SIGHASH_ALL , OP_TRUE
18+ from test_framework .script import CScript , CScriptOp , SignatureHash , SIGHASH_ALL , OP_TRUE , OP_FALSE
1919
2020class PreviousSpendableOutput (object ):
2121 def __init__ (self , tx = CTransaction (), n = - 1 ):
@@ -122,13 +122,29 @@ def accepted():
122122 return TestInstance ([[self .tip , True ]])
123123
124124 # returns a test case that asserts that the current tip was rejected
125- def rejected ():
126- return TestInstance ([[self .tip , False ]])
125+ def rejected (reject = None ):
126+ if reject is None :
127+ return TestInstance ([[self .tip , False ]])
128+ else :
129+ return TestInstance ([[self .tip , reject ]])
127130
128131 # move the tip back to a previous block
129132 def tip (number ):
130133 self .tip = self .blocks [number ]
131134
135+ # add transactions to a block produced by next_block
136+ def update_block (block_number , new_transactions ):
137+ block = self .blocks [block_number ]
138+ old_hash = block .sha256
139+ self .add_transactions_to_block (block , new_transactions )
140+ block .solve ()
141+ # Update the internal state just like in next_block
142+ self .tip = block
143+ self .block_heights [block .sha256 ] = self .block_heights [old_hash ]
144+ del self .block_heights [old_hash ]
145+ self .blocks [block_number ] = block
146+ return block
147+
132148 # creates a new block and advances the tip to that block
133149 block = self .next_block
134150
@@ -141,23 +157,23 @@ def tip(number):
141157
142158 # Now we need that block to mature so we can spend the coinbase.
143159 test = TestInstance (sync_every_block = False )
144- for i in range (100 ):
160+ for i in range (99 ):
145161 block (1000 + i )
146162 test .blocks_and_transactions .append ([self .tip , True ])
147163 save_spendable_output ()
148164 yield test
149165
150166
151- # Start by bulding a couple of blocks on top (which output is spent is in parentheses):
167+ # Start by building a couple of blocks on top (which output is spent is
168+ # in parentheses):
152169 # genesis -> b1 (0) -> b2 (1)
153170 out0 = get_spendable_output ()
154171 block (1 , spend = out0 )
155172 save_spendable_output ()
156173 yield accepted ()
157174
158175 out1 = get_spendable_output ()
159- block (2 , spend = out1 )
160- # Inv again, then deliver twice (shouldn't break anything).
176+ b2 = block (2 , spend = out1 )
161177 yield accepted ()
162178
163179
@@ -168,8 +184,8 @@ def tip(number):
168184 #
169185 # Nothing should happen at this point. We saw b2 first so it takes priority.
170186 tip (1 )
171- block (3 , spend = out1 )
172- # Deliver twice (should still not break anything )
187+ b3 = block (3 , spend = out1 )
188+ txout_b3 = PreviousSpendableOutput ( b3 . vtx [ 1 ], 1 )
173189 yield rejected ()
174190
175191
@@ -214,7 +230,7 @@ def tip(number):
214230 # \-> b3 (1) -> b4 (2)
215231 tip (6 )
216232 block (9 , spend = out4 , additional_coinbase_value = 1 )
217- yield rejected ()
233+ yield rejected (RejectResult ( 16 , 'bad-cb-amount' ) )
218234
219235
220236 # Create a fork that ends in a block with too much fee (the one that causes the reorg)
@@ -226,7 +242,7 @@ def tip(number):
226242 yield rejected ()
227243
228244 block (11 , spend = out4 , additional_coinbase_value = 1 )
229- yield rejected ()
245+ yield rejected (RejectResult ( 16 , 'bad-cb-amount' ) )
230246
231247
232248 # Try again, but with a valid fork first
@@ -252,6 +268,10 @@ def tip(number):
252268
253269 yield TestInstance ([[b12 , True , b13 .sha256 ]]) # New tip should be b13.
254270
271+ # Add a block with MAX_BLOCK_SIGOPS and one with one more sigop
272+ # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
273+ # \-> b12 (3) -> b13 (4) -> b15 (5) -> b16 (6)
274+ # \-> b3 (1) -> b4 (2)
255275
256276 # Test that a block with a lot of checksigs is okay
257277 lots_of_checksigs = CScript ([OP_CHECKSIG ] * (1000000 / 50 - 1 ))
@@ -264,8 +284,121 @@ def tip(number):
264284 out6 = get_spendable_output ()
265285 too_many_checksigs = CScript ([OP_CHECKSIG ] * (1000000 / 50 ))
266286 block (16 , spend = out6 , script = too_many_checksigs )
287+ yield rejected (RejectResult (16 , 'bad-blk-sigops' ))
288+
289+
290+ # Attempt to spend a transaction created on a different fork
291+ # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
292+ # \-> b12 (3) -> b13 (4) -> b15 (5) -> b17 (b3.vtx[1])
293+ # \-> b3 (1) -> b4 (2)
294+ tip (15 )
295+ block (17 , spend = txout_b3 )
296+ yield rejected (RejectResult (16 , 'bad-txns-inputs-missingorspent' ))
297+
298+ # Attempt to spend a transaction created on a different fork (on a fork this time)
299+ # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
300+ # \-> b12 (3) -> b13 (4) -> b15 (5)
301+ # \-> b18 (b3.vtx[1]) -> b19 (6)
302+ # \-> b3 (1) -> b4 (2)
303+ tip (13 )
304+ block (18 , spend = txout_b3 )
305+ yield rejected ()
306+
307+ block (19 , spend = out6 )
267308 yield rejected ()
268309
310+ # Attempt to spend a coinbase at depth too low
311+ # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
312+ # \-> b12 (3) -> b13 (4) -> b15 (5) -> b20 (7)
313+ # \-> b3 (1) -> b4 (2)
314+ tip (15 )
315+ out7 = get_spendable_output ()
316+ block (20 , spend = out7 )
317+ yield rejected (RejectResult (16 , 'bad-txns-premature-spend-of-coinbase' ))
318+
319+ # Attempt to spend a coinbase at depth too low (on a fork this time)
320+ # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
321+ # \-> b12 (3) -> b13 (4) -> b15 (5)
322+ # \-> b21 (6) -> b22 (5)
323+ # \-> b3 (1) -> b4 (2)
324+ tip (13 )
325+ block (21 , spend = out6 )
326+ yield rejected ()
327+
328+ block (22 , spend = out5 )
329+ yield rejected ()
330+
331+ # Create a block on either side of MAX_BLOCK_SIZE and make sure its accepted/rejected
332+ # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
333+ # \-> b12 (3) -> b13 (4) -> b15 (5) -> b23 (6)
334+ # \-> b24 (6) -> b25 (7)
335+ # \-> b3 (1) -> b4 (2)
336+ tip (15 )
337+ b23 = block (23 , spend = out6 )
338+ old_hash = b23 .sha256
339+ tx = CTransaction ()
340+ script_length = MAX_BLOCK_SIZE - len (b23 .serialize ()) - 69
341+ script_output = CScript ([chr (0 )* script_length ])
342+ tx .vout .append (CTxOut (0 , script_output ))
343+ tx .vin .append (CTxIn (COutPoint (b23 .vtx [1 ].sha256 , 1 )))
344+ b23 = update_block (23 , [tx ])
345+ # Make sure the math above worked out to produce a max-sized block
346+ assert_equal (len (b23 .serialize ()), MAX_BLOCK_SIZE )
347+ yield accepted ()
348+
349+ # Make the next block one byte bigger and check that it fails
350+ tip (15 )
351+ b24 = block (24 , spend = out6 )
352+ script_length = MAX_BLOCK_SIZE - len (b24 .serialize ()) - 69
353+ script_output = CScript ([chr (0 )* (script_length + 1 )])
354+ tx .vout = [CTxOut (0 , script_output )]
355+ b24 = update_block (24 , [tx ])
356+ assert_equal (len (b24 .serialize ()), MAX_BLOCK_SIZE + 1 )
357+ yield rejected (RejectResult (16 , 'bad-blk-length' ))
358+
359+ b25 = block (25 , spend = out7 )
360+ yield rejected ()
361+
362+ # Create blocks with a coinbase input script size out of range
363+ # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
364+ # \-> b12 (3) -> b13 (4) -> b15 (5) -> b23 (6) -> b30 (7)
365+ # \-> ... (6) -> ... (7)
366+ # \-> b3 (1) -> b4 (2)
367+ tip (15 )
368+ b26 = block (26 , spend = out6 )
369+ b26 .vtx [0 ].vin [0 ].scriptSig = chr (0 )
370+ b26 .vtx [0 ].rehash ()
371+ # update_block causes the merkle root to get updated, even with no new
372+ # transactions, and updates the required state.
373+ b26 = update_block (26 , [])
374+ yield rejected (RejectResult (16 , 'bad-cb-length' ))
375+
376+ # Extend the b26 chain to make sure bitcoind isn't accepting b26
377+ b27 = block (27 , spend = out7 )
378+ yield rejected ()
379+
380+ # Now try a too-large-coinbase script
381+ tip (15 )
382+ b28 = block (28 , spend = out6 )
383+ b28 .vtx [0 ].vin [0 ].scriptSig = chr (0 )* 101
384+ b28 .vtx [0 ].rehash ()
385+ b28 = update_block (28 , [])
386+ yield rejected (RejectResult (16 , 'bad-cb-length' ))
387+
388+ # Extend the b28 chain to make sure bitcoind isn't accepted b28
389+ b29 = block (29 , spend = out7 )
390+ # TODO: Should get a reject message back with "bad-prevblk", except
391+ # there's a bug that prevents this from being detected. Just note
392+ # failure for now, and add the reject result later.
393+ yield rejected ()
394+
395+ # b30 has a max-sized coinbase scriptSig.
396+ tip (23 )
397+ b30 = block (30 )
398+ b30 .vtx [0 ].vin [0 ].scriptSig = chr (0 )* 100
399+ b30 .vtx [0 ].rehash ()
400+ b30 = update_block (30 , [])
401+ yield accepted ()
269402
270403
271404if __name__ == '__main__' :
0 commit comments