Skip to content

Commit 82dc597

Browse files
committed
[tests] don't build blocks manually in getblocktemplate test
1 parent f82c709 commit 82dc597

File tree

1 file changed

+57
-92
lines changed

1 file changed

+57
-92
lines changed

test/functional/getblocktemplate_proposals.py

Lines changed: 57 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -4,66 +4,21 @@
44
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
55
"""Test block proposals with getblocktemplate."""
66

7-
from binascii import a2b_hex, b2a_hex
8-
from hashlib import sha256
9-
from struct import pack
7+
from binascii import b2a_hex
8+
import copy
109

1110
from test_framework.blocktools import create_coinbase
1211
from test_framework.test_framework import BitcoinTestFramework
12+
from test_framework.mininode import CBlock
1313
from test_framework.util import *
1414

1515
def b2x(b):
1616
return b2a_hex(b).decode('ascii')
1717

18-
# NOTE: This does not work for signed numbers (set the high bit) or zero (use b'\0')
19-
def encodeUNum(n):
20-
s = bytearray(b'\1')
21-
while n > 127:
22-
s[0] += 1
23-
s.append(n % 256)
24-
n //= 256
25-
s.append(n)
26-
return bytes(s)
27-
28-
def varlenEncode(n):
29-
if n < 0xfd:
30-
return pack('<B', n)
31-
if n <= 0xffff:
32-
return b'\xfd' + pack('<H', n)
33-
if n <= 0xffffffff:
34-
return b'\xfe' + pack('<L', n)
35-
return b'\xff' + pack('<Q', n)
36-
37-
def dblsha(b):
38-
return sha256(sha256(b).digest()).digest()
39-
40-
def genmrklroot(leaflist):
41-
cur = leaflist
42-
while len(cur) > 1:
43-
n = []
44-
if len(cur) & 1:
45-
cur.append(cur[-1])
46-
for i in range(0, len(cur), 2):
47-
n.append(dblsha(cur[i] + cur[i + 1]))
48-
cur = n
49-
return cur[0]
50-
51-
def template_to_bytearray(tmpl, txlist):
52-
blkver = pack('<L', tmpl['version'])
53-
mrklroot = genmrklroot(list(dblsha(a) for a in txlist))
54-
timestamp = pack('<L', tmpl['curtime'])
55-
nonce = b'\0\0\0\0'
56-
blk = blkver + a2b_hex(tmpl['previousblockhash'])[::-1] + mrklroot + timestamp + a2b_hex(tmpl['bits'])[::-1] + nonce
57-
blk += varlenEncode(len(txlist))
58-
for tx in txlist:
59-
blk += tx
60-
return bytearray(blk)
61-
62-
def template_to_hex(tmpl, txlist):
63-
return b2x(template_to_bytearray(tmpl, txlist))
64-
65-
def assert_template(node, tmpl, txlist, expect):
66-
rsp = node.getblocktemplate({'data': template_to_hex(tmpl, txlist), 'mode': 'proposal'})
18+
def assert_template(node, block, expect, rehash=True):
19+
if rehash:
20+
block.hashMerkleRoot = block.calc_merkle_root()
21+
rsp = node.getblocktemplate({'data': b2x(block.serialize()), 'mode': 'proposal'})
6722
assert_equal(rsp, expect)
6823

6924
class GetBlockTemplateProposalTest(BitcoinTestFramework):
@@ -78,74 +33,84 @@ def run_test(self):
7833
# Mine a block to leave initial block download
7934
node.generate(1)
8035
tmpl = node.getblocktemplate()
36+
self.log.info("getblocktemplate: Test capability advertised")
37+
assert 'proposal' in tmpl['capabilities']
8138
assert 'coinbasetxn' not in tmpl
8239

8340
coinbase_tx = create_coinbase(height=int(tmpl["height"]) + 1)
8441
# sequence numbers must not be max for nLockTime to have effect
8542
coinbase_tx.vin[0].nSequence = 2 ** 32 - 2
86-
tmpl['coinbasetxn'] = {'data': coinbase_tx.serialize()}
87-
txlist = [bytearray(coinbase_tx.serialize())]
43+
coinbase_tx.rehash()
8844

89-
self.log.info("getblocktemplate: Test capability advertised")
90-
assert 'proposal' in tmpl['capabilities']
45+
block = CBlock()
46+
block.nVersion = tmpl["version"]
47+
block.hashPrevBlock = int(tmpl["previousblockhash"], 16)
48+
block.nTime = tmpl["curtime"]
49+
block.nBits = int(tmpl["bits"], 16)
50+
block.nNonce = 0
51+
block.vtx = [coinbase_tx]
9152

9253
self.log.info("getblocktemplate: Test bad input hash for coinbase transaction")
93-
txlist[0][4 + 1] += 1
94-
assert_template(node, tmpl, txlist, 'bad-cb-missing')
95-
txlist[0][4 + 1] -= 1
54+
bad_block = copy.deepcopy(block)
55+
bad_block.vtx[0].vin[0].prevout.hash += 1
56+
bad_block.vtx[0].rehash()
57+
assert_template(node, bad_block, 'bad-cb-missing')
58+
9659

9760
self.log.info("getblocktemplate: Test truncated final transaction")
98-
lastbyte = txlist[-1].pop()
99-
assert_raises_jsonrpc(-22, "Block decode failed", assert_template, node, tmpl, txlist, 'n/a')
100-
txlist[-1].append(lastbyte)
61+
assert_raises_jsonrpc(-22, "Block decode failed", node.getblocktemplate, {'data': b2x(block.serialize()[:-1]), 'mode': 'proposal'})
10162

10263
self.log.info("getblocktemplate: Test duplicate transaction")
103-
txlist.append(txlist[0])
104-
assert_template(node, tmpl, txlist, 'bad-txns-duplicate')
105-
txlist.pop()
64+
bad_block = copy.deepcopy(block)
65+
bad_block.vtx.append(bad_block.vtx[0])
66+
assert_template(node, bad_block, 'bad-txns-duplicate')
10667

10768
self.log.info("getblocktemplate: Test invalid transaction")
108-
txlist.append(bytearray(txlist[0]))
109-
txlist[-1][4 + 1] = 0xff
110-
assert_template(node, tmpl, txlist, 'bad-txns-inputs-missingorspent')
111-
txlist.pop()
69+
bad_block = copy.deepcopy(block)
70+
bad_tx = copy.deepcopy(bad_block.vtx[0])
71+
bad_tx.vin[0].prevout.hash = 255
72+
bad_tx.rehash()
73+
bad_block.vtx.append(bad_tx)
74+
assert_template(node, bad_block, 'bad-txns-inputs-missingorspent')
11275

11376
self.log.info("getblocktemplate: Test nonfinal transaction")
114-
txlist[0][-4:] = b'\xff\xff\xff\xff'
115-
assert_template(node, tmpl, txlist, 'bad-txns-nonfinal')
116-
txlist[0][-4:] = b'\0\0\0\0'
77+
bad_block = copy.deepcopy(block)
78+
bad_block.vtx[0].nLockTime = 2 ** 32 - 1
79+
bad_block.vtx[0].rehash()
80+
assert_template(node, bad_block, 'bad-txns-nonfinal')
11781

11882
self.log.info("getblocktemplate: Test bad tx count")
119-
txlist.append(b'')
120-
assert_raises_jsonrpc(-22, 'Block decode failed', assert_template, node, tmpl, txlist, 'n/a')
121-
txlist.pop()
83+
# The tx count is immediately after the block header
84+
TX_COUNT_OFFSET = 80
85+
bad_block_sn = bytearray(block.serialize())
86+
assert_equal(bad_block_sn[TX_COUNT_OFFSET], 1)
87+
bad_block_sn[TX_COUNT_OFFSET] += 1
88+
assert_raises_jsonrpc(-22, "Block decode failed", node.getblocktemplate, {'data': b2x(bad_block_sn), 'mode': 'proposal'})
12289

12390
self.log.info("getblocktemplate: Test bad bits")
124-
realbits = tmpl['bits']
125-
tmpl['bits'] = '1c0000ff' # impossible in the real world
126-
assert_template(node, tmpl, txlist, 'bad-diffbits')
127-
tmpl['bits'] = realbits
91+
bad_block = copy.deepcopy(block)
92+
bad_block.nBits = 469762303 # impossible in the real world
93+
assert_template(node, bad_block, 'bad-diffbits')
12894

12995
self.log.info("getblocktemplate: Test bad merkle root")
130-
rawtmpl = template_to_bytearray(tmpl, txlist)
131-
rawtmpl[4 + 32] = (rawtmpl[4 + 32] + 1) % 0x100
132-
rsp = node.getblocktemplate({'data': b2x(rawtmpl), 'mode': 'proposal'})
133-
assert_equal(rsp, 'bad-txnmrklroot')
96+
bad_block = copy.deepcopy(block)
97+
bad_block.hashMerkleRoot += 1
98+
assert_template(node, bad_block, 'bad-txnmrklroot', False)
13499

135100
self.log.info("getblocktemplate: Test bad timestamps")
136-
realtime = tmpl['curtime']
137-
tmpl['curtime'] = 0x7fffffff
138-
assert_template(node, tmpl, txlist, 'time-too-new')
139-
tmpl['curtime'] = 0
140-
assert_template(node, tmpl, txlist, 'time-too-old')
141-
tmpl['curtime'] = realtime
101+
bad_block = copy.deepcopy(block)
102+
bad_block.nTime = 2 ** 31 - 1
103+
assert_template(node, bad_block, 'time-too-new')
104+
bad_block.nTime = 0
105+
assert_template(node, bad_block, 'time-too-old')
142106

143107
self.log.info("getblocktemplate: Test valid block")
144-
assert_template(node, tmpl, txlist, None)
108+
assert_template(node, block, None)
145109

146110
self.log.info("getblocktemplate: Test not best block")
147-
tmpl['previousblockhash'] = 'ff00' * 16
148-
assert_template(node, tmpl, txlist, 'inconclusive-not-best-prevblk')
111+
bad_block = copy.deepcopy(block)
112+
bad_block.hashPrevBlock = 123
113+
assert_template(node, bad_block, 'inconclusive-not-best-prevblk')
149114

150115
if __name__ == '__main__':
151116
GetBlockTemplateProposalTest().main()

0 commit comments

Comments
 (0)