Browse Source

[qa] p2p segwit tests

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.

Py3 conversion by Marco Falke

Test to make sure upgraded nodes don't ask for non-wit blocks by
Gregory Sanders.
0.13
Suhas Daftuar 9 years ago committed by Pieter Wuille
parent
commit
330b0f31ee
  1. 1
      qa/pull-tester/rpc-tests.py
  2. 1646
      qa/rpc-tests/p2p-segwit.py
  3. 25
      qa/rpc-tests/test_framework/blocktools.py
  4. 212
      qa/rpc-tests/test_framework/mininode.py
  5. 52
      qa/rpc-tests/test_framework/script.py
  6. 84
      src/test/data/script_tests.json
  7. 47
      src/test/script_tests.cpp

1
qa/pull-tester/rpc-tests.py

@ -136,6 +136,7 @@ testScripts = [ @@ -136,6 +136,7 @@ testScripts = [
'invalidtxrequest.py',
'abandonconflict.py',
'p2p-versionbits-warning.py',
'p2p-segwit.py',
'segwit.py',
'importprunedfunds.py',
'signmessages.py',

1646
qa/rpc-tests/p2p-segwit.py

File diff suppressed because it is too large Load Diff

25
qa/rpc-tests/test_framework/blocktools.py

@ -5,7 +5,7 @@ @@ -5,7 +5,7 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
from .mininode import *
from .script import CScript, OP_TRUE, OP_CHECKSIG
from .script import CScript, OP_TRUE, OP_CHECKSIG, OP_RETURN
# Create a block (with regtest difficulty)
def create_block(hashprev, coinbase, nTime=None):
@ -22,6 +22,29 @@ def create_block(hashprev, coinbase, nTime=None): @@ -22,6 +22,29 @@ def create_block(hashprev, coinbase, nTime=None):
block.calc_sha256()
return block
# From BIP141
WITNESS_COMMITMENT_HEADER = b"\xaa\x21\xa9\xed"
# According to BIP141, blocks with witness rules active must commit to the
# hash of all in-block transactions including witness.
def add_witness_commitment(block, nonce=0):
# First calculate the merkle root of the block's
# transactions, with witnesses.
witness_nonce = nonce
witness_root = block.calc_witness_merkle_root()
witness_commitment = uint256_from_str(hash256(ser_uint256(witness_root)+ser_uint256(witness_nonce)))
# witness_nonce should go to coinbase witness.
block.vtx[0].wit.vtxinwit = [CTxinWitness()]
block.vtx[0].wit.vtxinwit[0].scriptWitness.stack = [ser_uint256(witness_nonce)]
# witness commitment is the last OP_RETURN output in coinbase
output_data = WITNESS_COMMITMENT_HEADER + ser_uint256(witness_commitment)
block.vtx[0].vout.append(CTxOut(0, CScript([OP_RETURN, output_data])))
block.vtx[0].rehash()
block.hashMerkleRoot = block.calc_merkle_root()
block.rehash()
def serialize_script_num(value):
r = bytearray(0)
if value == 0:

212
qa/rpc-tests/test_framework/mininode.py

@ -28,7 +28,7 @@ import asyncore @@ -28,7 +28,7 @@ import asyncore
import time
import sys
import random
from binascii import hexlify, unhexlify
from .util import hex_str_to_bytes, bytes_to_hex_str
from io import BytesIO
from codecs import encode
import hashlib
@ -46,6 +46,11 @@ MAX_BLOCK_SIZE = 1000000 @@ -46,6 +46,11 @@ MAX_BLOCK_SIZE = 1000000
COIN = 100000000 # 1 btc in satoshis
NODE_NETWORK = (1 << 0)
NODE_GETUTXO = (1 << 1)
NODE_BLOOM = (1 << 2)
NODE_WITNESS = (1 << 3)
# Keep our own socket map for asyncore, so that we can track disconnects
# ourselves (to workaround an issue with closing an asyncore socket when
# using select)
@ -63,6 +68,8 @@ mininode_lock = RLock() @@ -63,6 +68,8 @@ mininode_lock = RLock()
def sha256(s):
return hashlib.new('sha256', s).digest()
def ripemd160(s):
return hashlib.new('ripemd160', s).digest()
def hash256(s):
return sha256(sha256(s))
@ -133,7 +140,10 @@ def deser_vector(f, c): @@ -133,7 +140,10 @@ def deser_vector(f, c):
return r
def ser_vector(l):
# ser_function_name: Allow for an alternate serialization function on the
# entries in the vector (we use this for serializing the vector of transactions
# for a witness block).
def ser_vector(l, ser_function_name=None):
r = b""
if len(l) < 253:
r = struct.pack("B", len(l))
@ -144,7 +154,10 @@ def ser_vector(l): @@ -144,7 +154,10 @@ def ser_vector(l):
else:
r = struct.pack("<BQ", 255, len(l))
for i in l:
r += i.serialize()
if ser_function_name:
r += getattr(i, ser_function_name)()
else:
r += i.serialize()
return r
@ -239,12 +252,12 @@ def ser_int_vector(l): @@ -239,12 +252,12 @@ def ser_int_vector(l):
# Deserialize from a hex string representation (eg from RPC)
def FromHex(obj, hex_string):
obj.deserialize(BytesIO(unhexlify(hex_string.encode('ascii'))))
obj.deserialize(BytesIO(hex_str_to_bytes(hex_string)))
return obj
# Convert a binary-serializable object to hex (eg for submission via RPC)
def ToHex(obj):
return hexlify(obj.serialize()).decode('ascii')
return bytes_to_hex_str(obj.serialize())
# Objects that map to bitcoind objects, which can be serialized/deserialized
@ -273,12 +286,16 @@ class CAddress(object): @@ -273,12 +286,16 @@ class CAddress(object):
return "CAddress(nServices=%i ip=%s port=%i)" % (self.nServices,
self.ip, self.port)
MSG_WITNESS_FLAG = 1<<30
class CInv(object):
typemap = {
0: "Error",
1: "TX",
2: "Block"}
2: "Block",
1|MSG_WITNESS_FLAG: "WitnessTx",
2|MSG_WITNESS_FLAG : "WitnessBlock"
}
def __init__(self, t=0, h=0):
self.type = t
@ -362,7 +379,7 @@ class CTxIn(object): @@ -362,7 +379,7 @@ class CTxIn(object):
def __repr__(self):
return "CTxIn(prevout=%s scriptSig=%s nSequence=%i)" \
% (repr(self.prevout), hexlify(self.scriptSig),
% (repr(self.prevout), bytes_to_hex_str(self.scriptSig),
self.nSequence)
@ -384,7 +401,67 @@ class CTxOut(object): @@ -384,7 +401,67 @@ class CTxOut(object):
def __repr__(self):
return "CTxOut(nValue=%i.%08i scriptPubKey=%s)" \
% (self.nValue // COIN, self.nValue % COIN,
hexlify(self.scriptPubKey))
bytes_to_hex_str(self.scriptPubKey))
class CScriptWitness(object):
def __init__(self):
# stack is a vector of strings
self.stack = []
def __repr__(self):
return "CScriptWitness(%s)" % \
(",".join([bytes_to_hex_str(x) for x in self.stack]))
def is_null(self):
if self.stack:
return False
return True
class CTxinWitness(object):
def __init__(self):
self.scriptWitness = CScriptWitness()
def deserialize(self, f):
self.scriptWitness.stack = deser_string_vector(f)
def serialize(self):
return ser_string_vector(self.scriptWitness.stack)
def __repr__(self):
return repr(self.scriptWitness)
def is_null(self):
return self.scriptWitness.is_null()
class CTxWitness(object):
def __init__(self):
self.vtxinwit = []
def deserialize(self, f):
for i in range(len(self.vtxinwit)):
self.vtxinwit[i].deserialize(f)
def serialize(self):
r = b""
# This is different than the usual vector serialization --
# we omit the length of the vector, which is required to be
# the same length as the transaction's vin vector.
for x in self.vtxinwit:
r += x.serialize()
return r
def __repr__(self):
return "CTxWitness(%s)" % \
(';'.join([repr(x) for x in self.vtxinwit]))
def is_null(self):
for x in self.vtxinwit:
if not x.is_null():
return False
return True
class CTransaction(object):
@ -393,6 +470,7 @@ class CTransaction(object): @@ -393,6 +470,7 @@ class CTransaction(object):
self.nVersion = 1
self.vin = []
self.vout = []
self.wit = CTxWitness()
self.nLockTime = 0
self.sha256 = None
self.hash = None
@ -401,32 +479,80 @@ class CTransaction(object): @@ -401,32 +479,80 @@ class CTransaction(object):
self.vin = copy.deepcopy(tx.vin)
self.vout = copy.deepcopy(tx.vout)
self.nLockTime = tx.nLockTime
self.sha256 = None
self.hash = None
self.sha256 = tx.sha256
self.hash = tx.hash
self.wit = copy.deepcopy(tx.wit)
def deserialize(self, f):
self.nVersion = struct.unpack("<i", f.read(4))[0]
self.vin = deser_vector(f, CTxIn)
self.vout = deser_vector(f, CTxOut)
flags = 0
if len(self.vin) == 0:
flags = struct.unpack("<B", f.read(1))[0]
# Not sure why flags can't be zero, but this
# matches the implementation in bitcoind
if (flags != 0):
self.vin = deser_vector(f, CTxIn)
self.vout = deser_vector(f, CTxOut)
else:
self.vout = deser_vector(f, CTxOut)
if flags != 0:
self.wit.vtxinwit = [CTxinWitness()]*len(self.vin)
self.wit.deserialize(f)
self.nLockTime = struct.unpack("<I", f.read(4))[0]
self.sha256 = None
self.hash = None
def serialize(self):
def serialize_without_witness(self):
r = b""
r += struct.pack("<i", self.nVersion)
r += ser_vector(self.vin)
r += ser_vector(self.vout)
r += struct.pack("<I", self.nLockTime)
return r
# Only serialize with witness when explicitly called for
def serialize_with_witness(self):
flags = 0
if not self.wit.is_null():
flags |= 1
r = b""
r += struct.pack("<i", self.nVersion)
if flags:
dummy = []
r += ser_vector(dummy)
r += struct.pack("<B", flags)
r += ser_vector(self.vin)
r += ser_vector(self.vout)
if flags & 1:
if (len(self.wit.vtxinwit) != len(self.vin)):
# vtxinwit must have the same length as vin
self.wit.vtxinwit = self.wit.vtxinwit[:len(self.vin)]
for i in range(len(self.wit.vtxinwit), len(self.vin)):
self.wit.vtxinwit.append(CTxinWitness())
r += self.wit.serialize()
r += struct.pack("<I", self.nLockTime)
return r
# Regular serialization is without witness -- must explicitly
# call serialize_with_witness to include witness data.
def serialize(self):
return self.serialize_without_witness()
# Recalculate the txid (transaction hash without witness)
def rehash(self):
self.sha256 = None
self.calc_sha256()
def calc_sha256(self):
# We will only cache the serialization without witness in
# self.sha256 and self.hash -- those are expected to be the txid.
def calc_sha256(self, with_witness=False):
if with_witness:
# Don't cache the result, just return it
return uint256_from_str(hash256(self.serialize_with_witness()))
if self.sha256 is None:
self.sha256 = uint256_from_str(hash256(self.serialize()))
self.sha256 = uint256_from_str(hash256(self.serialize_without_witness()))
self.hash = encode(hash256(self.serialize())[::-1], 'hex_codec').decode('ascii')
def is_valid(self):
@ -518,17 +644,17 @@ class CBlock(CBlockHeader): @@ -518,17 +644,17 @@ class CBlock(CBlockHeader):
super(CBlock, self).deserialize(f)
self.vtx = deser_vector(f, CTransaction)
def serialize(self):
def serialize(self, with_witness=False):
r = b""
r += super(CBlock, self).serialize()
r += ser_vector(self.vtx)
if with_witness:
r += ser_vector(self.vtx, "serialize_with_witness")
else:
r += ser_vector(self.vtx)
return r
def calc_merkle_root(self):
hashes = []
for tx in self.vtx:
tx.calc_sha256()
hashes.append(ser_uint256(tx.sha256))
# Calculate the merkle root given a vector of transaction hashes
def get_merkle_root(self, hashes):
while len(hashes) > 1:
newhashes = []
for i in range(0, len(hashes), 2):
@ -537,6 +663,24 @@ class CBlock(CBlockHeader): @@ -537,6 +663,24 @@ class CBlock(CBlockHeader):
hashes = newhashes
return uint256_from_str(hashes[0])
def calc_merkle_root(self):
hashes = []
for tx in self.vtx:
tx.calc_sha256()
hashes.append(ser_uint256(tx.sha256))
return self.get_merkle_root(hashes)
def calc_witness_merkle_root(self):
# For witness root purposes, the hash of the
# coinbase, with witness, is defined to be 0...0
hashes = [ser_uint256(0)]
for tx in self.vtx[1:]:
# Calculate the hashes with witness data
hashes.append(ser_uint256(tx.calc_sha256(True)))
return self.get_merkle_root(hashes)
def is_valid(self):
self.calc_sha256()
target = uint256_from_compact(self.nBits)
@ -812,11 +956,16 @@ class msg_tx(object): @@ -812,11 +956,16 @@ class msg_tx(object):
self.tx.deserialize(f)
def serialize(self):
return self.tx.serialize()
return self.tx.serialize_without_witness()
def __repr__(self):
return "msg_tx(tx=%s)" % (repr(self.tx))
class msg_witness_tx(msg_tx):
def serialize(self):
return self.tx.serialize_with_witness()
class msg_block(object):
command = b"block"
@ -849,6 +998,12 @@ class msg_generic(object): @@ -849,6 +998,12 @@ class msg_generic(object):
def __repr__(self):
return "msg_generic()"
class msg_witness_block(msg_block):
def serialize(self):
r = self.block.serialize(with_witness=True)
return r
class msg_getaddr(object):
command = b"getaddr"
@ -947,6 +1102,7 @@ class msg_sendheaders(object): @@ -947,6 +1102,7 @@ class msg_sendheaders(object):
def __repr__(self):
return "msg_sendheaders()"
# getheaders message has
# number of entries
# vector of hashes
@ -1068,6 +1224,8 @@ class NodeConnCB(object): @@ -1068,6 +1224,8 @@ class NodeConnCB(object):
# tests; it causes message delivery to sleep for the specified time
# before acquiring the global lock and delivering the next message.
self.deliver_sleep_time = None
# Remember the services our peer has advertised
self.peer_services = None
def set_deliver_sleep_time(self, value):
with mininode_lock:
@ -1105,6 +1263,7 @@ class NodeConnCB(object): @@ -1105,6 +1263,7 @@ class NodeConnCB(object):
conn.ver_send = min(MY_VERSION, message.nVersion)
if message.nVersion < 209:
conn.ver_recv = conn.ver_send
conn.nServices = message.nServices
def on_verack(self, conn, message):
conn.ver_recv = conn.ver_send
@ -1135,6 +1294,7 @@ class NodeConnCB(object): @@ -1135,6 +1294,7 @@ class NodeConnCB(object):
def on_mempool(self, conn): pass
def on_pong(self, conn, message): pass
def on_feefilter(self, conn, message): pass
def on_sendheaders(self, conn, message): pass
# More useful callbacks and functions for NodeConnCB's which have a single NodeConn
class SingleNodeConnCB(NodeConnCB):
@ -1183,15 +1343,16 @@ class NodeConn(asyncore.dispatcher): @@ -1183,15 +1343,16 @@ class NodeConn(asyncore.dispatcher):
b"getheaders": msg_getheaders,
b"reject": msg_reject,
b"mempool": msg_mempool,
b"feefilter": msg_feefilter
b"feefilter": msg_feefilter,
b"sendheaders": msg_sendheaders
}
MAGIC_BYTES = {
"mainnet": b"\xf9\xbe\xb4\xd9", # mainnet
"testnet3": b"\x0b\x11\x09\x07", # testnet3
"regtest": b"\xfa\xbf\xb5\xda" # regtest
"regtest": b"\xfa\xbf\xb5\xda", # regtest
}
def __init__(self, dstaddr, dstport, rpc, callback, net="regtest", services=1):
def __init__(self, dstaddr, dstport, rpc, callback, net="regtest", services=NODE_NETWORK):
asyncore.dispatcher.__init__(self, map=mininode_socket_map)
self.log = logging.getLogger("NodeConn(%s:%d)" % (dstaddr, dstport))
self.dstaddr = dstaddr
@ -1206,6 +1367,7 @@ class NodeConn(asyncore.dispatcher): @@ -1206,6 +1367,7 @@ class NodeConn(asyncore.dispatcher):
self.network = net
self.cb = callback
self.disconnect = False
self.nServices = 0
# stuff version msg into sendbuf
vt = msg_version()

52
qa/rpc-tests/test_framework/script.py

@ -15,8 +15,9 @@ Functionality to build scripts, as well as SignatureHash(). @@ -15,8 +15,9 @@ Functionality to build scripts, as well as SignatureHash().
"""
from .mininode import CTransaction, CTxOut, hash256
from .mininode import CTransaction, CTxOut, sha256, hash256, uint256_from_str, ser_uint256, ser_string
from binascii import hexlify
import hashlib
import sys
bchr = chr
@ -36,6 +37,10 @@ MAX_SCRIPT_OPCODES = 201 @@ -36,6 +37,10 @@ MAX_SCRIPT_OPCODES = 201
OPCODE_NAMES = {}
def hash160(s):
return hashlib.new('ripemd160', sha256(s)).digest()
_opcode_instances = []
class CScriptOp(int):
"""A single script opcode"""
@ -895,3 +900,48 @@ def SignatureHash(script, txTo, inIdx, hashtype): @@ -895,3 +900,48 @@ def SignatureHash(script, txTo, inIdx, hashtype):
hash = hash256(s)
return (hash, None)
# TODO: Allow cached hashPrevouts/hashSequence/hashOutputs to be provided.
# Performance optimization probably not necessary for python tests, however.
# Note that this corresponds to sigversion == 1 in EvalScript, which is used
# for version 0 witnesses.
def SegwitVersion1SignatureHash(script, txTo, inIdx, hashtype, amount):
hashPrevouts = 0
hashSequence = 0
hashOutputs = 0
if not (hashtype & SIGHASH_ANYONECANPAY):
serialize_prevouts = bytes()
for i in txTo.vin:
serialize_prevouts += i.prevout.serialize()
hashPrevouts = uint256_from_str(hash256(serialize_prevouts))
if (not (hashtype & SIGHASH_ANYONECANPAY) and (hashtype & 0x1f) != SIGHASH_SINGLE and (hashtype & 0x1f) != SIGHASH_NONE):
serialize_sequence = bytes()
for i in txTo.vin:
serialize_sequence += struct.pack("<I", i.nSequence)
hashSequence = uint256_from_str(hash256(serialize_sequence))
if ((hashtype & 0x1f) != SIGHASH_SINGLE and (hashtype & 0x1f) != SIGHASH_NONE):
serialize_outputs = bytes()
for o in txTo.vout:
serialize_outputs += o.serialize()
hashOutputs = uint256_from_str(hash256(serialize_outputs))
elif ((hashtype & 0x1f) == SIGHASH_SINGLE and inIdx < len(txTo.vout)):
serialize_outputs = txTo.vout[inIdx].serialize()
hashOutputs = uint256_from_str(hash256(serialize_outputs))
ss = bytes()
ss += struct.pack("<i", txTo.nVersion)
ss += ser_uint256(hashPrevouts)
ss += ser_uint256(hashSequence)
ss += txTo.vin[inIdx].prevout.serialize()
ss += ser_string(script)
ss += struct.pack("<q", amount)
ss += struct.pack("<I", txTo.vin[inIdx].nSequence)
ss += ser_uint256(hashOutputs)
ss += struct.pack("<i", txTo.nLockTime)
ss += struct.pack("<I", hashtype)
return hash256(ss)

84
src/test/data/script_tests.json

@ -1966,6 +1966,90 @@ @@ -1966,6 +1966,90 @@
"OK",
"Basic P2SH(P2WPKH) with the wrong key but no WITNESS"
],
[
[
"304402205ae57ae0534c05ca9981c8a6cdf353b505eaacb7375f96681a2d1a4ba6f02f84022056248e68643b7d8ce7c7d128c9f1f348bcab8be15d094ad5cadd24251a28df8001",
"0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8"
],
"",
"1 0x14 0x91b24bf9f5288532960ac687abb035127b1d28a5",
"DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM,P2SH,WITNESS",
"DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM",
"P2WPKH with future witness version"
],
[
[
"3044022064100ca0e2a33332136775a86cd83d0230e58b9aebb889c5ac952abff79a46ef02205f1bf900e022039ad3091bdaf27ac2aef3eae9ed9f190d821d3e508405b9513101",
"0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8"
],
"",
"0 0x1f 0xb34b78da162751647974d5cb7410aa428ad339dbf7d1e16e833f68a0cbf1c3",
"P2SH,WITNESS",
"WITNESS_PROGRAM_WRONG_LENGTH",
"P2WPKH with wrong witness program length"
],
[
"",
"0 0x20 0xb95237b48faaa69eb078e1170be3b5cbb3fddf16d0a991e14ad274f7b33a4f64",
"P2SH,WITNESS",
"WITNESS_PROGRAM_WITNESS_EMPTY",
"P2WSH with empty witness"
],
[
[
"3044022039105b995a5f448639a997a5c90fda06f50b49df30c3bdb6663217bf79323db002206fecd54269dec569fcc517178880eb58bb40f381a282bb75766ff3637d5f4b4301",
"400479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ac"
],
"",
"0 0x20 0xb95237b48faaa69eb078e1170be3b5cbb3fddf16d0a991e14ad274f7b33a4f64",
"P2SH,WITNESS",
"WITNESS_PROGRAM_MISMATCH",
"P2WSH with witness program mismatch"
],
[
[
"304402201a96950593cb0af32d080b0f193517f4559241a8ebd1e95e414533ad64a3f423022047f4f6d3095c23235bdff3aeff480d0529c027a3f093cb265b7cbf148553b85101",
"0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8",
""
],
"",
"0 0x14 0x91b24bf9f5288532960ac687abb035127b1d28a5",
"P2SH,WITNESS",
"WITNESS_PROGRAM_MISMATCH",
"P2WPKH with witness program mismatch"
],
[
[
"304402201a96950593cb0af32d080b0f193517f4559241a8ebd1e95e414533ad64a3f423022047f4f6d3095c23235bdff3aeff480d0529c027a3f093cb265b7cbf148553b85101",
"0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8"
],
"11",
"0 0x14 0x91b24bf9f5288532960ac687abb035127b1d28a5",
"P2SH,WITNESS",
"WITNESS_MALLEATED",
"P2WPKH with non-empty scriptSig"
],
[
[
"304402204209e49457c2358f80d0256bc24535b8754c14d08840fc4be762d6f5a0aed80b02202eaf7d8fc8d62f60c67adcd99295528d0e491ae93c195cec5a67e7a09532a88001",
"048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf"
],
"11 0x16 0x00147cf9c846cd4882efec4bf07e44ebdad495c94f4b",
"HASH160 0x14 0x4e0c2aed91315303fc6a1dc4c7bc21c88f75402e EQUAL",
"P2SH,WITNESS",
"WITNESS_MALLEATED_P2SH",
"P2SH(P2WPKH) with superfluous push in scriptSig"
],
[
[
""
],
"0x47 0x304402200a5c6163f07b8d3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa102201fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b742001",
"0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG",
"P2SH,WITNESS",
"WITNESS_UNEXPECTED",
"P2PK with witness"
],
["CHECKSEQUENCEVERIFY tests"],
["", "NOP3", "CHECKSEQUENCEVERIFY", "INVALID_STACK_OPERATION", "CSV automatically fails on a empty stack"],

47
src/test/script_tests.cpp

@ -293,19 +293,19 @@ private: @@ -293,19 +293,19 @@ private:
}
public:
TestBuilder(const CScript& script_, const std::string& comment_, int flags_, bool P2SH = false, WitnessMode wm = WITNESS_NONE) : script(script_), havePush(false), comment(comment_), flags(flags_), scriptError(SCRIPT_ERR_OK)
TestBuilder(const CScript& script_, const std::string& comment_, int flags_, bool P2SH = false, WitnessMode wm = WITNESS_NONE, int witnessversion = 0) : script(script_), havePush(false), comment(comment_), flags(flags_), scriptError(SCRIPT_ERR_OK)
{
CScript scriptPubKey = script;
if (wm == WITNESS_PKH) {
uint160 hash;
CHash160().Write(&script[1], script.size() - 1).Finalize(hash.begin());
script = CScript() << OP_DUP << OP_HASH160 << ToByteVector(hash) << OP_EQUALVERIFY << OP_CHECKSIG;
scriptPubKey = CScript() << OP_0 << ToByteVector(hash);
scriptPubKey = CScript() << witnessversion << ToByteVector(hash);
} else if (wm == WITNESS_SH) {
witscript = scriptPubKey;
uint256 hash;
CSHA256().Write(&witscript[0], witscript.size()).Finalize(hash.begin());
scriptPubKey = CScript() << OP_0 << ToByteVector(hash);
scriptPubKey = CScript() << witnessversion << ToByteVector(hash);
}
if (P2SH) {
redeemscript = scriptPubKey;
@ -341,6 +341,11 @@ public: @@ -341,6 +341,11 @@ public:
return *this;
}
TestBuilder& Push(const CScript& script) {
DoPush(std::vector<unsigned char>(script.begin(), script.end()));
return *this;
}
TestBuilder& PushSig(const CKey& key, int nHashType = SIGHASH_ALL, unsigned int lenR = 32, unsigned int lenS = 32, SigVersion sigversion = SIGVERSION_BASE)
{
uint256 hash = SignatureHash(script, spendTx, 0, nHashType, 0, sigversion);
@ -765,6 +770,42 @@ BOOST_AUTO_TEST_CASE(script_build) @@ -765,6 +770,42 @@ BOOST_AUTO_TEST_CASE(script_build)
"Basic P2SH(P2WPKH) with the wrong key but no WITNESS", SCRIPT_VERIFY_P2SH, true, WITNESS_PKH
).PushWitSig(keys.key0).Push(keys.pubkey1).AsWit().PushRedeem());
tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0),
"P2WPKH with future witness version", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH |
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM, false, WITNESS_PKH, 1
).PushWitSig(keys.key0).Push(keys.pubkey0).AsWit().ScriptError(SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM));
{
CScript witscript = CScript() << ToByteVector(keys.pubkey0);
uint256 hash;
CSHA256().Write(&witscript[0], witscript.size()).Finalize(hash.begin());
vector<unsigned char> hashBytes = ToByteVector(hash);
hashBytes.pop_back();
tests.push_back(TestBuilder(CScript() << OP_0 << hashBytes,
"P2WPKH with wrong witness program length", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false
).PushWitSig(keys.key0).Push(keys.pubkey0).AsWit().ScriptError(SCRIPT_ERR_WITNESS_PROGRAM_WRONG_LENGTH));
}
tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG,
"P2WSH with empty witness", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false, WITNESS_SH
).ScriptError(SCRIPT_ERR_WITNESS_PROGRAM_WITNESS_EMPTY));
{
CScript witscript = CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG;
tests.push_back(TestBuilder(witscript,
"P2WSH with witness program mismatch", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false, WITNESS_SH
).PushWitSig(keys.key0).Push(witscript).DamagePush(0).AsWit().ScriptError(SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH));
}
tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0),
"P2WPKH with witness program mismatch", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false, WITNESS_PKH
).PushWitSig(keys.key0).Push(keys.pubkey0).AsWit().Push("0").AsWit().ScriptError(SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH));
tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0),
"P2WPKH with non-empty scriptSig", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false, WITNESS_PKH
).PushWitSig(keys.key0).Push(keys.pubkey0).AsWit().Num(11).ScriptError(SCRIPT_ERR_WITNESS_MALLEATED));
tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1),
"P2SH(P2WPKH) with superfluous push in scriptSig", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true, WITNESS_PKH
).PushWitSig(keys.key0).Push(keys.pubkey1).AsWit().Num(11).PushRedeem().ScriptError(SCRIPT_ERR_WITNESS_MALLEATED_P2SH));
tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG,
"P2PK with witness", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH
).PushSig(keys.key0).Push("0").AsWit().ScriptError(SCRIPT_ERR_WITNESS_UNEXPECTED));
std::set<std::string> tests_set;
{

Loading…
Cancel
Save