-
Notifications
You must be signed in to change notification settings - Fork 29
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Amended by Pieter Wuille to use multisig 1-of-1 for P2WSH tests, and BIP9 based switchover logic. Fixes and py3 conversion by Marco Falke.
- Loading branch information
Showing
5 changed files
with
222 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,209 @@ | ||
#!/usr/bin/env python3 | ||
# Copyright (c) 2016 The Bitcoin Core developers | ||
# Distributed under the MIT software license, see the accompanying | ||
# file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||
|
||
# | ||
# Test the SegWit changeover logic | ||
# | ||
|
||
from test_framework.test_framework import BitcoinTestFramework | ||
from test_framework.util import * | ||
from test_framework.mininode import sha256, ripemd160 | ||
import os | ||
import shutil | ||
|
||
NODE_0 = 0 | ||
NODE_1 = 1 | ||
NODE_2 = 2 | ||
WIT_V0 = 0 | ||
WIT_V1 = 1 | ||
|
||
def witness_script(version, pubkey): | ||
if (version == 0): | ||
pubkeyhash = bytes_to_hex_str(ripemd160(sha256(hex_str_to_bytes(pubkey)))) | ||
pkscript = "0014" + pubkeyhash | ||
elif (version == 1): | ||
# 1-of-1 multisig | ||
scripthash = bytes_to_hex_str(sha256(hex_str_to_bytes("5121" + pubkey + "51ae"))) | ||
pkscript = "0020" + scripthash | ||
else: | ||
assert("Wrong version" == "0 or 1") | ||
return pkscript | ||
|
||
def addlength(script): | ||
scriptlen = format(len(script)//2, 'x') | ||
assert(len(scriptlen) == 2) | ||
return scriptlen + script | ||
|
||
def create_witnessprogram(version, node, utxo, pubkey, encode_p2sh, amount): | ||
pkscript = witness_script(version, pubkey); | ||
if (encode_p2sh): | ||
p2sh_hash = bytes_to_hex_str(ripemd160(sha256(hex_str_to_bytes(pkscript)))) | ||
pkscript = "a914"+p2sh_hash+"87" | ||
inputs = [] | ||
outputs = {} | ||
inputs.append({ "txid" : utxo["txid"], "vout" : utxo["vout"]} ) | ||
DUMMY_P2SH = "2MySexEGVzZpRgNQ1JdjdP5bRETznm3roQ2" # P2SH of "OP_1 OP_DROP" | ||
outputs[DUMMY_P2SH] = amount | ||
tx_to_witness = node.createrawtransaction(inputs,outputs) | ||
#replace dummy output with our own | ||
tx_to_witness = tx_to_witness[0:110] + addlength(pkscript) + tx_to_witness[-8:] | ||
return tx_to_witness | ||
|
||
def send_to_witness(version, node, utxo, pubkey, encode_p2sh, amount, sign=True, insert_redeem_script=""): | ||
tx_to_witness = create_witnessprogram(version, node, utxo, pubkey, encode_p2sh, amount) | ||
if (sign): | ||
signed = node.signrawtransaction(tx_to_witness) | ||
assert("errors" not in signed or len(["errors"]) == 0) | ||
return node.sendrawtransaction(signed["hex"]) | ||
else: | ||
if (insert_redeem_script): | ||
tx_to_witness = tx_to_witness[0:82] + addlength(insert_redeem_script) + tx_to_witness[84:] | ||
|
||
return node.sendrawtransaction(tx_to_witness) | ||
|
||
def getutxo(txid): | ||
utxo = {} | ||
utxo["vout"] = 0 | ||
utxo["txid"] = txid | ||
return utxo | ||
|
||
class SegWitTest(BitcoinTestFramework): | ||
|
||
def setup_chain(self): | ||
print("Initializing test directory "+self.options.tmpdir) | ||
initialize_chain_clean(self.options.tmpdir, 3) | ||
|
||
def setup_network(self): | ||
self.nodes = [] | ||
self.nodes.append(start_node(0, self.options.tmpdir, ["-logtimemicros", "-debug", "-walletprematurewitness"])) | ||
self.nodes.append(start_node(1, self.options.tmpdir, ["-logtimemicros", "-debug", "-blockversion=4", "-promiscuousmempoolflags=517", "-prematurewitness", "-walletprematurewitness"])) | ||
self.nodes.append(start_node(2, self.options.tmpdir, ["-logtimemicros", "-debug", "-blockversion=536870915", "-promiscuousmempoolflags=517", "-prematurewitness", "-walletprematurewitness"])) | ||
connect_nodes(self.nodes[1], 0) | ||
connect_nodes(self.nodes[2], 1) | ||
connect_nodes(self.nodes[0], 2) | ||
self.is_network_split = False | ||
self.sync_all() | ||
|
||
def success_mine(self, node, txid, sign, redeem_script=""): | ||
send_to_witness(1, node, getutxo(txid), self.pubkey[0], False, Decimal("49.998"), sign, redeem_script) | ||
block = node.generate(1) | ||
assert_equal(len(node.getblock(block[0])["tx"]), 2) | ||
sync_blocks(self.nodes) | ||
|
||
def skip_mine(self, node, txid, sign, redeem_script=""): | ||
send_to_witness(1, node, getutxo(txid), self.pubkey[0], False, Decimal("49.998"), sign, redeem_script) | ||
block = node.generate(1) | ||
assert_equal(len(node.getblock(block[0])["tx"]), 1) | ||
sync_blocks(self.nodes) | ||
|
||
def fail_accept(self, node, txid, sign, redeem_script=""): | ||
try: | ||
send_to_witness(1, node, getutxo(txid), self.pubkey[0], False, Decimal("49.998"), sign, redeem_script) | ||
except JSONRPCException as exp: | ||
assert(exp.error["code"] == -26) | ||
else: | ||
raise AssertionError("Tx should not have been accepted") | ||
|
||
def fail_mine(self, node, txid, sign, redeem_script=""): | ||
send_to_witness(1, node, getutxo(txid), self.pubkey[0], False, Decimal("49.998"), sign, redeem_script) | ||
try: | ||
node.generate(1) | ||
except JSONRPCException as exp: | ||
assert(exp.error["code"] == -1) | ||
else: | ||
raise AssertionError("Created valid block when TestBlockValidity should have failed") | ||
sync_blocks(self.nodes) | ||
|
||
def run_test(self): | ||
self.nodes[0].generate(160) #block 160 | ||
|
||
self.pubkey = [] | ||
p2sh_ids = [] # p2sh_ids[NODE][VER] is an array of txids that spend to a witness version VER pkscript to an address for NODE embedded in p2sh | ||
wit_ids = [] # wit_ids[NODE][VER] is an array of txids that spend to a witness version VER pkscript to an address for NODE via bare witness | ||
for i in range(3): | ||
newaddress = self.nodes[i].getnewaddress() | ||
self.pubkey.append(self.nodes[i].validateaddress(newaddress)["pubkey"]) | ||
multiaddress = self.nodes[i].addmultisigaddress(1, [self.pubkey[-1]]) | ||
self.nodes[i].addwitnessaddress(newaddress) | ||
self.nodes[i].addwitnessaddress(multiaddress) | ||
p2sh_ids.append([]) | ||
wit_ids.append([]) | ||
for v in range(2): | ||
p2sh_ids[i].append([]) | ||
wit_ids[i].append([]) | ||
|
||
for i in range(5): | ||
for n in range(3): | ||
for v in range(2): | ||
wit_ids[n][v].append(send_to_witness(v, self.nodes[0], self.nodes[0].listunspent()[0], self.pubkey[n], False, Decimal("49.999"))) | ||
p2sh_ids[n][v].append(send_to_witness(v, self.nodes[0], self.nodes[0].listunspent()[0], self.pubkey[n], True, Decimal("49.999"))) | ||
|
||
self.nodes[0].generate(1) #block 161 | ||
sync_blocks(self.nodes) | ||
|
||
# Make sure all nodes recognize the transactions as theirs | ||
assert_equal(self.nodes[0].getbalance(), 60*50 - 60*50 + 20*Decimal("49.999") + 50) | ||
assert_equal(self.nodes[1].getbalance(), 20*Decimal("49.999")) | ||
assert_equal(self.nodes[2].getbalance(), 20*Decimal("49.999")) | ||
|
||
self.nodes[0].generate(262) #block 423 | ||
sync_blocks(self.nodes) | ||
|
||
print("Verify default node can't accept any witness format txs before fork") | ||
# unsigned, no scriptsig | ||
self.fail_accept(self.nodes[0], wit_ids[NODE_0][WIT_V0][0], False) | ||
self.fail_accept(self.nodes[0], wit_ids[NODE_0][WIT_V1][0], False) | ||
self.fail_accept(self.nodes[0], p2sh_ids[NODE_0][WIT_V0][0], False) | ||
self.fail_accept(self.nodes[0], p2sh_ids[NODE_0][WIT_V1][0], False) | ||
# unsigned with redeem script | ||
self.fail_accept(self.nodes[0], p2sh_ids[NODE_0][WIT_V0][0], False, addlength(witness_script(0, self.pubkey[0]))) | ||
self.fail_accept(self.nodes[0], p2sh_ids[NODE_0][WIT_V1][0], False, addlength(witness_script(1, self.pubkey[0]))) | ||
# signed | ||
self.fail_accept(self.nodes[0], wit_ids[NODE_0][WIT_V0][0], True) | ||
self.fail_accept(self.nodes[0], wit_ids[NODE_0][WIT_V1][0], True) | ||
self.fail_accept(self.nodes[0], p2sh_ids[NODE_0][WIT_V0][0], True) | ||
self.fail_accept(self.nodes[0], p2sh_ids[NODE_0][WIT_V1][0], True) | ||
|
||
print("Verify witness txs are skipped for mining before the fork") | ||
self.skip_mine(self.nodes[2], wit_ids[NODE_2][WIT_V0][0], True) #block 424 | ||
self.skip_mine(self.nodes[2], wit_ids[NODE_2][WIT_V1][0], True) #block 425 | ||
self.skip_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V0][0], True) #block 426 | ||
self.skip_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V1][0], True) #block 427 | ||
|
||
# TODO: An old node would see these txs without witnesses and be able to mine them | ||
|
||
print("Verify unsigned bare witness txs in versionbits-setting blocks are valid before the fork") | ||
self.success_mine(self.nodes[2], wit_ids[NODE_2][WIT_V0][1], False) #block 428 | ||
self.success_mine(self.nodes[2], wit_ids[NODE_2][WIT_V1][1], False) #block 429 | ||
|
||
print("Verify unsigned p2sh witness txs without a redeem script are invalid") | ||
self.fail_accept(self.nodes[2], p2sh_ids[NODE_2][WIT_V0][1], False) | ||
self.fail_accept(self.nodes[2], p2sh_ids[NODE_2][WIT_V1][1], False) | ||
|
||
print("Verify unsigned p2sh witness txs with a redeem script in versionbits-settings blocks are valid before the fork") | ||
self.success_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V0][1], False, addlength(witness_script(0, self.pubkey[2]))) #block 430 | ||
self.success_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V1][1], False, addlength(witness_script(1, self.pubkey[2]))) #block 431 | ||
|
||
print("Verify previous witness txs skipped for mining can now be mined") | ||
assert_equal(len(self.nodes[2].getrawmempool()), 4) | ||
block = self.nodes[2].generate(1) #block 432 (first block with new rules; 432 = 144 * 3) | ||
sync_blocks(self.nodes) | ||
assert_equal(len(self.nodes[2].getrawmempool()), 0) | ||
assert_equal(len(self.nodes[2].getblock(block[0])["tx"]), 5) | ||
|
||
print("Verify witness txs without witness data are invalid after the fork") | ||
self.fail_mine(self.nodes[2], wit_ids[NODE_2][WIT_V0][2], False) | ||
self.fail_mine(self.nodes[2], wit_ids[NODE_2][WIT_V1][2], False) | ||
self.fail_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V0][2], False, addlength(witness_script(0, self.pubkey[2]))) | ||
self.fail_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V1][2], False, addlength(witness_script(1, self.pubkey[2]))) | ||
|
||
print("Verify default node can now use witness txs") | ||
self.success_mine(self.nodes[0], wit_ids[NODE_0][WIT_V0][0], True) #block 432 | ||
self.success_mine(self.nodes[0], wit_ids[NODE_0][WIT_V1][0], True) #block 433 | ||
self.success_mine(self.nodes[0], p2sh_ids[NODE_0][WIT_V0][0], True) #block 434 | ||
self.success_mine(self.nodes[0], p2sh_ids[NODE_0][WIT_V1][0], True) #block 435 | ||
|
||
if __name__ == '__main__': | ||
SegWitTest().main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters