Skip to content

Commit 5bd6e9e

Browse files
sdaftuarsipa
authored andcommitted
Update p2p test framework with segwit support
mininode now supports witness transactions/blocks, blocktools has a helper for adding witness commitments to blocks, and script has a function to calculate hashes for signature under sigversion 1, used by segwit.
1 parent 240cc9a commit 5bd6e9e

File tree

3 files changed

+257
-22
lines changed

3 files changed

+257
-22
lines changed

qa/rpc-tests/test_framework/blocktools.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
#
66

77
from mininode import *
8-
from script import CScript, OP_TRUE, OP_CHECKSIG
8+
from script import CScript, OP_TRUE, OP_CHECKSIG, OP_RETURN
99

1010
# Create a block (with regtest difficulty)
1111
def create_block(hashprev, coinbase, nTime=None):
@@ -22,6 +22,29 @@ def create_block(hashprev, coinbase, nTime=None):
2222
block.calc_sha256()
2323
return block
2424

25+
# From BIP141
26+
WITNESS_COMMITMENT_HEADER = "\xaa\x21\xa9\xed"
27+
28+
# According to BIP141, nVersion=5 blocks must commit to the
29+
# hash of all in-block transactions including witness.
30+
def add_witness_commitment(block, nonce=0L):
31+
# First calculate the merkle root of the block's
32+
# transactions, with witnesses.
33+
witness_nonce = nonce
34+
witness_root = block.calc_witness_merkle_root()
35+
witness_commitment = uint256_from_str(hash256(ser_uint256(witness_root)+ser_uint256(witness_nonce)))
36+
# witness_nonce should go to coinbase witness.
37+
block.vtx[0].wit.vtxinwit = [CTxinWitness()]
38+
block.vtx[0].wit.vtxinwit[0].scriptWitness.stack = [ser_uint256(witness_nonce)]
39+
40+
# witness commitment is the last OP_RETURN output in coinbase
41+
output_data = WITNESS_COMMITMENT_HEADER + ser_uint256(witness_commitment)
42+
block.vtx[0].vout.append(CTxOut(0, CScript([OP_RETURN, output_data])))
43+
block.vtx[0].rehash()
44+
block.hashMerkleRoot = block.calc_merkle_root()
45+
block.rehash()
46+
47+
2548
def serialize_script_num(value):
2649
r = bytearray(0)
2750
if value == 0:

qa/rpc-tests/test_framework/mininode.py

Lines changed: 182 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@
3838
MAX_INV_SZ = 50000
3939
MAX_BLOCK_SIZE = 1000000
4040

41+
NODE_NETWORK = (1 << 0)
42+
NODE_GETUTXO = (1 << 1)
43+
NODE_BLOOM = (1 << 2)
44+
NODE_WITNESS = (1 << 3)
45+
4146
# Keep our own socket map for asyncore, so that we can track disconnects
4247
# ourselves (to workaround an issue with closing an asyncore socket when
4348
# using select)
@@ -127,7 +132,10 @@ def deser_vector(f, c):
127132
return r
128133

129134

130-
def ser_vector(l):
135+
# ser_function_name: Allow for an alternate serialization function on the
136+
# entries in the vector (we use this for serializing the vector of transactions
137+
# for a witness block).
138+
def ser_vector(l, ser_function_name=None):
131139
r = ""
132140
if len(l) < 253:
133141
r = chr(len(l))
@@ -138,7 +146,10 @@ def ser_vector(l):
138146
else:
139147
r = chr(255) + struct.pack("<Q", len(l))
140148
for i in l:
141-
r += i.serialize()
149+
if ser_function_name:
150+
r += getattr(i, ser_function_name)()
151+
else:
152+
r += i.serialize()
142153
return r
143154

144155

@@ -267,12 +278,16 @@ def __repr__(self):
267278
return "CAddress(nServices=%i ip=%s port=%i)" % (self.nServices,
268279
self.ip, self.port)
269280

281+
MSG_WITNESS_FLAG = 1<<30
270282

271283
class CInv(object):
272284
typemap = {
273285
0: "Error",
274286
1: "TX",
275-
2: "Block"}
287+
2: "Block",
288+
1|MSG_WITNESS_FLAG: "WitnessTx",
289+
2|MSG_WITNESS_FLAG : "WitnessBlock"
290+
}
276291

277292
def __init__(self, t=0, h=0L):
278293
self.type = t
@@ -381,12 +396,73 @@ def __repr__(self):
381396
binascii.hexlify(self.scriptPubKey))
382397

383398

399+
class CScriptWitness(object):
400+
def __init__(self):
401+
# stack is a vector of strings
402+
self.stack = []
403+
404+
def __repr__(self):
405+
return "CScriptWitness(%s)" % \
406+
(",".join([binascii.hexlify(x) for x in self.stack]))
407+
408+
def is_null(self):
409+
if self.stack:
410+
return False
411+
return True
412+
413+
414+
class CTxinWitness(object):
415+
def __init__(self):
416+
self.scriptWitness = CScriptWitness()
417+
418+
def deserialize(self, f):
419+
self.scriptWitness.stack = deser_string_vector(f)
420+
421+
def serialize(self):
422+
return ser_string_vector(self.scriptWitness.stack)
423+
424+
def __repr__(self):
425+
return repr(self.scriptWitness)
426+
427+
def is_null(self):
428+
return self.scriptWitness.is_null()
429+
430+
431+
class CTxWitness(object):
432+
def __init__(self):
433+
self.vtxinwit = []
434+
435+
def deserialize(self, f):
436+
for i in xrange(len(self.vtxinwit)):
437+
self.vtxinwit[i].deserialize(f)
438+
439+
def serialize(self):
440+
r = ""
441+
# This is different than the usual vector serialization --
442+
# we omit the length of the vector, which is required to be
443+
# the same length as the transaction's vin vector.
444+
for x in self.vtxinwit:
445+
r += x.serialize()
446+
return r
447+
448+
def __repr__(self):
449+
return "CTxWitness(%s)" % \
450+
(';'.join([repr(x) for x in self.vtxinwit]))
451+
452+
def is_null(self):
453+
for x in self.vtxinwit:
454+
if not x.is_null():
455+
return False
456+
return True
457+
458+
384459
class CTransaction(object):
385460
def __init__(self, tx=None):
386461
if tx is None:
387462
self.nVersion = 1
388463
self.vin = []
389464
self.vout = []
465+
self.wit = CTxWitness()
390466
self.nLockTime = 0
391467
self.sha256 = None
392468
self.hash = None
@@ -395,33 +471,82 @@ def __init__(self, tx=None):
395471
self.vin = copy.deepcopy(tx.vin)
396472
self.vout = copy.deepcopy(tx.vout)
397473
self.nLockTime = tx.nLockTime
398-
self.sha256 = None
399-
self.hash = None
474+
self.sha256 = tx.sha256
475+
self.hash = tx.hash
476+
self.wit = copy.deepcopy(tx.wit)
400477

401478
def deserialize(self, f):
402479
self.nVersion = struct.unpack("<i", f.read(4))[0]
403480
self.vin = deser_vector(f, CTxIn)
404-
self.vout = deser_vector(f, CTxOut)
481+
flags = 0
482+
if len(self.vin) == 0:
483+
flags = struct.unpack("<B", f.read(1))[0]
484+
# Not sure why flags can't be zero, but this
485+
# matches the implementation in bitcoind
486+
if (flags != 0):
487+
self.vin = deser_vector(f, CTxIn)
488+
self.vout = deser_vector(f, CTxOut)
489+
else:
490+
self.vout = deser_vector(f, CTxOut)
491+
if flags != 0:
492+
self.wit.vtxinwit = [CTxinWitness()]*len(self.vin)
493+
self.wit.deserialize(f)
405494
self.nLockTime = struct.unpack("<I", f.read(4))[0]
406495
self.sha256 = None
407496
self.hash = None
408497

409-
def serialize(self):
498+
def serialize_without_witness(self):
499+
r = ""
500+
r += struct.pack("<i", self.nVersion)
501+
r += ser_vector(self.vin)
502+
r += ser_vector(self.vout)
503+
r += struct.pack("<I", self.nLockTime)
504+
return r
505+
506+
# Only serialize with witness when explicitly called for
507+
def serialize_with_witness(self):
508+
flags = 0
509+
if not self.wit.is_null():
510+
flags |= 1
410511
r = ""
411512
r += struct.pack("<i", self.nVersion)
513+
if flags:
514+
dummy = []
515+
r += ser_vector(dummy)
516+
r += struct.pack("<B", flags)
412517
r += ser_vector(self.vin)
413518
r += ser_vector(self.vout)
519+
if flags & 1:
520+
if (len(self.wit.vtxinwit) != len(self.vin)):
521+
# vtxinwit must have the same length as vin
522+
self.wit.vtxinwit = self.wit.vtxinwit[:len(self.vin)]
523+
for i in xrange(len(self.wit.vtxinwit), len(self.vin)):
524+
self.wit.vtxinwit.append(CTxinWitness())
525+
r += self.wit.serialize()
414526
r += struct.pack("<I", self.nLockTime)
415527
return r
416528

529+
# Regular serialization is without witness -- must explicitly
530+
# call serialize_with_witness to include witness data.
531+
def serialize(self):
532+
return self.serialize_without_witness()
533+
534+
# Recalculate the txid (transaction hash without witness)
417535
def rehash(self):
418536
self.sha256 = None
419537
self.calc_sha256()
420538

421-
def calc_sha256(self):
539+
# We will only cache the serialization without witness in
540+
# self.sha256 and self.hash -- those are expected to be the txid.
541+
def calc_sha256(self, with_witness=False):
542+
if with_witness:
543+
# Don't cache the result, just return it
544+
return uint256_from_str(hash256(self.serialize_with_witness()))
545+
422546
if self.sha256 is None:
423-
self.sha256 = uint256_from_str(hash256(self.serialize()))
547+
self.sha256 = uint256_from_str(hash256(self.serialize_without_witness()))
424548
self.hash = hash256(self.serialize())[::-1].encode('hex_codec')
549+
return self.sha256
425550

426551
def is_valid(self):
427552
self.calc_sha256()
@@ -512,17 +637,17 @@ def deserialize(self, f):
512637
super(CBlock, self).deserialize(f)
513638
self.vtx = deser_vector(f, CTransaction)
514639

515-
def serialize(self):
640+
def serialize(self, with_witness=False):
516641
r = ""
517642
r += super(CBlock, self).serialize()
518-
r += ser_vector(self.vtx)
643+
if with_witness:
644+
r += ser_vector(self.vtx, "serialize_with_witness")
645+
else:
646+
r += ser_vector(self.vtx)
519647
return r
520648

521-
def calc_merkle_root(self):
522-
hashes = []
523-
for tx in self.vtx:
524-
tx.calc_sha256()
525-
hashes.append(ser_uint256(tx.sha256))
649+
# Calculate the merkle root given a vector of transaction hashes
650+
def get_merkle_root(self, hashes):
526651
while len(hashes) > 1:
527652
newhashes = []
528653
for i in xrange(0, len(hashes), 2):
@@ -531,6 +656,24 @@ def calc_merkle_root(self):
531656
hashes = newhashes
532657
return uint256_from_str(hashes[0])
533658

659+
def calc_merkle_root(self):
660+
hashes = []
661+
for tx in self.vtx:
662+
tx.calc_sha256()
663+
hashes.append(ser_uint256(tx.sha256))
664+
return self.get_merkle_root(hashes)
665+
666+
def calc_witness_merkle_root(self):
667+
# For witness root purposes, the hash of the
668+
# coinbase, with witness, is defined to be 0...0
669+
hashes = [ser_uint256(0)]
670+
671+
for tx in self.vtx[1:]:
672+
# Calculate the hashes with witness data
673+
hashes.append(ser_uint256(tx.calc_sha256(True)))
674+
675+
return self.get_merkle_root(hashes)
676+
534677
def is_valid(self):
535678
self.calc_sha256()
536679
target = uint256_from_compact(self.nBits)
@@ -806,11 +949,16 @@ def deserialize(self, f):
806949
self.tx.deserialize(f)
807950

808951
def serialize(self):
809-
return self.tx.serialize()
952+
return self.tx.serialize_without_witness()
810953

811954
def __repr__(self):
812955
return "msg_tx(tx=%s)" % (repr(self.tx))
813956

957+
class msg_witness_tx(msg_tx):
958+
959+
def serialize(self):
960+
return self.tx.serialize_with_witness()
961+
814962

815963
class msg_block(object):
816964
command = "block"
@@ -830,6 +978,12 @@ def serialize(self):
830978
def __repr__(self):
831979
return "msg_block(block=%s)" % (repr(self.block))
832980

981+
class msg_witness_block(msg_block):
982+
983+
def serialize(self):
984+
r = self.block.serialize(with_witness=True)
985+
return r
986+
833987

834988
class msg_getaddr(object):
835989
command = "getaddr"
@@ -929,6 +1083,7 @@ def serialize(self):
9291083
def __repr__(self):
9301084
return "msg_sendheaders()"
9311085

1086+
9321087
# getheaders message has
9331088
# number of entries
9341089
# vector of hashes
@@ -1016,6 +1171,8 @@ def __init__(self):
10161171
# tests; it causes message delivery to sleep for the specified time
10171172
# before acquiring the global lock and delivering the next message.
10181173
self.deliver_sleep_time = None
1174+
# Remember the services our peer has advertised
1175+
self.peer_services = None
10191176

10201177
def set_deliver_sleep_time(self, value):
10211178
with mininode_lock:
@@ -1053,6 +1210,7 @@ def on_version(self, conn, message):
10531210
conn.ver_send = min(MY_VERSION, message.nVersion)
10541211
if message.nVersion < 209:
10551212
conn.ver_recv = conn.ver_send
1213+
conn.nServices = message.nServices
10561214

10571215
def on_verack(self, conn, message):
10581216
conn.ver_recv = conn.ver_send
@@ -1082,6 +1240,7 @@ def on_reject(self, conn, message): pass
10821240
def on_close(self, conn): pass
10831241
def on_mempool(self, conn): pass
10841242
def on_pong(self, conn, message): pass
1243+
def on_sendheaders(self, conn, message): pass
10851244

10861245

10871246
# The actual NodeConn class
@@ -1103,15 +1262,17 @@ class NodeConn(asyncore.dispatcher):
11031262
"headers": msg_headers,
11041263
"getheaders": msg_getheaders,
11051264
"reject": msg_reject,
1106-
"mempool": msg_mempool
1265+
"mempool": msg_mempool,
1266+
"sendheaders": msg_sendheaders,
11071267
}
11081268
MAGIC_BYTES = {
11091269
"mainnet": "\xf9\xbe\xb4\xd9", # mainnet
11101270
"testnet3": "\x0b\x11\x09\x07", # testnet3
1111-
"regtest": "\xfa\xbf\xb5\xda" # regtest
1271+
"regtest": "\xfa\xbf\xb5\xda", # regtest
1272+
"segnet": "\x2e\x96\xea\xca" # segnet
11121273
}
11131274

1114-
def __init__(self, dstaddr, dstport, rpc, callback, net="regtest", services=1):
1275+
def __init__(self, dstaddr, dstport, rpc, callback, net="regtest", services=NODE_NETWORK):
11151276
asyncore.dispatcher.__init__(self, map=mininode_socket_map)
11161277
self.log = logging.getLogger("NodeConn(%s:%d)" % (dstaddr, dstport))
11171278
self.dstaddr = dstaddr
@@ -1126,6 +1287,7 @@ def __init__(self, dstaddr, dstport, rpc, callback, net="regtest", services=1):
11261287
self.network = net
11271288
self.cb = callback
11281289
self.disconnect = False
1290+
self.nServices = 0
11291291

11301292
# stuff version msg into sendbuf
11311293
vt = msg_version()

0 commit comments

Comments
 (0)