From ca9b2ca783c3678511b3875059b9cf0dbe85618c Mon Sep 17 00:00:00 2001 From: David Burkett Date: Sat, 29 Jan 2022 22:23:05 -0500 Subject: [PATCH] MWEB: Functional tests --- test/functional/feature_bip68_sequence.py | 6 +- test/functional/feature_cltv.py | 1 + test/functional/feature_dersig.py | 1 + test/functional/feature_maxuploadtarget.py | 6 +- test/functional/feature_nulldummy.py | 1 + test/functional/feature_segwit.py | 3 + test/functional/mweb_basic.py | 109 ++++++++++++++++++++ test/functional/mweb_pegout_all.py | 39 +++++++ test/functional/mweb_reorg.py | 65 ++++++++++++ test/functional/mweb_weight.py | 80 ++++++++++++++ test/functional/p2p_blockfilters.py | 4 +- test/functional/p2p_compactblocks.py | 1 + test/functional/p2p_node_network_limited.py | 8 +- test/functional/p2p_segwit.py | 11 +- test/functional/rpc_blockchain.py | 9 +- test/functional/rpc_fundrawtransaction.py | 8 +- test/functional/rpc_signrawtransaction.py | 1 + test/functional/test_framework/ltc_util.py | 20 +++- test/functional/test_framework/messages.py | 1 + test/functional/test_runner.py | 6 +- test/functional/tool_wallet.py | 4 +- test/functional/wallet_dump.py | 29 ++++-- test/functional/wallet_keypool.py | 10 +- 23 files changed, 389 insertions(+), 34 deletions(-) create mode 100644 test/functional/mweb_basic.py create mode 100644 test/functional/mweb_pegout_all.py create mode 100644 test/functional/mweb_reorg.py create mode 100644 test/functional/mweb_weight.py diff --git a/test/functional/feature_bip68_sequence.py b/test/functional/feature_bip68_sequence.py index 601aa058082eb..739900b26e7dc 100755 --- a/test/functional/feature_bip68_sequence.py +++ b/test/functional/feature_bip68_sequence.py @@ -33,8 +33,12 @@ def set_test_params(self): [ "-acceptnonstdtxn=1", "-peertimeout=9999", # bump because mocktime might cause a disconnect otherwise + "-vbparams=mweb:-2:0", + ], + [ + "-acceptnonstdtxn=0", + "-vbparams=mweb:-2:0", ], - ["-acceptnonstdtxn=0"], ] def skip_test_if_missing_module(self): diff --git a/test/functional/feature_cltv.py b/test/functional/feature_cltv.py index 45566b225d8d4..07ee6e61e28fc 100755 --- a/test/functional/feature_cltv.py +++ b/test/functional/feature_cltv.py @@ -58,6 +58,7 @@ def set_test_params(self): '-whitelist=noban@127.0.0.1', '-par=1', # Use only one script thread to get the exact reject reason for testing '-acceptnonstdtxn=1', # cltv_invalidate is nonstandard + '-vbparams=mweb:-2:0', ]] self.setup_clean_chain = True self.rpc_timeout = 480 diff --git a/test/functional/feature_dersig.py b/test/functional/feature_dersig.py index 3287a475bbdd2..fe46699c5c805 100755 --- a/test/functional/feature_dersig.py +++ b/test/functional/feature_dersig.py @@ -43,6 +43,7 @@ def set_test_params(self): self.extra_args = [[ '-whitelist=noban@127.0.0.1', '-par=1', # Use only one script thread to get the exact log msg for testing + '-vbparams=mweb:-2:0', ]] self.setup_clean_chain = True self.rpc_timeout = 240 diff --git a/test/functional/feature_maxuploadtarget.py b/test/functional/feature_maxuploadtarget.py index d0a94658ff2a7..2ec7ae256780c 100755 --- a/test/functional/feature_maxuploadtarget.py +++ b/test/functional/feature_maxuploadtarget.py @@ -36,7 +36,7 @@ def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 self.extra_args = [[ - "-maxuploadtarget=800", + "-maxuploadtarget=3200", "-acceptnonstdtxn=1", "-peertimeout=9999", # bump because mocktime might cause a disconnect otherwise ]] @@ -90,8 +90,8 @@ def run_test(self): getdata_request = msg_getdata() getdata_request.inv.append(CInv(MSG_BLOCK, big_old_block)) - max_bytes_per_day = 800*1024*1024 - daily_buffer = 144 * 4000000 + max_bytes_per_day = 3200*1024*1024 + daily_buffer = 144 * 4000000 * 4 # MWEB uses a buffer 4x the max serialized segwit block max_bytes_available = max_bytes_per_day - daily_buffer success_count = max_bytes_available // old_block_size diff --git a/test/functional/feature_nulldummy.py b/test/functional/feature_nulldummy.py index d20b714ce357c..151d9298edced 100755 --- a/test/functional/feature_nulldummy.py +++ b/test/functional/feature_nulldummy.py @@ -46,6 +46,7 @@ def set_test_params(self): self.extra_args = [[ '-segwitheight=432', '-addresstype=legacy', + '-vbparams=mweb:-2:0', ]] * 2 def skip_test_if_missing_module(self): diff --git a/test/functional/feature_segwit.py b/test/functional/feature_segwit.py index 7bd2fc7847ce4..52fbf8f905235 100755 --- a/test/functional/feature_segwit.py +++ b/test/functional/feature_segwit.py @@ -57,17 +57,20 @@ def set_test_params(self): "-rpcserialversion=0", "-segwitheight=432", "-addresstype=legacy", + "-vbparams=mweb:-2:0", ], [ "-acceptnonstdtxn=1", "-rpcserialversion=1", "-segwitheight=432", "-addresstype=legacy", + "-vbparams=mweb:-2:0", ], [ "-acceptnonstdtxn=1", "-segwitheight=432", "-addresstype=legacy", + "-vbparams=mweb:-2:0", ], ] self.rpc_timeout = 120 diff --git a/test/functional/mweb_basic.py b/test/functional/mweb_basic.py new file mode 100644 index 0000000000000..7d19d625067aa --- /dev/null +++ b/test/functional/mweb_basic.py @@ -0,0 +1,109 @@ +#!/usr/bin/env python3 +# Copyright (c) 2021 The Litecoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""Basic MWEB test""" + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import assert_equal + +class MWEBBasicTest(BitcoinTestFramework): + def set_test_params(self): + self.setup_clean_chain = True + self.num_nodes = 2 + + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + + def run_test(self): + self.log.info("Create all pre-MWEB blocks") + self.nodes[0].generate(431) + + self.log.info("Pegin some coins") + addr0 = self.nodes[0].getnewaddress(address_type='mweb') + self.nodes[0].sendtoaddress(addr0, 10) + + self.log.info("Create some blocks - activate MWEB") + self.nodes[0].generate(10) + self.sync_all() + + self.log.info("Check for MWEB UTXOs") + utxos = [x for x in self.nodes[0].listunspent() if x['address'].startswith('tmweb')] + assert_equal(len(utxos), 2) + utxos.sort(key=lambda x: x['amount']) + + utxo0 = utxos[0] + utxo1 = utxos[1] + if utxos[0]['address'] != addr0: + utxo0 = utxos[1] + utxo1 = utxos[0] + + assert utxo0['amount'] == 10 and utxo0['address'] == addr0 + assert 2 < utxo1['amount'] < 2.5 # change from single 12.5 LTC coinbase being spent + + self.log.info("Send MWEB coins to node 1") + addr1 = self.nodes[1].getnewaddress(address_type='mweb') + tx1_hash = self.nodes[0].sendtoaddress(addr1, 5) + tx1 = self.nodes[0].getmempoolentry(tx1_hash) + self.log.info("tx1: {}".format(tx1)) + self.nodes[0].generate(1) + self.sync_all() + + self.log.info("Check MWEB coins are spent on node 0") + utxos = [x for x in self.nodes[0].listunspent() if x['address'].startswith('tmweb')] + assert_equal(len(utxos), 2) + assert sum(x['amount'] for x in utxos) < 45 + + self.log.info("Check for MWEB UTXO on node 1") + utxos = [x for x in self.nodes[1].listunspent() if x['address'].startswith('tmweb')] + assert_equal(len(utxos), 1) + assert utxos[0]['amount'] == 5 and utxos[0]['address'] == addr1 + + self.log.info("Send MWEB coins to node 0") + self.nodes[1].sendtoaddress(addr0, 2) + self.sync_all() + self.nodes[0].generate(1) + self.sync_all() + + self.log.info("Check MWEB coins are spent on node 1") + utxos = [x for x in self.nodes[1].listunspent() if x['address'].startswith('tmweb')] + assert_equal(len(utxos), 1) + assert sum(x['amount'] for x in utxos) < 3 + self.log.info("UTXO amount: {}".format(utxos[0]['amount'])) + + self.log.info("Check for MWEB UTXO on node 0") + utxos = self.nodes[0].listunspent(addresses=[addr0]) + assert_equal(len(utxos), 1) + assert utxos[0]['amount'] == 2 and utxos[0]['address'] == addr0 + + self.log.info("Pegout coins on node 1") + addr2 = self.nodes[1].getnewaddress() + self.nodes[1].sendtoaddress(addr2, 2) + self.sync_all() + self.nodes[1].generate(1) + self.sync_all() + + self.log.info("Check MWEB coins are spent on node 1") + utxos = [x for x in self.nodes[1].listunspent() if x['address'].startswith('tmweb')] + assert_equal(len(utxos), 1) + assert sum(x['amount'] for x in utxos) < 1 + + self.log.info("Mine 5 blocks. Peg-out maturity is 6 blocks, so coins shouldn't be available yet.") + self.nodes[1].generate(5) + self.sync_all() + + self.log.info("Check for UTXO on node 1") + utxos = self.nodes[1].listunspent(addresses=[addr2]) + assert_equal(len(utxos), 0) + + self.log.info("Mine 1 more block. Peg-out coins should mature.") + self.nodes[1].generate(1) + self.sync_all() + + self.log.info("Check for UTXO on node 1") + utxos = self.nodes[1].listunspent(addresses=[addr2]) + assert_equal(len(utxos), 1) + assert utxos[0]['amount'] == 2 and utxos[0]['address'] == addr2 + +if __name__ == '__main__': + MWEBBasicTest().main() diff --git a/test/functional/mweb_pegout_all.py b/test/functional/mweb_pegout_all.py new file mode 100644 index 0000000000000..5fe3bd330b098 --- /dev/null +++ b/test/functional/mweb_pegout_all.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 +# Copyright (c) 2021 The Litecoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""Verify that we can pegout all coins in the MWEB""" + +from decimal import Decimal +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import assert_equal +from test_framework.ltc_util import get_hog_addr_txout, setup_mweb_chain + +class MWEBPegoutAllTest(BitcoinTestFramework): + def set_test_params(self): + self.setup_clean_chain = True + self.num_nodes = 1 + + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + + def run_test(self): + self.log.info("Setup MWEB chain") + setup_mweb_chain(self.nodes[0]) + + total_balance = self.nodes[0].getbalance() + pegout_txid = self.nodes[0].sendtoaddress(address=self.nodes[0].getnewaddress(), amount=total_balance, subtractfeefromamount=True) + pegout_tx = self.nodes[0].gettransaction(txid=pegout_txid, verbose=True) + assert_equal(len(self.nodes[0].getrawmempool()), 1) + self.nodes[0].generate(1) + assert_equal(len(self.nodes[0].getrawmempool()), 0) + + self.log.info("Check that pegged in amount is 0") + hog_addr_txout = get_hog_addr_txout(self.nodes[0]) + assert_equal(hog_addr_txout.nValue, 0.0) + + self.log.info("Ensure we can mine the next block") + self.nodes[0].generate(1) + +if __name__ == '__main__': + MWEBPegoutAllTest().main() diff --git a/test/functional/mweb_reorg.py b/test/functional/mweb_reorg.py new file mode 100644 index 0000000000000..7760982acbc00 --- /dev/null +++ b/test/functional/mweb_reorg.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python3 +# Copyright (c) 2014-2020 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 mempool re-org scenarios for MWEB transactions + +Test re-org scenarios with a mempool that contains transactions +that create or spend (directly or indirectly) MWEB outputs. +""" + +import json + +from test_framework.blocktools import create_raw_transaction +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import assert_equal, assert_raises_rpc_error +from test_framework.ltc_util import setup_mweb_chain + +class MWEBReorgTest(BitcoinTestFramework): + def set_test_params(self): + self.setup_clean_chain = True + self.num_nodes = 2 + self.extra_args = [ + [ + '-whitelist=noban@127.0.0.1', # immediate tx relay + ], + [] + ] + + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + + def run_test(self): + self.basic_reorg_test() + + def basic_reorg_test(self): + self.log.info("Create all pre-MWEB blocks") + setup_mweb_chain(self.nodes[0]) + + self.log.info("Pegin some coins in pegin_tx1. pegin_tx1 should be in the mempool") + node0_mweb_addr = self.nodes[0].getnewaddress(address_type='mweb') + pegin_tx1_id = self.nodes[0].sendtoaddress(node0_mweb_addr, 100) + self.sync_all() + + assert_equal(set(self.nodes[1].getrawmempool()), {pegin_tx1_id}) + + self.log.info("Mine pegin_tx1 in block0a, and mine a few blocks on top. mempool should be empty") + block0a = self.nodes[0].generate(4)[0] + self.sync_all() + + assert_equal(len(self.nodes[1].getrawmempool()), 0) + + self.log.info("Invalidate block0a. pegin_tx1 should be back in the mempool") + self.nodes[1].invalidateblock(block0a) + assert_equal(set(self.nodes[1].getrawmempool()), {pegin_tx1_id}) + + self.log.info("Generate block0b. pegin_tx1 should be included in the block") + block0b_hash = self.nodes[1].generate(1)[0] + + block0b_txs = self.nodes[1].getblock(block0b_hash, 2)['tx'] + assert_equal(len(block0b_txs), 3) + assert_equal(block0b_txs[1]['txid'], pegin_tx1_id) + + +if __name__ == '__main__': + MWEBReorgTest().main() diff --git a/test/functional/mweb_weight.py b/test/functional/mweb_weight.py new file mode 100644 index 0000000000000..4665a864f5aaa --- /dev/null +++ b/test/functional/mweb_weight.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python3 +# Copyright (c) 2021 The Litecoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""MWEB block weight test""" + +from decimal import Decimal + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import assert_equal + +class MWEBWeightTest(BitcoinTestFramework): + def set_test_params(self): + self.setup_clean_chain = True + self.rpc_timeout = 120 + self.num_nodes = 3 + self.extra_args = [["-spendzeroconfchange=0"]] * self.num_nodes + + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + + def run_test(self): + self.log.info("Create some blocks") + self.nodes[0].generate(101) + + self.log.info("Pegin some coins - activate MWEB") + addr = self.nodes[0].getnewaddress(address_type='mweb') + self.nodes[0].sendtoaddress(addr, 1) + self.sync_all() + self.nodes[1].generate(700) + self.sync_all() + + # Workaround for syncing issue + self.nodes[2].generate(1) + self.sync_all() + + self.nodes[2].generate(700) + self.sync_all() + + # Max number of MWEB transactions in a block (21000/39) + tx_limit = 538 + + self.log.info("Create transactions up to the max block weight") + addr = self.nodes[0].getnewaddress(address_type='mweb') + for x in range(0, tx_limit): + self.nodes[1].sendtoaddress(addr, 1) + assert_equal(len(self.nodes[1].getrawmempool()), tx_limit) + + self.log.info("Create a block") + self.nodes[1].generate(1) + self.sync_all() + + self.log.info("Check mempool is empty") + assert_equal(len(self.nodes[1].getrawmempool()), 0) + + self.log.info("Check UTXOs have matured") + utxos = self.nodes[0].listunspent(addresses=[addr]) + assert_equal(len(utxos), tx_limit) + assert all(x['amount'] == 1 and x['spendable'] for x in utxos) + + self.log.info("Create transactions exceeding the max block weight") + addr = self.nodes[0].getnewaddress(address_type='mweb') + for x in range(0, tx_limit + 1): + self.nodes[2].sendtoaddress(addr, 0.01) + assert_equal(len(self.nodes[2].getrawmempool()), tx_limit + 1) + + self.log.info("Create a block") + self.nodes[2].generate(1) + self.sync_all() + + self.log.info("Check mempool is not empty") + assert_equal(len(self.nodes[2].getrawmempool()), 1) + + self.log.info("Check UTXOs have matured") + utxos = self.nodes[0].listunspent(addresses=[addr]) + assert_equal(len(utxos), tx_limit) + assert all(x['amount'] == Decimal('0.01') and x['spendable'] for x in utxos) + +if __name__ == '__main__': + MWEBWeightTest().main() diff --git a/test/functional/p2p_blockfilters.py b/test/functional/p2p_blockfilters.py index 3250cbecf905b..4ac4d6731bec9 100755 --- a/test/functional/p2p_blockfilters.py +++ b/test/functional/p2p_blockfilters.py @@ -45,8 +45,8 @@ def set_test_params(self): self.rpc_timeout = 480 self.num_nodes = 2 self.extra_args = [ - ["-blockfilterindex", "-peerblockfilters"], - ["-blockfilterindex"], + ["-blockfilterindex", "-peerblockfilters", "-vbparams=mweb:-2:0"], + ["-blockfilterindex", "-vbparams=mweb:-2:0"], ] def run_test(self): diff --git a/test/functional/p2p_compactblocks.py b/test/functional/p2p_compactblocks.py index d0b5c948c930b..1fdf110336fbd 100755 --- a/test/functional/p2p_compactblocks.py +++ b/test/functional/p2p_compactblocks.py @@ -99,6 +99,7 @@ def set_test_params(self): self.num_nodes = 1 self.extra_args = [[ "-acceptnonstdtxn=1", + "-vbparams=mweb:-2:0", ]] self.utxos = [] diff --git a/test/functional/p2p_node_network_limited.py b/test/functional/p2p_node_network_limited.py index b1a7ef6877f19..b87e33771501c 100755 --- a/test/functional/p2p_node_network_limited.py +++ b/test/functional/p2p_node_network_limited.py @@ -4,11 +4,11 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Tests NODE_NETWORK_LIMITED. -Tests that a node configured with -prune=550 signals NODE_NETWORK_LIMITED correctly +Tests that a node configured with -prune=2200 signals NODE_NETWORK_LIMITED correctly and that it responds to getdata requests for blocks correctly: - send a block within 288 + 2 of the tip - disconnect peers who request blocks older than that.""" -from test_framework.messages import CInv, MSG_BLOCK, msg_getdata, msg_verack, NODE_NETWORK_LIMITED, NODE_WITNESS +from test_framework.messages import CInv, MSG_BLOCK, msg_getdata, msg_verack, NODE_NETWORK_LIMITED, NODE_WITNESS, NODE_MWEB from test_framework.p2p import P2PInterface from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( @@ -35,7 +35,7 @@ class NodeNetworkLimitedTest(BitcoinTestFramework): def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 3 - self.extra_args = [['-prune=550', '-addrmantest'], [], []] + self.extra_args = [['-prune=2200', '-addrmantest'], [], []] def disconnect_all(self): self.disconnect_nodes(0, 1) @@ -49,7 +49,7 @@ def setup_network(self): def run_test(self): node = self.nodes[0].add_p2p_connection(P2PIgnoreInv()) - expected_services = NODE_WITNESS | NODE_NETWORK_LIMITED + expected_services = NODE_WITNESS | NODE_MWEB | NODE_NETWORK_LIMITED self.log.info("Check that node has signalled expected services.") assert_equal(node.nServices, expected_services) diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py index 447de4a5f2307..027907e41f4fd 100755 --- a/test/functional/p2p_segwit.py +++ b/test/functional/p2p_segwit.py @@ -56,6 +56,7 @@ OP_0, OP_1, OP_2, + OP_8, OP_16, OP_2DROP, OP_CHECKMULTISIG, @@ -220,9 +221,9 @@ def set_test_params(self): self.num_nodes = 3 # This test tests SegWit both pre and post-activation, so use the normal BIP9 activation. self.extra_args = [ - ["-acceptnonstdtxn=1", "-segwitheight={}".format(SEGWIT_HEIGHT), "-whitelist=noban@127.0.0.1", "-mempoolreplacement=1"], - ["-acceptnonstdtxn=0", "-segwitheight={}".format(SEGWIT_HEIGHT), "-mempoolreplacement=1"], - ["-acceptnonstdtxn=1", "-segwitheight=-1", "-mempoolreplacement=1"], + ["-acceptnonstdtxn=1", "-segwitheight={}".format(SEGWIT_HEIGHT), "-whitelist=noban@127.0.0.1", "-mempoolreplacement=1", "-vbparams=mweb:0:0"], + ["-acceptnonstdtxn=0", "-segwitheight={}".format(SEGWIT_HEIGHT), "-mempoolreplacement=1", "-vbparams=mweb:0:0"], + ["-acceptnonstdtxn=1", "-segwitheight=-1", "-mempoolreplacement=1", "-vbparams=mweb:0:0"], ] self.supports_cli = False @@ -1400,6 +1401,10 @@ def test_segwit_versions(self): witness_hash = sha256(witness_program) assert_equal(len(self.nodes[1].getrawmempool()), 0) for version in list(range(OP_1, OP_16 + 1)) + [OP_0]: + # MWEB: We no longer allow version byte of 8 for segwit outputs except for first output (HogAddr) of HogEx txs. + #if version == OP_8: + # continue + # First try to spend to a future version segwit script_pubkey. if version == OP_1: # Don't use 32-byte v1 witness (used by Taproot; see BIP 341) diff --git a/test/functional/rpc_blockchain.py b/test/functional/rpc_blockchain.py index 7e7cc29bf4385..a14399bb0e718 100755 --- a/test/functional/rpc_blockchain.py +++ b/test/functional/rpc_blockchain.py @@ -50,10 +50,11 @@ def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 self.supports_cli = False + self.extra_args=[['-vbparams=mweb:-2:0']] def run_test(self): self.mine_chain() - self.restart_node(0, extra_args=['-stopatheight=207', '-prune=1']) # Set extra args with pruning after rescan is complete + self.restart_node(0, extra_args=['-stopatheight=207', '-prune=1', '-vbparams=mweb:-2:0']) # Set extra args with pruning after rescan is complete self._test_getblockchaininfo() self._test_getchaintxstats() @@ -112,16 +113,16 @@ def _test_getblockchaininfo(self): # should have exact keys assert_equal(sorted(res.keys()), keys) - self.restart_node(0, ['-stopatheight=207', '-prune=550']) + self.restart_node(0, ['-stopatheight=207', '-prune=2200', '-vbparams=mweb:-2:0']) res = self.nodes[0].getblockchaininfo() - # result should have these additional pruning keys if prune=550 + # result should have these additional pruning keys if prune=2200 assert_equal(sorted(res.keys()), sorted(['pruneheight', 'automatic_pruning', 'prune_target_size'] + keys)) # check related fields assert res['pruned'] assert_equal(res['pruneheight'], 0) assert res['automatic_pruning'] - assert_equal(res['prune_target_size'], 576716800) + assert_equal(res['prune_target_size'], 2306867200) assert_greater_than(res['size_on_disk'], 0) assert_equal(res['softforks'], { diff --git a/test/functional/rpc_fundrawtransaction.py b/test/functional/rpc_fundrawtransaction.py index f702635fd788f..0d7b068bb7efc 100755 --- a/test/functional/rpc_fundrawtransaction.py +++ b/test/functional/rpc_fundrawtransaction.py @@ -31,7 +31,7 @@ def set_test_params(self): self.setup_clean_chain = True # This test isn't testing tx relay. Set whitelist on the peers for # instant tx relay. - self.extra_args = [['-whitelist=noban@127.0.0.1']] * self.num_nodes + self.extra_args = [['-whitelist=noban@127.0.0.1', '-vbparams=mweb:-2:0']] * self.num_nodes def skip_test_if_missing_module(self): self.skip_if_no_wallet() @@ -533,6 +533,12 @@ def test_locked_wallet(self): }]) self.nodes[1].walletlock() + # MWEB: We don't update hd seed when encrypting wallet, so new keypool was not generated. + # We need to refill keypool manually. + self.nodes[1].walletpassphrase('test', 10) + self.nodes[1].keypoolrefill(1) + self.nodes[1].walletlock() + # Drain the keypool. self.nodes[1].getnewaddress() self.nodes[1].getrawchangeaddress() diff --git a/test/functional/rpc_signrawtransaction.py b/test/functional/rpc_signrawtransaction.py index 60b4d1c7447c9..f0e23bedcdf2b 100755 --- a/test/functional/rpc_signrawtransaction.py +++ b/test/functional/rpc_signrawtransaction.py @@ -20,6 +20,7 @@ class SignRawTransactionsTest(BitcoinTestFramework): def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 2 + self.extra_args=[['-vbparams=mweb:-2:0'],['-vbparams=mweb:-2:0']] def skip_test_if_missing_module(self): self.skip_if_no_wallet() diff --git a/test/functional/test_framework/ltc_util.py b/test/functional/test_framework/ltc_util.py index 9edfa9564be62..15b90b7b75b48 100644 --- a/test/functional/test_framework/ltc_util.py +++ b/test/functional/test_framework/ltc_util.py @@ -52,4 +52,22 @@ def make_utxo(node, amount, confirmed=True, scriptPubKey=DUMMY_P2WPKH_SCRIPT): assert new_size < mempool_size mempool_size = new_size - return COutPoint(int(txid, 16), 0) \ No newline at end of file + return COutPoint(int(txid, 16), 0) + +def setup_mweb_chain(node): + # Create all pre-MWEB blocks + node.generate(431) + + # Pegin some coins + node.sendtoaddress(node.getnewaddress(address_type='mweb'), 1) + + # Create some blocks - activate MWEB + node.generate(1) + +def get_hog_addr_txout(node): + best_block = node.getblock(node.getbestblockhash(), 2) + + hogex_tx = best_block['tx'][-1] # TODO: Should validate that the tx is marked as a hogex tx + hog_addr = hogex_tx['vout'][0] + + return CTxOut(hog_addr['value'], hog_addr['scriptPubKey']) \ No newline at end of file diff --git a/test/functional/test_framework/messages.py b/test/functional/test_framework/messages.py index c75a1fe2a0296..97ec4242e5369 100755 --- a/test/functional/test_framework/messages.py +++ b/test/functional/test_framework/messages.py @@ -57,6 +57,7 @@ NODE_WITNESS = (1 << 3) NODE_COMPACT_FILTERS = (1 << 6) NODE_NETWORK_LIMITED = (1 << 10) +NODE_MWEB = (1 << 24) MSG_TX = 1 MSG_BLOCK = 2 diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index 9dc2cf002b8c1..850ebbde68cec 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -79,6 +79,7 @@ EXTENDED_SCRIPTS = [ # These tests are not run by default. # Longest test should go first, to favor running tests in parallel + 'mweb_weight.py', 'feature_pruning.py', 'feature_dbcrash.py', ] @@ -244,6 +245,9 @@ 'wallet_scriptaddress2.py', 'feature_dersig.py', 'feature_cltv.py', + 'mweb_basic.py', + 'mweb_reorg.py', + 'mweb_pegout_all.py' 'rpc_uptime.py', 'wallet_resendwallettransactions.py', 'wallet_resendwallettransactions.py --descriptors', @@ -683,7 +687,7 @@ def was_successful(self): def check_script_prefixes(): """Check that test scripts start with one of the allowed name prefixes.""" - good_prefixes_re = re.compile("^(example|feature|interface|mempool|mining|p2p|rpc|wallet|tool|ltc)_") + good_prefixes_re = re.compile("(example|feature|interface|mempool|mining|p2p|rpc|wallet|tool|ltc|mweb)_") bad_script_names = [script for script in ALL_SCRIPTS if good_prefixes_re.match(script) is None] if bad_script_names: diff --git a/test/functional/tool_wallet.py b/test/functional/tool_wallet.py index ddb039500b34e..58b4b1978f7eb 100755 --- a/test/functional/tool_wallet.py +++ b/test/functional/tool_wallet.py @@ -123,7 +123,7 @@ def test_tool_wallet_info(self): HD (hd seed available): yes Keypool Size: 2 Transactions: 0 - Address Book: 3 + Address Book: 4 ''') self.assert_tool_output(out, '-wallet=' + self.default_wallet_name, 'info') timestamp_after = self.wallet_timestamp() @@ -180,7 +180,7 @@ def test_tool_wallet_info_after_transaction(self): HD (hd seed available): yes Keypool Size: 2 Transactions: 1 - Address Book: 3 + Address Book: 4 ''') self.assert_tool_output(out, '-wallet=' + self.default_wallet_name, 'info') shasum_after = self.wallet_shasum() diff --git a/test/functional/wallet_dump.py b/test/functional/wallet_dump.py index 5baaa55e37aff..f607f7036543c 100755 --- a/test/functional/wallet_dump.py +++ b/test/functional/wallet_dump.py @@ -25,6 +25,7 @@ def read_dump(file_name, addrs, script_addrs, hd_master_addr_old): found_p2sh_segwit_addr = 0 found_bech32_addr = 0 found_script_addr = 0 + found_mweb_addr = 0 found_addr_chg = 0 found_addr_rsv = 0 hd_master_addr_ret = None @@ -55,8 +56,9 @@ def read_dump(file_name, addrs, script_addrs, hd_master_addr_old): # ensure the old master is still available assert hd_master_addr_old == addr elif keytype == "hdseed=1": - # ensure we have generated a new hd master key - assert hd_master_addr_old != addr + if hd_master_addr_old != None: + # MWEB: No new seed is generated when encrypting, so assert hd master key is unchanged + assert hd_master_addr_old == addr hd_master_addr_ret = addr elif keytype == "script=1": # scripts don't have keypaths @@ -75,6 +77,8 @@ def read_dump(file_name, addrs, script_addrs, hd_master_addr_old): found_p2sh_segwit_addr += 1 elif addr.startswith('rltc1'): found_bech32_addr += 1 + elif addr.startswith('tmweb'): + found_mweb_addr += 1 break elif keytype == "change=1": found_addr_chg += 1 @@ -89,7 +93,7 @@ def read_dump(file_name, addrs, script_addrs, hd_master_addr_old): found_script_addr += 1 break - return found_comments, found_legacy_addr, found_p2sh_segwit_addr, found_bech32_addr, found_script_addr, found_addr_chg, found_addr_rsv, hd_master_addr_ret + return found_comments, found_legacy_addr, found_p2sh_segwit_addr, found_bech32_addr, found_script_addr, found_mweb_addr, found_addr_chg, found_addr_rsv, hd_master_addr_ret class WalletDumpTest(BitcoinTestFramework): @@ -111,13 +115,14 @@ def run_test(self): wallet_unenc_dump = os.path.join(self.nodes[0].datadir, "wallet.unencrypted.dump") wallet_enc_dump = os.path.join(self.nodes[0].datadir, "wallet.encrypted.dump") - # generate 30 addresses to compare against the dump + # generate 40 addresses to compare against the dump # - 10 legacy P2PKH # - 10 P2SH-segwit # - 10 bech32 + # - 10 mweb test_addr_count = 10 addrs = [] - for address_type in ['legacy', 'p2sh-segwit', 'bech32']: + for address_type in ['legacy', 'p2sh-segwit', 'bech32', 'mweb']: for _ in range(test_addr_count): addr = self.nodes[0].getnewaddress(address_type=address_type) vaddr = self.nodes[0].getaddressinfo(addr) # required to get hd keypath @@ -155,7 +160,7 @@ def run_test(self): result = self.nodes[0].dumpwallet(wallet_unenc_dump) assert_equal(result['filename'], wallet_unenc_dump) - found_comments, found_legacy_addr, found_p2sh_segwit_addr, found_bech32_addr, found_script_addr, found_addr_chg, found_addr_rsv, hd_master_addr_unenc = \ + found_comments, found_legacy_addr, found_p2sh_segwit_addr, found_bech32_addr, found_script_addr, found_mweb_addr, found_addr_chg, found_addr_rsv, hd_master_addr_unenc = \ read_dump(wallet_unenc_dump, addrs, [multisig_addr], None) assert '# End of dump' in found_comments # Check that file is not corrupt assert_equal(dump_time_str, next(c for c in found_comments if c.startswith('# * Created on'))) @@ -165,8 +170,9 @@ def run_test(self): assert_equal(found_p2sh_segwit_addr, test_addr_count) # all keys must be in the dump assert_equal(found_bech32_addr, test_addr_count) # all keys must be in the dump assert_equal(found_script_addr, 1) # all scripts must be in the dump - assert_equal(found_addr_chg, 0) # 0 blocks where mined - assert_equal(found_addr_rsv, 90 * 2) # 90 keys plus 100% internal keys + assert_equal(found_mweb_addr, test_addr_count) + assert_equal(found_addr_chg, 0 + 2) # 0 blocks were mined plus 2 initial MWEB keys (CHANGE and PEG-IN) + assert_equal(found_addr_rsv, 90 * 3) # 90 keys plus 100% internal keys and 100% MWEB keys # encrypt wallet, restart, unlock and dump self.nodes[0].encryptwallet('test') @@ -175,7 +181,7 @@ def run_test(self): self.nodes[0].keypoolrefill() self.nodes[0].dumpwallet(wallet_enc_dump) - found_comments, found_legacy_addr, found_p2sh_segwit_addr, found_bech32_addr, found_script_addr, found_addr_chg, found_addr_rsv, _ = \ + found_comments, found_legacy_addr, found_p2sh_segwit_addr, found_bech32_addr, found_script_addr, found_mweb_addr, found_addr_chg, found_addr_rsv, _ = \ read_dump(wallet_enc_dump, addrs, [multisig_addr], hd_master_addr_unenc) assert '# End of dump' in found_comments # Check that file is not corrupt assert_equal(dump_time_str, next(c for c in found_comments if c.startswith('# * Created on'))) @@ -185,8 +191,9 @@ def run_test(self): assert_equal(found_p2sh_segwit_addr, test_addr_count) # all keys must be in the dump assert_equal(found_bech32_addr, test_addr_count) # all keys must be in the dump assert_equal(found_script_addr, 1) - assert_equal(found_addr_chg, 90 * 2) # old reserve keys are marked as change now - assert_equal(found_addr_rsv, 90 * 2) + assert_equal(found_mweb_addr, test_addr_count) + assert_equal(found_addr_chg, 0 + 2) # 0 blocks were mined plus 2 initial MWEB keys (CHANGE and PEG-IN) + assert_equal(found_addr_rsv, 90 * 3) # Overwriting should fail assert_raises_rpc_error(-8, "already exists", lambda: self.nodes[0].dumpwallet(wallet_enc_dump)) diff --git a/test/functional/wallet_keypool.py b/test/functional/wallet_keypool.py index 51795aca231e2..0785837716178 100755 --- a/test/functional/wallet_keypool.py +++ b/test/functional/wallet_keypool.py @@ -72,11 +72,19 @@ def run_test(self): } ]) nodes[0].walletlock() + + # MWEB: We don't update hd seed when encrypting wallet, so new keypool was not generated. + # We need to refill keypool manually. + self.nodes[0].walletpassphrase('test', 10) + self.nodes[0].keypoolrefill(1) + self.nodes[0].walletlock() + # Keep creating keys addr = nodes[0].getnewaddress() addr_data = nodes[0].getaddressinfo(addr) wallet_info = nodes[0].getwalletinfo() - assert addr_before_encrypting_data['hdmasterfingerprint'] != addr_data['hdmasterfingerprint'] + # MWEB: We don't update hd seed when encrypting wallet, so fingerprint shouldn't change + assert addr_before_encrypting_data['hdmasterfingerprint'] == addr_data['hdmasterfingerprint'] if not self.options.descriptors: assert addr_data['hdseedid'] == wallet_info['hdseedid'] assert_raises_rpc_error(-12, "Error: Keypool ran out, please call keypoolrefill first", nodes[0].getnewaddress)