diff --git a/contrib/devtools/circular-dependencies.py b/contrib/devtools/circular-dependencies.py index 4de4054118f4..e939ec6d45ba 100755 --- a/contrib/devtools/circular-dependencies.py +++ b/contrib/devtools/circular-dependencies.py @@ -5,7 +5,7 @@ import sys import re -from multiprocess import Pool +from multiprocess import Pool # type: ignore[import] from typing import Dict, List, Set MAPPING = { diff --git a/contrib/devtools/optimize-pngs.py b/contrib/devtools/optimize-pngs.py index ad8c65dba911..12de9e784633 100755 --- a/contrib/devtools/optimize-pngs.py +++ b/contrib/devtools/optimize-pngs.py @@ -10,7 +10,8 @@ import sys import subprocess import hashlib -from PIL import Image # pip3 install Pillow +# pip3 install Pillow +from PIL import Image # type: ignore[import] def file_hash(filename): '''Return hash of raw file contents''' diff --git a/doc/design/libraries.md b/doc/design/libraries.md index d3c421a0d319..755efe9ed143 100644 --- a/doc/design/libraries.md +++ b/doc/design/libraries.md @@ -37,7 +37,7 @@ Note: libbitcoin_kernel is a subject to be backported & dashified. ```mermaid -%%{ init : { "flowchart" : { "curve" : "linear" }}}%% +%%{ init : { "flowchart" : { "curve" : "basis" }}}%% graph TD; @@ -53,18 +53,19 @@ dash-qt[dash-qt]-->libbitcoin_wallet; dash-wallet[dash-wallet]-->libbitcoin_wallet; dash-wallet[dash-wallet]-->libbitcoin_wallet_tool; -libbitcoin_cli-->libbitcoin_common; libbitcoin_cli-->libbitcoin_util; +libbitcoin_cli-->libbitcoin_common; -libbitcoin_common-->libbitcoin_util; libbitcoin_common-->libdash_consensus; +libbitcoin_common-->libbitcoin_util; libbitcoin_kernel-->libdash_consensus; libbitcoin_kernel-->libbitcoin_util; -libbitcoin_node-->libbitcoin_common; libbitcoin_node-->libdash_consensus; +libbitcoin_node-->libbitcoin_common; libbitcoin_node-->libbitcoin_kernel; +libbitcoin_node-->libbitcoin_common; libbitcoin_node-->libbitcoin_util; libbitcoinqt-->libbitcoin_common; @@ -73,8 +74,8 @@ libbitcoinqt-->libbitcoin_util; libbitcoin_wallet-->libbitcoin_common; libbitcoin_wallet-->libbitcoin_util; -libbitcoin_wallet_tool-->libbitcoin_util; libbitcoin_wallet_tool-->libbitcoin_wallet; +libbitcoin_wallet_tool-->libbitcoin_util; classDef bold stroke-width:2px, font-weight:bold, font-size: smaller; class dash-qt,dashd,dash-cli,dash-wallet bold diff --git a/src/Makefile.am b/src/Makefile.am index 77b384d144e2..d62df14146fd 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1090,6 +1090,7 @@ dash_tx_LDADD += $(BACKTRACE_LIBS) $(GMP_LIBS) # dash-wallet binary # dash_wallet_SOURCES = bitcoin-wallet.cpp +dash_wallet_SOURCES += init/bitcoin-wallet.cpp dash_wallet_CPPFLAGS = $(bitcoin_bin_cppflags) dash_wallet_CXXFLAGS = $(bitcoin_bin_cxxflags) dash_wallet_LDFLAGS = $(bitcoin_bin_ldflags) diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 488cbb21ff78..2b7a21a5e74e 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -424,15 +424,15 @@ bitcoin_qt_libtoolflags = $(AM_LIBTOOLFLAGS) --tag CXX qt_dash_qt_CPPFLAGS = $(bitcoin_qt_cppflags) qt_dash_qt_CXXFLAGS = $(bitcoin_qt_cxxflags) -qt_dash_qt_SOURCES = $(bitcoin_qt_sources) init/bitcoind.cpp +qt_dash_qt_SOURCES = $(bitcoin_qt_sources) init/bitcoin-qt.cpp qt_dash_qt_LDADD = $(bitcoin_qt_ldadd) qt_dash_qt_LDFLAGS = $(bitcoin_qt_ldflags) qt_dash_qt_LIBTOOLFLAGS = $(bitcoin_qt_libtoolflags) dash_gui_CPPFLAGS = $(bitcoin_qt_cppflags) dash_gui_CXXFLAGS = $(bitcoin_qt_cxxflags) -dash_gui_SOURCES = $(bitcoin_qt_sources) init/bitcoind.cpp -dash_gui_LDADD = $(bitcoin_qt_ldadd) +dash_gui_SOURCES = $(bitcoin_qt_sources) init/bitcoin-gui.cpp +dash_gui_LDADD = $(bitcoin_qt_ldadd) $(LIBBITCOIN_IPC) $(LIBBITCOIN_UTIL) $(LIBMULTIPROCESS_LIBS) dash_gui_LDFLAGS = $(bitcoin_qt_ldflags) dash_gui_LIBTOOLFLAGS = $(bitcoin_qt_libtoolflags) diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include index 83cdbefc1424..62071d40e5a5 100644 --- a/src/Makefile.qttest.include +++ b/src/Makefile.qttest.include @@ -33,7 +33,7 @@ qt_test_test_dash_qt_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BITCOIN_QT_ $(QT_INCLUDES) $(QT_TEST_INCLUDES) $(BOOST_CPPFLAGS) qt_test_test_dash_qt_SOURCES = \ - init/bitcoind.cpp \ + init/bitcoin-qt.cpp \ qt/test/apptests.cpp \ qt/test/optiontests.cpp \ qt/test/rpcnestedtests.cpp \ diff --git a/src/bitcoin-wallet.cpp b/src/bitcoin-wallet.cpp index 7bc14502a3f1..6590188b9f9a 100644 --- a/src/bitcoin-wallet.cpp +++ b/src/bitcoin-wallet.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -100,6 +101,13 @@ MAIN_FUNCTION util::WinCmdLineArgs winArgs; std::tie(argc, argv) = winArgs.get(); #endif + + int exit_status; + std::unique_ptr init = interfaces::MakeWalletInit(argc, argv, exit_status); + if (!init) { + return exit_status; + } + SetupEnvironment(); RandomInit(); try { diff --git a/src/init/bitcoin-gui.cpp b/src/init/bitcoin-gui.cpp new file mode 100644 index 000000000000..7b21a33de5cc --- /dev/null +++ b/src/init/bitcoin-gui.cpp @@ -0,0 +1,52 @@ +// Copyright (c) 2021 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace init { +namespace { +const char* EXE_NAME = "dash-gui"; + +class BitcoinGuiInit : public interfaces::Init +{ +public: + BitcoinGuiInit(const char* arg0) : m_ipc(interfaces::MakeIpc(EXE_NAME, arg0, *this)) + { + m_node.args = &gArgs; + m_node.init = this; + } + std::unique_ptr makeNode() override { return interfaces::MakeNode(m_node); } + std::unique_ptr makeChain() override { return interfaces::MakeChain(m_node); } + std::unique_ptr makeCoinJoinLoader() override + { + return interfaces::MakeCoinJoinLoader(m_node); + } + std::unique_ptr makeWalletLoader(interfaces::Chain& chain, interfaces::CoinJoin::Loader& coinjoin_loader) override + { + return MakeWalletLoader(chain, *Assert(m_node.args), m_node, coinjoin_loader); + } + std::unique_ptr makeEcho() override { return interfaces::MakeEcho(); } + interfaces::Ipc* ipc() override { return m_ipc.get(); } + node::NodeContext m_node; + std::unique_ptr m_ipc; +}; +} // namespace +} // namespace init + +namespace interfaces { +std::unique_ptr MakeGuiInit(int argc, char* argv[]) +{ + return std::make_unique(argc > 0 ? argv[0] : ""); +} +} // namespace interfaces diff --git a/src/init/bitcoin-qt.cpp b/src/init/bitcoin-qt.cpp new file mode 100644 index 000000000000..38716895d110 --- /dev/null +++ b/src/init/bitcoin-qt.cpp @@ -0,0 +1,47 @@ +// Copyright (c) 2021 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace init { +namespace { +class BitcoinQtInit : public interfaces::Init +{ +public: + BitcoinQtInit() + { + m_node.args = &gArgs; + m_node.init = this; + } + std::unique_ptr makeNode() override { return interfaces::MakeNode(m_node); } + std::unique_ptr makeChain() override { return interfaces::MakeChain(m_node); } + std::unique_ptr makeCoinJoinLoader() override + { + return interfaces::MakeCoinJoinLoader(m_node); + } + std::unique_ptr makeWalletLoader(interfaces::Chain& chain, interfaces::CoinJoin::Loader& coinjoin_loader) override + { + return MakeWalletLoader(chain, *Assert(m_node.args), m_node, coinjoin_loader); + } + std::unique_ptr makeEcho() override { return interfaces::MakeEcho(); } + node::NodeContext m_node; +}; +} // namespace +} // namespace init + +namespace interfaces { +std::unique_ptr MakeGuiInit(int argc, char* argv[]) +{ + return std::make_unique(); +} +} // namespace interfaces diff --git a/src/init/bitcoin-wallet.cpp b/src/init/bitcoin-wallet.cpp new file mode 100644 index 000000000000..e9dcde72fe23 --- /dev/null +++ b/src/init/bitcoin-wallet.cpp @@ -0,0 +1,12 @@ +// Copyright (c) 2021 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +namespace interfaces { +std::unique_ptr MakeWalletInit(int argc, char* argv[], int& exit_status) +{ + return std::make_unique(); +} +} // namespace interfaces diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index e78adbb79884..0b56f19e865a 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include @@ -81,8 +80,6 @@ Q_DECLARE_METATYPE(CAmount) Q_DECLARE_METATYPE(SynchronizationState) Q_DECLARE_METATYPE(uint256) -using node::NodeContext; - static void RegisterMetaTypes() { // Register meta types used for QMetaObject::invokeMethod and Qt::QueuedConnection @@ -511,9 +508,7 @@ int GuiMain(int argc, char* argv[]) std::tie(argc, argv) = winArgs.get(); #endif - NodeContext node_context; - int unused_exit_status; - std::unique_ptr init = interfaces::MakeNodeInit(node_context, argc, argv, unused_exit_status); + std::unique_ptr init = interfaces::MakeGuiInit(argc, argv); SetupEnvironment(); util::ThreadSetInternalName("main"); diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp index d2f56ab891d6..a043b24ffe9c 100644 --- a/src/qt/test/test_main.cpp +++ b/src/qt/test/test_main.cpp @@ -45,8 +45,6 @@ Q_IMPORT_PLUGIN(QAndroidPlatformIntegrationPlugin) #endif #endif -using node::NodeContext; - const std::function G_TEST_LOG_FUN{}; const std::function()> G_TEST_COMMAND_LINE_ARGUMENTS{}; @@ -64,9 +62,7 @@ int main(int argc, char* argv[]) BasicTestingSetup dummy{CBaseChainParams::REGTEST}; } - NodeContext node_context; - int unused_exit_status; - std::unique_ptr init = interfaces::MakeNodeInit(node_context, argc, argv, unused_exit_status); + std::unique_ptr init = interfaces::MakeGuiInit(argc, argv); gArgs.ForceSetArg("-listen", "0"); gArgs.ForceSetArg("-listenonion", "0"); gArgs.ForceSetArg("-discover", "0"); diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 8401e186c750..a2c4aa399072 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -517,6 +517,12 @@ static RPCHelpMan getblockfrompeer() throw JSONRPCError(RPC_MISC_ERROR, "Block header missing"); } + // Fetching blocks before the node has syncing past their height can prevent block files from + // being pruned, so we avoid it if the node is in prune mode. + if (index->nHeight > chainman.ActiveChain().Tip()->nHeight && node::fPruneMode) { + throw JSONRPCError(RPC_MISC_ERROR, "In prune mode, only blocks that the node has already synced previously can be fetched from a peer"); + } + const bool block_has_data = WITH_LOCK(::cs_main, return index->nStatus & BLOCK_HAVE_DATA); if (block_has_data) { throw JSONRPCError(RPC_MISC_ERROR, "Block already downloaded"); diff --git a/src/wallet/test/fuzz/notifications.cpp b/src/wallet/test/fuzz/notifications.cpp index 013878da5e35..daa9d5a8aa09 100644 --- a/src/wallet/test/fuzz/notifications.cpp +++ b/src/wallet/test/fuzz/notifications.cpp @@ -95,7 +95,7 @@ FUZZ_TARGET(wallet_notifications, .init = initialize_setup) using Coins = std::set>; std::vector> chain; { - // Add the inital entry + // Add the initial entry chain.emplace_back(); auto& [coins, block]{chain.back()}; coins.emplace(total_amount, COutPoint{uint256::ONE, 1}); diff --git a/test/functional/feature_assumevalid.py b/test/functional/feature_assumevalid.py index 00a130ff6907..877ca5796122 100755 --- a/test/functional/feature_assumevalid.py +++ b/test/functional/feature_assumevalid.py @@ -126,10 +126,8 @@ def run_test(self): tx.vout.append(CTxOut(49 * 100000000, CScript([OP_TRUE]))) tx.calc_sha256() - block102 = create_block(self.tip, create_coinbase(height), self.block_time) + block102 = create_block(self.tip, create_coinbase(height), self.block_time, txlist=[tx]) self.block_time += 1 - block102.vtx.extend([tx]) - block102.hashMerkleRoot = block102.calc_merkle_root() block102.solve() self.blocks.append(block102) self.tip = block102.sha256 @@ -139,7 +137,6 @@ def run_test(self): # Bury the assumed valid block 8400 deep (Dash needs 4x as much blocks to allow -assumevalid to work) for _ in range(8400): block = create_block(self.tip, create_coinbase(height), self.block_time) - block.nVersion = 4 block.solve() self.blocks.append(block) self.tip = block.sha256 diff --git a/test/functional/feature_bip68_sequence.py b/test/functional/feature_bip68_sequence.py index be8811e9eb53..c7ca1ec190f9 100755 --- a/test/functional/feature_bip68_sequence.py +++ b/test/functional/feature_bip68_sequence.py @@ -385,8 +385,7 @@ def test_bip68_not_consensus(self): assert_raises_rpc_error(-26, NOT_FINAL_ERROR, self.wallet.sendrawtransaction, from_node=self.nodes[0], tx_hex=tx3.serialize().hex()) # make a block that violates bip68; ensure that the tip updates - block = create_block(tmpl=self.nodes[0].getblocktemplate(NORMAL_GBT_REQUEST_PARAMS)) - block.vtx.extend([tx1, tx2, tx3]) + block = create_block(tmpl=self.nodes[0].getblocktemplate(NORMAL_GBT_REQUEST_PARAMS), txlist=[tx1, tx2, tx3]) block.hashMerkleRoot = block.calc_merkle_root() block.solve() diff --git a/test/functional/feature_block.py b/test/functional/feature_block.py index 99e70478f71f..a56288176f31 100755 --- a/test/functional/feature_block.py +++ b/test/functional/feature_block.py @@ -1380,11 +1380,10 @@ def next_block(self, number, spend=None, additional_coinbase_value=0, script=CSc else: coinbase.vout[0].nValue += spend.vout[0].nValue - 1 # all but one satoshi to fees coinbase.rehash() - block = create_block(base_block_hash, coinbase, block_time, version=version) tx = self.create_tx(spend, 0, 1, script) # spend 1 satoshi self.sign_tx(tx, spend) - self.add_transactions_to_block(block, [tx]) - block.hashMerkleRoot = block.calc_merkle_root() + tx.rehash() + block = create_block(base_block_hash, coinbase, block_time, version=version, txlist=[tx]) # Block is created. Find a valid nonce. block.solve() self.tip = block diff --git a/test/functional/feature_cltv.py b/test/functional/feature_cltv.py index 907811c47250..eced70a78bdc 100755 --- a/test/functional/feature_cltv.py +++ b/test/functional/feature_cltv.py @@ -128,10 +128,7 @@ def run_test(self): tip = self.nodes[0].getbestblockhash() block_time = self.nodes[0].getblockheader(tip)['mediantime'] + 1 - block = create_block(int(tip, 16), create_coinbase(CLTV_HEIGHT - 1), block_time) - block.nVersion = 3 - block.vtx.extend(invalid_cltv_txs) - block.hashMerkleRoot = block.calc_merkle_root() + block = create_block(int(tip, 16), create_coinbase(CLTV_HEIGHT - 1), block_time, version=3, txlist=invalid_cltv_txs) block.solve() self.test_cltv_info(is_active=False) # Not active as of current tip and next block does not need to obey rules @@ -142,8 +139,7 @@ def run_test(self): self.log.info("Test that blocks must now be at least version 4") tip = block.sha256 block_time += 1 - block = create_block(tip, create_coinbase(CLTV_HEIGHT), block_time) - block.nVersion = 3 + block = create_block(tip, create_coinbase(CLTV_HEIGHT), block_time, version=3) block.solve() with self.nodes[0].assert_debug_log(expected_msgs=[f'{block.hash}, bad-version(0x00000003)']): diff --git a/test/functional/feature_csv_activation.py b/test/functional/feature_csv_activation.py index 969ad4b0003f..4c6632ed869c 100755 --- a/test/functional/feature_csv_activation.py +++ b/test/functional/feature_csv_activation.py @@ -182,10 +182,7 @@ def generate_blocks(self, number): return test_blocks def create_test_block(self, txs): - block = create_block(self.tip, create_coinbase(self.tipheight + 1), self.last_block_time + 600) - block.nVersion = 4 - block.vtx.extend(txs) - block.hashMerkleRoot = block.calc_merkle_root() + block = create_block(self.tip, create_coinbase(self.tipheight + 1), self.last_block_time + 600, txlist=txs) block.solve() return block diff --git a/test/functional/feature_dersig.py b/test/functional/feature_dersig.py index 604a471c4da0..0880321f02f4 100755 --- a/test/functional/feature_dersig.py +++ b/test/functional/feature_dersig.py @@ -89,9 +89,7 @@ def run_test(self): tip = self.nodes[0].getbestblockhash() block_time = self.nodes[0].getblockheader(tip)['mediantime'] + 1 - block = create_block(int(tip, 16), create_coinbase(DERSIG_HEIGHT - 1), block_time) - block.vtx.append(spendtx) - block.hashMerkleRoot = block.calc_merkle_root() + block = create_block(int(tip, 16), create_coinbase(DERSIG_HEIGHT - 1), block_time, txlist=[spendtx]) block.solve() assert_equal(self.nodes[0].getblockcount(), DERSIG_HEIGHT - 2) @@ -104,8 +102,7 @@ def run_test(self): self.log.info("Test that blocks must now be at least version 3") tip = block.sha256 block_time += 1 - block = create_block(tip, create_coinbase(DERSIG_HEIGHT), block_time) - block.nVersion = 2 + block = create_block(tip, create_coinbase(DERSIG_HEIGHT), block_time, version=2) block.solve() with self.nodes[0].assert_debug_log(expected_msgs=[f'{block.hash}, bad-version(0x00000002)']): diff --git a/test/functional/feature_versionbits_warning.py b/test/functional/feature_versionbits_warning.py index 20e131c56899..e386fbae7179 100755 --- a/test/functional/feature_versionbits_warning.py +++ b/test/functional/feature_versionbits_warning.py @@ -45,8 +45,7 @@ def send_blocks_with_version(self, peer, numblocks, version): tip = int(tip, 16) for _ in range(numblocks): - block = create_block(tip, create_coinbase(height + 1), block_time) - block.nVersion = version + block = create_block(tip, create_coinbase(height + 1), block_time, version=version) block.solve() peer.send_message(msg_block(block)) block_time += 1 diff --git a/test/functional/interface_bitcoin_cli.py b/test/functional/interface_bitcoin_cli.py index f92644baeedc..a81f6e25f11b 100755 --- a/test/functional/interface_bitcoin_cli.py +++ b/test/functional/interface_bitcoin_cli.py @@ -149,6 +149,9 @@ def run_test(self): if self.is_specified_wallet_compiled(): self.log.info("Test -getinfo and dash-cli getwalletinfo return expected wallet info") + # Explicitely set the output type in order to have constintent tx vsize / fees + # for both legacy and descriptor wallets (disables the change address type detection algorithm) + self.restart_node(0, extra_args=[]) assert_equal(Decimal(cli_get_info['Balance']), BALANCE) assert 'Balances' not in cli_get_info_string wallet_info = self.nodes[0].getwalletinfo() diff --git a/test/functional/p2p_invalid_block.py b/test/functional/p2p_invalid_block.py index e4555dba9cf7..1d8217b40289 100755 --- a/test/functional/p2p_invalid_block.py +++ b/test/functional/p2p_invalid_block.py @@ -14,9 +14,15 @@ """ import copy -from test_framework.blocktools import MAX_FUTURE_BLOCK_TIME, create_block, create_coinbase, create_tx_with_script +from test_framework.blocktools import ( + MAX_FUTURE_BLOCK_TIME, + create_block, + create_coinbase, + create_tx_with_script, +) from test_framework.messages import COIN from test_framework.p2p import P2PDataStore +from test_framework.script import OP_TRUE from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal @@ -61,15 +67,10 @@ def run_test(self): # For more information on merkle-root malleability see src/consensus/merkle.cpp. self.log.info("Test merkle root malleability.") - block2 = create_block(tip, create_coinbase(height), block_time) + tx1 = create_tx_with_script(block1.vtx[0], 0, script_sig=bytes([OP_TRUE]), amount=50 * COIN) + tx2 = create_tx_with_script(tx1, 0, script_sig=bytes([OP_TRUE]), amount=50 * COIN) + block2 = create_block(tip, create_coinbase(height), block_time, txlist=[tx1, tx2]) block_time += 1 - - # b'0x51' is OP_TRUE - tx1 = create_tx_with_script(block1.vtx[0], 0, script_sig=b'\x51', amount=50 * COIN) - tx2 = create_tx_with_script(tx1, 0, script_sig=b'\x51', amount=50 * COIN) - - block2.vtx.extend([tx1, tx2]) - block2.hashMerkleRoot = block2.calc_merkle_root() block2.solve() orig_hash = block2.sha256 block2_orig = copy.deepcopy(block2) @@ -94,12 +95,8 @@ def run_test(self): self.log.info("Test very broken block.") - block3 = create_block(tip, create_coinbase(height), block_time) + block3 = create_block(tip, create_coinbase(height, nValue=1000), block_time) block_time += 1 - block3.vtx[0].vout[0].nValue = 1000 * COIN # Too high! - block3.vtx[0].sha256 = None - block3.vtx[0].calc_sha256() - block3.hashMerkleRoot = block3.calc_merkle_root() block3.solve() peer.send_blocks_and_test([block3], node, success=False, reject_reason='bad-cb-amount') @@ -118,14 +115,10 @@ def run_test(self): # Complete testing of CVE-2018-17144, by checking for the inflation bug. # Create a block that spends the output of a tx in a previous block. - block4 = create_block(tip, create_coinbase(height), block_time) - tx3 = create_tx_with_script(tx2, 0, script_sig=b'\x51', amount=50 * COIN) - - # Duplicates input - tx3.vin.append(tx3.vin[0]) + tx3 = create_tx_with_script(tx2, 0, script_sig=bytes([OP_TRUE]), amount=50 * COIN) + tx3.vin.append(tx3.vin[0]) # Duplicates input tx3.rehash() - block4.vtx.append(tx3) - block4.hashMerkleRoot = block4.calc_merkle_root() + block4 = create_block(tip, create_coinbase(height), block_time, txlist=[tx3]) block4.solve() self.log.info("Test inflation by duplicating input") peer.send_blocks_and_test([block4], node, success=False, reject_reason='bad-txns-inputs-duplicate') @@ -134,7 +127,6 @@ def run_test(self): t = self.mocktime # Set block time +1 second past max future validity block = create_block(tip, create_coinbase(height), t + MAX_FUTURE_BLOCK_TIME + 1) - block.hashMerkleRoot = block.calc_merkle_root() block.solve() # Need force_send because the block will get rejected without a getdata otherwise peer.send_blocks_and_test([block], node, force_send=True, success=False, reject_reason='time-too-new') diff --git a/test/functional/p2p_unrequested_blocks.py b/test/functional/p2p_unrequested_blocks.py index 6dec38007208..7bfc3f539a93 100755 --- a/test/functional/p2p_unrequested_blocks.py +++ b/test/functional/p2p_unrequested_blocks.py @@ -221,10 +221,9 @@ def run_test(self): block_289f.solve() block_290f = create_block(block_289f.sha256, create_coinbase(290), block_289f.nTime+1) block_290f.solve() - block_291 = create_block(block_290f.sha256, create_coinbase(291), block_290f.nTime+1) # block_291 spends a coinbase below maturity! - block_291.vtx.append(create_tx_with_script(block_290f.vtx[0], 0, script_sig=b"42", amount=1)) - block_291.hashMerkleRoot = block_291.calc_merkle_root() + tx_to_add = create_tx_with_script(block_290f.vtx[0], 0, script_sig=b"42", amount=1) + block_291 = create_block(block_290f.sha256, create_coinbase(291), block_290f.nTime+1, txlist=[tx_to_add]) block_291.solve() block_292 = create_block(block_291.sha256, create_coinbase(292), block_291.nTime+1) block_292.solve() diff --git a/test/functional/rpc_decodescript.py b/test/functional/rpc_decodescript.py index 4eb5dfb2e6d8..00e4ea883f03 100755 --- a/test/functional/rpc_decodescript.py +++ b/test/functional/rpc_decodescript.py @@ -51,7 +51,7 @@ def decodescript_script_sig(self): rpc_result = self.nodes[0].decodescript('5100') assert_equal('1 0', rpc_result['asm']) - # null data scriptSig - no such thing because null data scripts can not be spent. + # null data scriptSig - no such thing because null data scripts cannot be spent. # thus, no test case for that standard transaction type is here. def decodescript_script_pub_key(self): diff --git a/test/functional/rpc_getblockfrompeer.py b/test/functional/rpc_getblockfrompeer.py index 43c96641cfd4..6b460336e698 100755 --- a/test/functional/rpc_getblockfrompeer.py +++ b/test/functional/rpc_getblockfrompeer.py @@ -5,12 +5,22 @@ """Test the getblockfrompeer RPC.""" from test_framework.authproxy import JSONRPCException +from test_framework.governance import EXPECTED_STDERR_NO_GOV_PRUNE +from test_framework.messages import ( + CBlock, + from_hex, + msg_headers, +) +from test_framework.p2p import ( + P2PInterface, +) from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, assert_raises_rpc_error, ) + class GetBlockFromPeerTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 2 @@ -69,5 +79,31 @@ def run_test(self): self.log.info("Don't fetch blocks we already have") assert_raises_rpc_error(-1, "Block already downloaded", self.nodes[0].getblockfrompeer, short_tip, peer_0_peer_1_id) + self.log.info("Don't fetch blocks while the node has not synced past it yet") + # For this test we need node 1 in prune mode and as a side effect this also disconnects + # the nodes which is also necessary for the rest of the test. + self.restart_node(1, ["-prune=550"]) + + # Generate a block on the disconnected node that the pruning node is not connected to + blockhash = self.generate(self.nodes[0], 1, sync_fun=self.no_op)[0] + block_hex = self.nodes[0].getblock(blockhash=blockhash, verbosity=0) + block = from_hex(CBlock(), block_hex) + + # Connect a P2PInterface to the pruning node and have it submit only the header of the + # block that the pruning node has not seen + node1_interface = self.nodes[1].add_p2p_connection(P2PInterface()) + node1_interface.send_message(msg_headers([block])) + + # Get the peer id of the P2PInterface from the pruning node + node1_peers = self.nodes[1].getpeerinfo() + assert_equal(len(node1_peers), 1) + node1_interface_id = node1_peers[0]["id"] + + # Trying to fetch this block from the P2PInterface should not be possible + error_msg = "In prune mode, only blocks that the node has already synced previously can be fetched from a peer" + assert_raises_rpc_error(-1, error_msg, self.nodes[1].getblockfrompeer, blockhash, node1_interface_id) + self.stop_node(1, expected_stderr=EXPECTED_STDERR_NO_GOV_PRUNE) + + if __name__ == '__main__': GetBlockFromPeerTest().main() diff --git a/test/functional/test_framework/messages.py b/test/functional/test_framework/messages.py index b22cb5475370..aa467d78f2be 100755 --- a/test/functional/test_framework/messages.py +++ b/test/functional/test_framework/messages.py @@ -30,7 +30,7 @@ from test_framework.crypto.siphash import siphash256 from test_framework.util import assert_equal -import dash_hash +import dash_hash # type: ignore[import] MAX_LOCATOR_SZ = 101 MAX_BLOCK_SIZE = 2000000 diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index ddcd17a662a4..226b03c22a07 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -169,7 +169,8 @@ 'interface_zmq_dash.py --legacy-wallet', 'interface_zmq.py', 'rpc_invalid_address_message.py', - 'interface_bitcoin_cli.py', + 'interface_bitcoin_cli.py --legacy-wallet', + 'interface_bitcoin_cli.py --descriptors', 'feature_bind_extra.py', 'mempool_resurrect.py', 'wallet_txn_doublespend.py --mineblock', diff --git a/test/functional/wallet_timelock.py b/test/functional/wallet_timelock.py index cf233a00effd..a71cec6607de 100755 --- a/test/functional/wallet_timelock.py +++ b/test/functional/wallet_timelock.py @@ -30,7 +30,7 @@ def run_test(self): ) self.generate(node, 1) - self.log.info("Check that clock can not change finality of confirmed txs") + self.log.info("Check that clock cannot change finality of confirmed txs") amount_before_ad = node.getreceivedbyaddress(address) amount_before_lb = node.getreceivedbylabel(label) list_before_ad = node.listreceivedbyaddress(address_filter=address) diff --git a/test/lint/lint-python.py b/test/lint/lint-python.py index fb6224b06e8a..a81edfd2fc7f 100755 --- a/test/lint/lint-python.py +++ b/test/lint/lint-python.py @@ -126,7 +126,8 @@ def main(): exit(1) mypy_files = subprocess.check_output(FILES_ARGS).decode("utf-8").splitlines() - mypy_args = ['mypy', '--ignore-missing-imports', '--show-error-codes'] + mypy_files + # TODO: remove `--namespace-packages` after upgrade to mypy 0.991 or newer + mypy_args = ['mypy', '--namespace-packages', '--show-error-codes'] + mypy_files try: subprocess.check_call(mypy_args)