Skip to content

Commit ed095f0

Browse files
committed
Merge pull request bitcoin#7226
9b41a5f Add more tests to p2p-fullblocktest (Suhas Daftuar)
2 parents c243379 + 9b41a5f commit ed095f0

File tree

2 files changed

+146
-12
lines changed

2 files changed

+146
-12
lines changed

qa/rpc-tests/p2p-fullblocktest.py

Lines changed: 145 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,15 @@
77

88
from test_framework.test_framework import ComparisonTestFramework
99
from test_framework.util import *
10-
from test_framework.comptool import TestManager, TestInstance
10+
from test_framework.comptool import TestManager, TestInstance, RejectResult
1111
from test_framework.mininode import *
1212
from test_framework.blocktools import *
1313
import logging
1414
import copy
1515
import time
1616
import numbers
1717
from 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

2020
class 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

271404
if __name__ == '__main__':

qa/rpc-tests/test_framework/mininode.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
MY_SUBVERSION = "/python-mininode-tester:0.0.1/"
3737

3838
MAX_INV_SZ = 50000
39+
MAX_BLOCK_SIZE = 1000000
3940

4041
# Keep our own socket map for asyncore, so that we can track disconnects
4142
# ourselves (to workaround an issue with closing an asyncore socket when

0 commit comments

Comments
 (0)