1cb2a00cb8
This triggers the tested node to no longer be in initial download, allowing the call to getblocktemplate() to succeed.
183 lines
6.2 KiB
Python
Executable file
183 lines
6.2 KiB
Python
Executable file
#!/usr/bin/env python2
|
|
# Copyright (c) 2014 The Bitcoin Core developers
|
|
# Distributed under the MIT software license, see the accompanying
|
|
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
from test_framework import BitcoinTestFramework
|
|
from bitcoinrpc.authproxy import AuthServiceProxy, JSONRPCException
|
|
from util import *
|
|
|
|
from binascii import a2b_hex, b2a_hex
|
|
from hashlib import sha256
|
|
from struct import pack
|
|
|
|
|
|
def check_array_result(object_array, to_match, expected):
|
|
"""
|
|
Pass in array of JSON objects, a dictionary with key/value pairs
|
|
to match against, and another dictionary with expected key/value
|
|
pairs.
|
|
"""
|
|
num_matched = 0
|
|
for item in object_array:
|
|
all_match = True
|
|
for key,value in to_match.items():
|
|
if item[key] != value:
|
|
all_match = False
|
|
if not all_match:
|
|
continue
|
|
for key,value in expected.items():
|
|
if item[key] != value:
|
|
raise AssertionError("%s : expected %s=%s"%(str(item), str(key), str(value)))
|
|
num_matched = num_matched+1
|
|
if num_matched == 0:
|
|
raise AssertionError("No objects matched %s"%(str(to_match)))
|
|
|
|
def b2x(b):
|
|
return b2a_hex(b).decode('ascii')
|
|
|
|
# NOTE: This does not work for signed numbers (set the high bit) or zero (use b'\0')
|
|
def encodeUNum(n):
|
|
s = bytearray(b'\1')
|
|
while n > 127:
|
|
s[0] += 1
|
|
s.append(n % 256)
|
|
n //= 256
|
|
s.append(n)
|
|
return bytes(s)
|
|
|
|
def varlenEncode(n):
|
|
if n < 0xfd:
|
|
return pack('<B', n)
|
|
if n <= 0xffff:
|
|
return b'\xfd' + pack('<H', n)
|
|
if n <= 0xffffffff:
|
|
return b'\xfe' + pack('<L', n)
|
|
return b'\xff' + pack('<Q', n)
|
|
|
|
def dblsha(b):
|
|
return sha256(sha256(b).digest()).digest()
|
|
|
|
def genmrklroot(leaflist):
|
|
cur = leaflist
|
|
while len(cur) > 1:
|
|
n = []
|
|
if len(cur) & 1:
|
|
cur.append(cur[-1])
|
|
for i in range(0, len(cur), 2):
|
|
n.append(dblsha(cur[i] + cur[i+1]))
|
|
cur = n
|
|
return cur[0]
|
|
|
|
def template_to_bytes(tmpl, txlist):
|
|
blkver = pack('<L', tmpl['version'])
|
|
mrklroot = genmrklroot(list(dblsha(a) for a in txlist))
|
|
timestamp = pack('<L', tmpl['curtime'])
|
|
nonce = b'\0\0\0\0'
|
|
blk = blkver + a2b_hex(tmpl['previousblockhash'])[::-1] + mrklroot + timestamp + a2b_hex(tmpl['bits'])[::-1] + nonce
|
|
blk += varlenEncode(len(txlist))
|
|
for tx in txlist:
|
|
blk += tx
|
|
return blk
|
|
|
|
def template_to_hex(tmpl, txlist):
|
|
return b2x(template_to_bytes(tmpl, txlist))
|
|
|
|
def assert_template(node, tmpl, txlist, expect):
|
|
rsp = node.getblocktemplate({'data':template_to_hex(tmpl, txlist),'mode':'proposal'})
|
|
if rsp != expect:
|
|
raise AssertionError('unexpected: %s' % (rsp,))
|
|
|
|
class GetBlockTemplateProposalTest(BitcoinTestFramework):
|
|
'''
|
|
Test block proposals with getblocktemplate.
|
|
'''
|
|
|
|
def run_test(self):
|
|
node = self.nodes[0]
|
|
node.setgenerate(True, 1) # Mine a block to leave initial block download
|
|
tmpl = node.getblocktemplate()
|
|
if 'coinbasetxn' not in tmpl:
|
|
rawcoinbase = encodeUNum(tmpl['height'])
|
|
rawcoinbase += b'\x01-'
|
|
hexcoinbase = b2x(rawcoinbase)
|
|
hexoutval = b2x(pack('<Q', tmpl['coinbasevalue']))
|
|
tmpl['coinbasetxn'] = {'data': '01000000' + '01' + '0000000000000000000000000000000000000000000000000000000000000000ffffffff' + ('%02x' % (len(rawcoinbase),)) + hexcoinbase + 'fffffffe' + '01' + hexoutval + '00' + '00000000'}
|
|
txlist = list(bytearray(a2b_hex(a['data'])) for a in (tmpl['coinbasetxn'],) + tuple(tmpl['transactions']))
|
|
|
|
# Test 0: Capability advertised
|
|
assert('proposal' in tmpl['capabilities'])
|
|
|
|
# NOTE: This test currently FAILS (regtest mode doesn't enforce block height in coinbase)
|
|
## Test 1: Bad height in coinbase
|
|
#txlist[0][4+1+36+1+1] += 1
|
|
#assert_template(node, tmpl, txlist, 'FIXME')
|
|
#txlist[0][4+1+36+1+1] -= 1
|
|
|
|
# Test 2: Bad input hash for gen tx
|
|
txlist[0][4+1] += 1
|
|
assert_template(node, tmpl, txlist, 'bad-cb-missing')
|
|
txlist[0][4+1] -= 1
|
|
|
|
# Test 3: Truncated final tx
|
|
lastbyte = txlist[-1].pop()
|
|
try:
|
|
assert_template(node, tmpl, txlist, 'n/a')
|
|
except JSONRPCException:
|
|
pass # Expected
|
|
txlist[-1].append(lastbyte)
|
|
|
|
# Test 4: Add an invalid tx to the end (duplicate of gen tx)
|
|
txlist.append(txlist[0])
|
|
assert_template(node, tmpl, txlist, 'bad-txns-duplicate')
|
|
txlist.pop()
|
|
|
|
# Test 5: Add an invalid tx to the end (non-duplicate)
|
|
txlist.append(bytearray(txlist[0]))
|
|
txlist[-1][4+1] = b'\xff'
|
|
assert_template(node, tmpl, txlist, 'bad-txns-inputs-missingorspent')
|
|
txlist.pop()
|
|
|
|
# Test 6: Future tx lock time
|
|
txlist[0][-4:] = b'\xff\xff\xff\xff'
|
|
assert_template(node, tmpl, txlist, 'bad-txns-nonfinal')
|
|
txlist[0][-4:] = b'\0\0\0\0'
|
|
|
|
# Test 7: Bad tx count
|
|
txlist.append(b'')
|
|
try:
|
|
assert_template(node, tmpl, txlist, 'n/a')
|
|
except JSONRPCException:
|
|
pass # Expected
|
|
txlist.pop()
|
|
|
|
# Test 8: Bad bits
|
|
realbits = tmpl['bits']
|
|
tmpl['bits'] = '1c0000ff' # impossible in the real world
|
|
assert_template(node, tmpl, txlist, 'bad-diffbits')
|
|
tmpl['bits'] = realbits
|
|
|
|
# Test 9: Bad merkle root
|
|
rawtmpl = template_to_bytes(tmpl, txlist)
|
|
rawtmpl[4+32] = (rawtmpl[4+32] + 1) % 0x100
|
|
rsp = node.getblocktemplate({'data':b2x(rawtmpl),'mode':'proposal'})
|
|
if rsp != 'bad-txnmrklroot':
|
|
raise AssertionError('unexpected: %s' % (rsp,))
|
|
|
|
# Test 10: Bad timestamps
|
|
realtime = tmpl['curtime']
|
|
tmpl['curtime'] = 0x7fffffff
|
|
assert_template(node, tmpl, txlist, 'time-too-new')
|
|
tmpl['curtime'] = 0
|
|
assert_template(node, tmpl, txlist, 'time-too-old')
|
|
tmpl['curtime'] = realtime
|
|
|
|
# Test 11: Valid block
|
|
assert_template(node, tmpl, txlist, None)
|
|
|
|
# Test 12: Orphan block
|
|
tmpl['previousblockhash'] = 'ff00' * 16
|
|
assert_template(node, tmpl, txlist, 'inconclusive-not-best-prevblk')
|
|
|
|
if __name__ == '__main__':
|
|
GetBlockTemplateProposalTest().main()
|