Skip to content

Commit da38dc6

Browse files
committed
Merge pull request #5981
2703412 Fix default binary in p2p tests to use environment variable (Suhas Daftuar) 29bff0e Add some travis debugging for python scripts (Suhas Daftuar) d76412b Add script manipulation tools for use in mininode testing framework (Suhas Daftuar) b93974c Add comparison tool test runner, built on mininode (Suhas Daftuar) 6c1d1ba Python p2p testing framework (Suhas Daftuar)
2 parents 9c25397 + 2703412 commit da38dc6

14 files changed

+3467
-4
lines changed

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ env:
1616
- CCACHE_COMPRESS=1
1717
- BASE_OUTDIR=$TRAVIS_BUILD_DIR/out
1818
- SDK_URL=https://bitcoincore.org/depends-sources/sdks
19+
- PYTHON_DEBUG=1
1920
cache:
2021
apt: true
2122
directories:

qa/pull-tester/rpc-tests.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ testScripts=(
3030
'proxy_test.py'
3131
'merkle_blocks.py'
3232
# 'forknotify.py'
33+
'maxblocksinflight.py'
34+
'invalidblockrequest.py'
3335
);
3436
if [ "x${ENABLE_BITCOIND}${ENABLE_UTILS}${ENABLE_WALLET}" = "x111" ]; then
3537
for (( i = 0; i < ${#testScripts[@]}; i++ ))

qa/rpc-tests/bignum.py

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
#
2+
#
3+
# bignum.py
4+
#
5+
# This file is copied from python-bitcoinlib.
6+
#
7+
# Distributed under the MIT/X11 software license, see the accompanying
8+
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
9+
#
10+
11+
"""Bignum routines"""
12+
13+
from __future__ import absolute_import, division, print_function, unicode_literals
14+
15+
import struct
16+
17+
18+
# generic big endian MPI format
19+
20+
def bn_bytes(v, have_ext=False):
21+
ext = 0
22+
if have_ext:
23+
ext = 1
24+
return ((v.bit_length()+7)//8) + ext
25+
26+
def bn2bin(v):
27+
s = bytearray()
28+
i = bn_bytes(v)
29+
while i > 0:
30+
s.append((v >> ((i-1) * 8)) & 0xff)
31+
i -= 1
32+
return s
33+
34+
def bin2bn(s):
35+
l = 0
36+
for ch in s:
37+
l = (l << 8) | ch
38+
return l
39+
40+
def bn2mpi(v):
41+
have_ext = False
42+
if v.bit_length() > 0:
43+
have_ext = (v.bit_length() & 0x07) == 0
44+
45+
neg = False
46+
if v < 0:
47+
neg = True
48+
v = -v
49+
50+
s = struct.pack(b">I", bn_bytes(v, have_ext))
51+
ext = bytearray()
52+
if have_ext:
53+
ext.append(0)
54+
v_bin = bn2bin(v)
55+
if neg:
56+
if have_ext:
57+
ext[0] |= 0x80
58+
else:
59+
v_bin[0] |= 0x80
60+
return s + ext + v_bin
61+
62+
def mpi2bn(s):
63+
if len(s) < 4:
64+
return None
65+
s_size = bytes(s[:4])
66+
v_len = struct.unpack(b">I", s_size)[0]
67+
if len(s) != (v_len + 4):
68+
return None
69+
if v_len == 0:
70+
return 0
71+
72+
v_str = bytearray(s[4:])
73+
neg = False
74+
i = v_str[0]
75+
if i & 0x80:
76+
neg = True
77+
i &= ~0x80
78+
v_str[0] = i
79+
80+
v = bin2bn(v_str)
81+
82+
if neg:
83+
return -v
84+
return v
85+
86+
# bitcoin-specific little endian format, with implicit size
87+
def mpi2vch(s):
88+
r = s[4:] # strip size
89+
r = r[::-1] # reverse string, converting BE->LE
90+
return r
91+
92+
def bn2vch(v):
93+
return bytes(mpi2vch(bn2mpi(v)))
94+
95+
def vch2mpi(s):
96+
r = struct.pack(b">I", len(s)) # size
97+
r += s[::-1] # reverse string, converting LE->BE
98+
return r
99+
100+
def vch2bn(s):
101+
return mpi2bn(vch2mpi(s))
102+

qa/rpc-tests/bipdersig-p2p.py

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
#!/usr/bin/env python2
2+
#
3+
# Distributed under the MIT/X11 software license, see the accompanying
4+
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
5+
#
6+
7+
from test_framework import ComparisonTestFramework
8+
from util import *
9+
from mininode import CTransaction, NetworkThread
10+
from blocktools import create_coinbase, create_block
11+
from binascii import hexlify, unhexlify
12+
import cStringIO
13+
from comptool import TestInstance, TestManager
14+
from script import CScript
15+
import time
16+
17+
# A canonical signature consists of:
18+
# <30> <total len> <02> <len R> <R> <02> <len S> <S> <hashtype>
19+
def unDERify(tx):
20+
'''
21+
Make the signature in vin 0 of a tx non-DER-compliant,
22+
by adding padding after the S-value.
23+
'''
24+
scriptSig = CScript(tx.vin[0].scriptSig)
25+
newscript = []
26+
for i in scriptSig:
27+
if (len(newscript) == 0):
28+
newscript.append(i[0:-1] + '\0' + i[-1])
29+
else:
30+
newscript.append(i)
31+
tx.vin[0].scriptSig = CScript(newscript)
32+
33+
'''
34+
This test is meant to exercise BIP66 (DER SIG).
35+
Connect to a single node.
36+
Mine 2 (version 2) blocks (save the coinbases for later).
37+
Generate 98 more version 2 blocks, verify the node accepts.
38+
Mine 749 version 3 blocks, verify the node accepts.
39+
Check that the new DERSIG rules are not enforced on the 750th version 3 block.
40+
Check that the new DERSIG rules are enforced on the 751st version 3 block.
41+
Mine 199 new version blocks.
42+
Mine 1 old-version block.
43+
Mine 1 new version block.
44+
Mine 1 old version block, see that the node rejects.
45+
'''
46+
47+
class BIP66Test(ComparisonTestFramework):
48+
49+
def __init__(self):
50+
self.num_nodes = 1
51+
52+
def setup_network(self):
53+
# Must set the blockversion for this test
54+
self.nodes = start_nodes(1, self.options.tmpdir,
55+
extra_args=[['-debug', '-whitelist=127.0.0.1', '-blockversion=2']],
56+
binary=[self.options.testbinary])
57+
58+
def run_test(self):
59+
test = TestManager(self, self.options.tmpdir)
60+
test.add_all_connections(self.nodes)
61+
NetworkThread().start() # Start up network handling in another thread
62+
test.run()
63+
64+
def create_transaction(self, node, coinbase, to_address, amount):
65+
from_txid = node.getblock(coinbase)['tx'][0]
66+
inputs = [{ "txid" : from_txid, "vout" : 0}]
67+
outputs = { to_address : amount }
68+
rawtx = node.createrawtransaction(inputs, outputs)
69+
signresult = node.signrawtransaction(rawtx)
70+
tx = CTransaction()
71+
f = cStringIO.StringIO(unhexlify(signresult['hex']))
72+
tx.deserialize(f)
73+
return tx
74+
75+
def get_tests(self):
76+
77+
self.coinbase_blocks = self.nodes[0].generate(2)
78+
self.tip = int ("0x" + self.nodes[0].getbestblockhash() + "L", 0)
79+
self.nodeaddress = self.nodes[0].getnewaddress()
80+
self.last_block_time = time.time()
81+
82+
''' 98 more version 2 blocks '''
83+
test_blocks = []
84+
for i in xrange(98):
85+
block = create_block(self.tip, create_coinbase(2), self.last_block_time + 1)
86+
block.nVersion = 2
87+
block.rehash()
88+
block.solve()
89+
test_blocks.append([block, True])
90+
self.last_block_time += 1
91+
self.tip = block.sha256
92+
yield TestInstance(test_blocks, sync_every_block=False)
93+
94+
''' Mine 749 version 3 blocks '''
95+
test_blocks = []
96+
for i in xrange(749):
97+
block = create_block(self.tip, create_coinbase(2), self.last_block_time + 1)
98+
block.nVersion = 3
99+
block.rehash()
100+
block.solve()
101+
test_blocks.append([block, True])
102+
self.last_block_time += 1
103+
self.tip = block.sha256
104+
yield TestInstance(test_blocks, sync_every_block=False)
105+
106+
'''
107+
Check that the new DERSIG rules are not enforced in the 750th
108+
version 3 block.
109+
'''
110+
spendtx = self.create_transaction(self.nodes[0],
111+
self.coinbase_blocks[0], self.nodeaddress, 1.0)
112+
unDERify(spendtx)
113+
spendtx.rehash()
114+
115+
block = create_block(self.tip, create_coinbase(2), self.last_block_time + 1)
116+
block.nVersion = 3
117+
block.vtx.append(spendtx)
118+
block.hashMerkleRoot = block.calc_merkle_root()
119+
block.rehash()
120+
block.solve()
121+
122+
self.last_block_time += 1
123+
self.tip = block.sha256
124+
yield TestInstance([[block, True]])
125+
126+
'''
127+
Check that the new DERSIG rules are enforced in the 751st version 3
128+
block.
129+
'''
130+
spendtx = self.create_transaction(self.nodes[0],
131+
self.coinbase_blocks[1], self.nodeaddress, 1.0)
132+
unDERify(spendtx)
133+
spendtx.rehash()
134+
135+
block = create_block(self.tip, create_coinbase(1), self.last_block_time + 1)
136+
block.nVersion = 3
137+
block.vtx.append(spendtx)
138+
block.hashMerkleRoot = block.calc_merkle_root()
139+
block.rehash()
140+
block.solve()
141+
self.last_block_time += 1
142+
yield TestInstance([[block, False]])
143+
144+
''' Mine 199 new version blocks on last valid tip '''
145+
test_blocks = []
146+
for i in xrange(199):
147+
block = create_block(self.tip, create_coinbase(1), self.last_block_time + 1)
148+
block.nVersion = 3
149+
block.rehash()
150+
block.solve()
151+
test_blocks.append([block, True])
152+
self.last_block_time += 1
153+
self.tip = block.sha256
154+
yield TestInstance(test_blocks, sync_every_block=False)
155+
156+
''' Mine 1 old version block '''
157+
block = create_block(self.tip, create_coinbase(1), self.last_block_time + 1)
158+
block.nVersion = 2
159+
block.rehash()
160+
block.solve()
161+
self.last_block_time += 1
162+
self.tip = block.sha256
163+
yield TestInstance([[block, True]])
164+
165+
''' Mine 1 new version block '''
166+
block = create_block(self.tip, create_coinbase(1), self.last_block_time + 1)
167+
block.nVersion = 3
168+
block.rehash()
169+
block.solve()
170+
self.last_block_time += 1
171+
self.tip = block.sha256
172+
yield TestInstance([[block, True]])
173+
174+
''' Mine 1 old version block, should be invalid '''
175+
block = create_block(self.tip, create_coinbase(1), self.last_block_time + 1)
176+
block.nVersion = 2
177+
block.rehash()
178+
block.solve()
179+
self.last_block_time += 1
180+
yield TestInstance([[block, False]])
181+
182+
if __name__ == '__main__':
183+
BIP66Test().main()

0 commit comments

Comments
 (0)