4
4
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
5
"""Test block proposals with getblocktemplate."""
6
6
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
10
9
11
10
from test_framework .blocktools import create_coinbase
12
11
from test_framework .test_framework import BitcoinTestFramework
12
+ from test_framework .mininode import CBlock
13
13
from test_framework .util import *
14
14
15
15
def b2x (b ):
16
16
return b2a_hex (b ).decode ('ascii' )
17
17
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' })
67
22
assert_equal (rsp , expect )
68
23
69
24
class GetBlockTemplateProposalTest (BitcoinTestFramework ):
@@ -78,74 +33,84 @@ def run_test(self):
78
33
# Mine a block to leave initial block download
79
34
node .generate (1 )
80
35
tmpl = node .getblocktemplate ()
36
+ self .log .info ("getblocktemplate: Test capability advertised" )
37
+ assert 'proposal' in tmpl ['capabilities' ]
81
38
assert 'coinbasetxn' not in tmpl
82
39
83
40
coinbase_tx = create_coinbase (height = int (tmpl ["height" ]) + 1 )
84
41
# sequence numbers must not be max for nLockTime to have effect
85
42
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 ()
88
44
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 ]
91
52
92
53
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
+
96
59
97
60
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' })
101
62
102
63
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' )
106
67
107
68
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' )
112
75
113
76
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' )
117
81
118
82
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' })
122
89
123
90
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' )
128
94
129
95
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 )
134
99
135
100
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' )
142
106
143
107
self .log .info ("getblocktemplate: Test valid block" )
144
- assert_template (node , tmpl , txlist , None )
108
+ assert_template (node , block , None )
145
109
146
110
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' )
149
114
150
115
if __name__ == '__main__' :
151
116
GetBlockTemplateProposalTest ().main ()
0 commit comments