diff --git a/CMakeLists.txt b/CMakeLists.txt index e17aafc3ac8..b78274af2a5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,7 +30,7 @@ set(CLIENT_NAME "Bitcoin Core") set(CLIENT_VERSION_MAJOR 30) set(CLIENT_VERSION_MINOR 0) set(CLIENT_VERSION_BUILD 0) -set(CLIENT_VERSION_RC 2) +set(CLIENT_VERSION_RC 3) set(CLIENT_VERSION_IS_RELEASE "true") set(COPYRIGHT_YEAR "2025") diff --git a/contrib/guix/symbol-check.py b/contrib/guix/symbol-check.py index d808ef6becf..79ab6b0fe54 100755 --- a/contrib/guix/symbol-check.py +++ b/contrib/guix/symbol-check.py @@ -112,7 +112,6 @@ ELF_ALLOWED_LIBRARIES = { 'libfontconfig.so.1', # font support 'libfreetype.so.6', # font parsing 'libdl.so.2', # programming interface to dynamic linker -'libxcb-cursor.so.0', 'libxcb-icccm.so.4', 'libxcb-image.so.0', 'libxcb-shm.so.0', diff --git a/contrib/macdeploy/macdeployqtplus b/contrib/macdeploy/macdeployqtplus index ba532d77740..802afa5389d 100755 --- a/contrib/macdeploy/macdeployqtplus +++ b/contrib/macdeploy/macdeployqtplus @@ -466,18 +466,18 @@ if config.translations_dir: sys.stderr.write(f"Error: Could not find translation dir \"{config.translations_dir[0]}\"\n") sys.exit(1) -print("+ Adding Qt translations +") + print("+ Adding Qt translations +") -translations = Path(config.translations_dir[0]) + translations = Path(config.translations_dir[0]) -regex = re.compile('qt_[a-z]*(.qm|_[A-Z]*.qm)') + regex = re.compile('qt_[a-z]*(.qm|_[A-Z]*.qm)') -lang_files = [x for x in translations.iterdir() if regex.match(x.name)] + lang_files = [x for x in translations.iterdir() if regex.match(x.name)] -for file in lang_files: - if verbose: - print(file.as_posix(), "->", os.path.join(applicationBundle.resourcesPath, file.name)) - shutil.copy2(file.as_posix(), os.path.join(applicationBundle.resourcesPath, file.name)) + for file in lang_files: + if verbose: + print(file.as_posix(), "->", os.path.join(applicationBundle.resourcesPath, file.name)) + shutil.copy2(file.as_posix(), os.path.join(applicationBundle.resourcesPath, file.name)) # ------------------------------------------------ diff --git a/depends/packages/libxcb_util_cursor.mk b/depends/packages/libxcb_util_cursor.mk index b308890638d..288afeaa1f0 100644 --- a/depends/packages/libxcb_util_cursor.mk +++ b/depends/packages/libxcb_util_cursor.mk @@ -6,7 +6,7 @@ $(package)_sha256_hash=0e9c5446dc6f3beb8af6ebfcc9e27bcc6da6fe2860f7fc07b99144dfa $(package)_dependencies=libxcb libxcb_util_render libxcb_util_image define $(package)_set_vars -$(package)_config_opts = --disable-static +$(package)_config_opts = --disable-shared $(package)_config_opts += --disable-dependency-tracking --enable-option-checking endef diff --git a/doc/build-unix.md b/doc/build-unix.md index bfb3bd35d99..d9bbb350a7a 100644 --- a/doc/build-unix.md +++ b/doc/build-unix.md @@ -81,8 +81,6 @@ the necessary parts of Qt, the libqrencode and pass `-DBUILD_GUI=ON`. Skip if yo sudo apt-get install qt6-base-dev qt6-tools-dev qt6-l10n-tools qt6-tools-dev-tools libgl-dev -For Qt 6.5 and later, the `libxcb-cursor0` package must be installed at runtime. - Additionally, to support Wayland protocol for modern desktop environments: sudo apt install qt6-wayland @@ -133,8 +131,6 @@ the necessary parts of Qt, the libqrencode and pass `-DBUILD_GUI=ON`. Skip if yo sudo dnf install qt6-qtbase-devel qt6-qttools-devel -For Qt 6.5 and later, the `xcb-util-cursor` package must be installed at runtime. - Additionally, to support Wayland protocol for modern desktop environments: sudo dnf install qt6-qtwayland @@ -182,8 +178,6 @@ the necessary parts of Qt, the libqrencode and pass `-DBUILD_GUI=ON`. Skip if yo apk add qt6-qtbase-dev qt6-qttools-dev -For Qt 6.5 and later, the `xcb-util-cursor` package must be installed at runtime. - The GUI will be able to encode addresses in QR codes unless this feature is explicitly disabled. To install libqrencode, run: apk add libqrencode-dev diff --git a/doc/man/bitcoin-cli.1 b/doc/man/bitcoin-cli.1 index b524d0318fa..fcb2ef423e4 100644 --- a/doc/man/bitcoin-cli.1 +++ b/doc/man/bitcoin-cli.1 @@ -1,7 +1,7 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3. -.TH BITCOIN-CLI "1" "September 2025" "bitcoin-cli v30.0.0rc2" "User Commands" +.TH BITCOIN-CLI "1" "October 2025" "bitcoin-cli v30.0.0rc3" "User Commands" .SH NAME -bitcoin-cli \- manual page for bitcoin-cli v30.0.0rc2 +bitcoin-cli \- manual page for bitcoin-cli v30.0.0rc3 .SH SYNOPSIS .B bitcoin-cli [\fI\,options\/\fR] \fI\, \/\fR[\fI\,params\/\fR] @@ -15,7 +15,7 @@ bitcoin-cli \- manual page for bitcoin-cli v30.0.0rc2 .B bitcoin-cli [\fI\,options\/\fR] \fI\,help \/\fR .SH DESCRIPTION -Bitcoin Core RPC client version v30.0.0rc2 +Bitcoin Core RPC client version v30.0.0rc3 .PP The bitcoin\-cli utility provides a command line interface to interact with a Bitcoin Core RPC server. .PP diff --git a/doc/man/bitcoin-qt.1 b/doc/man/bitcoin-qt.1 index df313ca2803..67324184dd2 100644 --- a/doc/man/bitcoin-qt.1 +++ b/doc/man/bitcoin-qt.1 @@ -1,12 +1,12 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3. -.TH BITCOIN-QT "1" "September 2025" "bitcoin-qt v30.0.0rc2" "User Commands" +.TH BITCOIN-QT "1" "October 2025" "bitcoin-qt v30.0.0rc3" "User Commands" .SH NAME -bitcoin-qt \- manual page for bitcoin-qt v30.0.0rc2 +bitcoin-qt \- manual page for bitcoin-qt v30.0.0rc3 .SH SYNOPSIS .B bitcoin-qt [\fI\,options\/\fR] [\fI\,URI\/\fR] .SH DESCRIPTION -Bitcoin Core version v30.0.0rc2 +Bitcoin Core version v30.0.0rc3 .PP The bitcoin\-qt application provides a graphical interface for interacting with Bitcoin Core. .PP @@ -695,13 +695,13 @@ Equivalent bytes per sigop in transactions for relay and mining .HP \fB\-datacarrier\fR .IP -(DEPRECATED) Relay and mine data carrier transactions (default: 1) +Relay and mine data carrier transactions (default: 1) .HP \fB\-datacarriersize\fR .IP -(DEPRECATED) Relay and mine transactions whose data\-carrying raw -scriptPubKeys in aggregate are of this size or less, allowing -multiple outputs (default: 100000) +Relay and mine transactions whose data\-carrying raw scriptPubKeys in +aggregate are of this size or less, allowing multiple outputs +(default: 100000) .HP \fB\-minrelaytxfee=\fR .IP diff --git a/doc/man/bitcoin-tx.1 b/doc/man/bitcoin-tx.1 index d28d33edaea..1dea8e061f5 100644 --- a/doc/man/bitcoin-tx.1 +++ b/doc/man/bitcoin-tx.1 @@ -1,7 +1,7 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3. -.TH BITCOIN-TX "1" "September 2025" "bitcoin-tx v30.0.0rc2" "User Commands" +.TH BITCOIN-TX "1" "October 2025" "bitcoin-tx v30.0.0rc3" "User Commands" .SH NAME -bitcoin-tx \- manual page for bitcoin-tx v30.0.0rc2 +bitcoin-tx \- manual page for bitcoin-tx v30.0.0rc3 .SH SYNOPSIS .B bitcoin-tx [\fI\,options\/\fR] \fI\, \/\fR[\fI\,commands\/\fR] @@ -9,7 +9,7 @@ bitcoin-tx \- manual page for bitcoin-tx v30.0.0rc2 .B bitcoin-tx [\fI\,options\/\fR] \fI\,-create \/\fR[\fI\,commands\/\fR] .SH DESCRIPTION -Bitcoin Core bitcoin\-tx utility version v30.0.0rc2 +Bitcoin Core bitcoin\-tx utility version v30.0.0rc3 .PP The bitcoin\-tx tool is used for creating and modifying bitcoin transactions. .PP diff --git a/doc/man/bitcoin-util.1 b/doc/man/bitcoin-util.1 index 14071e4ac37..c59b3f30ba9 100644 --- a/doc/man/bitcoin-util.1 +++ b/doc/man/bitcoin-util.1 @@ -1,7 +1,7 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3. -.TH BITCOIN-UTIL "1" "September 2025" "bitcoin-util v30.0.0rc2" "User Commands" +.TH BITCOIN-UTIL "1" "October 2025" "bitcoin-util v30.0.0rc3" "User Commands" .SH NAME -bitcoin-util \- manual page for bitcoin-util v30.0.0rc2 +bitcoin-util \- manual page for bitcoin-util v30.0.0rc3 .SH SYNOPSIS .B bitcoin-util [\fI\,options\/\fR] [\fI\,command\/\fR] @@ -9,7 +9,7 @@ bitcoin-util \- manual page for bitcoin-util v30.0.0rc2 .B bitcoin-util [\fI\,options\/\fR] \fI\,grind \/\fR .SH DESCRIPTION -Bitcoin Core bitcoin\-util utility version v30.0.0rc2 +Bitcoin Core bitcoin\-util utility version v30.0.0rc3 .PP The bitcoin\-util tool provides bitcoin related functionality that does not rely on the ability to access a running node. Available [commands] are listed below. .SH OPTIONS diff --git a/doc/man/bitcoin-wallet.1 b/doc/man/bitcoin-wallet.1 index 7d60722fadf..b040cbae538 100644 --- a/doc/man/bitcoin-wallet.1 +++ b/doc/man/bitcoin-wallet.1 @@ -1,12 +1,12 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3. -.TH BITCOIN-WALLET "1" "September 2025" "bitcoin-wallet v30.0.0rc2" "User Commands" +.TH BITCOIN-WALLET "1" "October 2025" "bitcoin-wallet v30.0.0rc3" "User Commands" .SH NAME -bitcoin-wallet \- manual page for bitcoin-wallet v30.0.0rc2 +bitcoin-wallet \- manual page for bitcoin-wallet v30.0.0rc3 .SH SYNOPSIS .B bitcoin-wallet [\fI\,options\/\fR] \fI\,\/\fR .SH DESCRIPTION -Bitcoin Core bitcoin\-wallet utility version v30.0.0rc2 +Bitcoin Core bitcoin\-wallet utility version v30.0.0rc3 .PP bitcoin\-wallet is an offline tool for creating and interacting with Bitcoin Core wallet files. .PP diff --git a/doc/man/bitcoin.1 b/doc/man/bitcoin.1 index e7f1a31528f..ba39bbe419d 100644 --- a/doc/man/bitcoin.1 +++ b/doc/man/bitcoin.1 @@ -1,7 +1,7 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3. -.TH BITCOIN "1" "September 2025" "bitcoin v30.0.0rc2" "User Commands" +.TH BITCOIN "1" "October 2025" "bitcoin v30.0.0rc3" "User Commands" .SH NAME -bitcoin \- manual page for bitcoin v30.0.0rc2 +bitcoin \- manual page for bitcoin v30.0.0rc3 .SH SYNOPSIS .B bitcoin [\fI\,OPTIONS\/\fR] \fI\,COMMAND\/\fR... diff --git a/doc/man/bitcoind.1 b/doc/man/bitcoind.1 index 4284cff1d1b..ddc09d82fda 100644 --- a/doc/man/bitcoind.1 +++ b/doc/man/bitcoind.1 @@ -1,12 +1,12 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3. -.TH BITCOIND "1" "September 2025" "bitcoind v30.0.0rc2" "User Commands" +.TH BITCOIND "1" "October 2025" "bitcoind v30.0.0rc3" "User Commands" .SH NAME -bitcoind \- manual page for bitcoind v30.0.0rc2 +bitcoind \- manual page for bitcoind v30.0.0rc3 .SH SYNOPSIS .B bitcoind [\fI\,options\/\fR] .SH DESCRIPTION -Bitcoin Core daemon version v30.0.0rc2 +Bitcoin Core daemon version v30.0.0rc3 .PP The Bitcoin Core daemon (bitcoind) is a headless program that connects to the Bitcoin network to validate and relay transactions and blocks, as well as relaying addresses. .PP @@ -695,13 +695,13 @@ Equivalent bytes per sigop in transactions for relay and mining .HP \fB\-datacarrier\fR .IP -(DEPRECATED) Relay and mine data carrier transactions (default: 1) +Relay and mine data carrier transactions (default: 1) .HP \fB\-datacarriersize\fR .IP -(DEPRECATED) Relay and mine transactions whose data\-carrying raw -scriptPubKeys in aggregate are of this size or less, allowing -multiple outputs (default: 100000) +Relay and mine transactions whose data\-carrying raw scriptPubKeys in +aggregate are of this size or less, allowing multiple outputs +(default: 100000) .HP \fB\-minrelaytxfee=\fR .IP diff --git a/share/examples/bitcoin.conf b/share/examples/bitcoin.conf index 5ae2853ff57..5eacee9ad94 100644 --- a/share/examples/bitcoin.conf +++ b/share/examples/bitcoin.conf @@ -576,12 +576,12 @@ # (default: 20) #bytespersigop=1 -# (DEPRECATED) Relay and mine data carrier transactions (default: 1) +# Relay and mine data carrier transactions (default: 1) #datacarrier=1 -# (DEPRECATED) Relay and mine transactions whose data-carrying raw -# scriptPubKeys in aggregate are of this size or less, allowing -# multiple outputs (default: 100000) +# Relay and mine transactions whose data-carrying raw scriptPubKeys in +# aggregate are of this size or less, allowing multiple outputs +# (default: 100000) #datacarriersize=1 # Fees (in BTC/kvB) smaller than this are considered zero fee for diff --git a/src/init.cpp b/src/init.cpp index 7c858242a8a..02e5f2a2488 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -658,9 +658,9 @@ void SetupServerArgs(ArgsManager& argsman, bool can_listen_ipc) argsman.AddArg("-dustrelayfee=", strprintf("Fee rate (in %s/kvB) used to define dust, the value of an output such that it will cost more than its value in fees at this fee rate to spend it. (default: %s)", CURRENCY_UNIT, FormatMoney(DUST_RELAY_TX_FEE)), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::NODE_RELAY); argsman.AddArg("-acceptstalefeeestimates", strprintf("Read fee estimates even if they are stale (%sdefault: %u) fee estimates are considered stale if they are %s hours old", "regtest only; ", DEFAULT_ACCEPT_STALE_FEE_ESTIMATES, Ticks(MAX_FILE_AGE)), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-bytespersigop", strprintf("Equivalent bytes per sigop in transactions for relay and mining (default: %u)", DEFAULT_BYTES_PER_SIGOP), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY); - argsman.AddArg("-datacarrier", strprintf("(DEPRECATED) Relay and mine data carrier transactions (default: %u)", DEFAULT_ACCEPT_DATACARRIER), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY); + argsman.AddArg("-datacarrier", strprintf("Relay and mine data carrier transactions (default: %u)", DEFAULT_ACCEPT_DATACARRIER), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY); argsman.AddArg("-datacarriersize", - strprintf("(DEPRECATED) Relay and mine transactions whose data-carrying raw scriptPubKeys in aggregate " + strprintf("Relay and mine transactions whose data-carrying raw scriptPubKeys in aggregate " "are of this size or less, allowing multiple outputs (default: %u)", MAX_OP_RETURN_RELAY), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY); @@ -903,10 +903,6 @@ bool AppInitParameterInteraction(const ArgsManager& args) InitWarning(_("Option '-checkpoints' is set but checkpoints were removed. This option has no effect.")); } - if (args.IsArgSet("-datacarriersize") || args.IsArgSet("-datacarrier")) { - InitWarning(_("Options '-datacarrier' or '-datacarriersize' are set but are marked as deprecated and are expected to be removed in a future version.")); - } - // We no longer limit the orphanage based on number of transactions but keep the option to warn users who still have it in their config. if (args.IsArgSet("-maxorphantx")) { InitWarning(_("Option '-maxorphantx' is set but no longer has any effect (see release notes). Please remove it from your configuration.")); diff --git a/src/node/miner.cpp b/src/node/miner.cpp index a08c70e29da..e75bc3a603b 100644 --- a/src/node/miner.cpp +++ b/src/node/miner.cpp @@ -397,8 +397,8 @@ void BlockAssembler::addPackageTxs(int& nPackagesSelected, int& nDescendantsUpda ++nConsecutiveFailed; - if (nConsecutiveFailed > MAX_CONSECUTIVE_FAILURES && nBlockWeight > - m_options.nBlockMaxWeight - BLOCK_FULL_ENOUGH_WEIGHT_DELTA) { + if (nConsecutiveFailed > MAX_CONSECUTIVE_FAILURES && nBlockWeight + + BLOCK_FULL_ENOUGH_WEIGHT_DELTA > m_options.nBlockMaxWeight) { // Give up if we're close to full and haven't succeeded in a while break; } diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index bd5deedf6ee..4ef863a4805 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -166,7 +166,7 @@ UniValue blockheaderToJSON(const CBlockIndex& tip, const CBlockIndex& blockindex result.pushKV("mediantime", blockindex.GetMedianTimePast()); result.pushKV("nonce", blockindex.nNonce); result.pushKV("bits", strprintf("%08x", blockindex.nBits)); - result.pushKV("target", GetTarget(tip, pow_limit).GetHex()); + result.pushKV("target", GetTarget(blockindex, pow_limit).GetHex()); result.pushKV("difficulty", GetDifficulty(blockindex)); result.pushKV("chainwork", blockindex.nChainWork.GetHex()); result.pushKV("nTx", blockindex.nTx); diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index b7f458ea294..1a8edc594fe 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -1608,7 +1608,7 @@ static RPCHelpMan finalizepsbt() return RPCHelpMan{"finalizepsbt", "Finalize the inputs of a PSBT. If the transaction is fully signed, it will produce a\n" "network serialized transaction which can be broadcast with sendrawtransaction. Otherwise a PSBT will be\n" - "created which has the final_scriptSig and final_scriptWitness fields filled for inputs that are complete.\n" + "created which has the final_scriptSig and final_scriptwitness fields filled for inputs that are complete.\n" "Implements the Finalizer and Extractor roles.\n", { {"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "A base64 string of a PSBT"}, diff --git a/src/test/fuzz/package_eval.cpp b/src/test/fuzz/package_eval.cpp index 23ea9d1f15a..50f4c416d79 100644 --- a/src/test/fuzz/package_eval.cpp +++ b/src/test/fuzz/package_eval.cpp @@ -325,7 +325,7 @@ FUZZ_TARGET(ephemeral_package_eval, .init = initialize_tx_pool) return ProcessNewPackage(chainstate, tx_pool, txs, /*test_accept=*/single_submit, /*client_maxfeerate=*/{})); const auto res = WITH_LOCK(::cs_main, return AcceptToMemoryPool(chainstate, txs.back(), GetTime(), - /*bypass_limits=*/fuzzed_data_provider.ConsumeBool(), /*test_accept=*/!single_submit)); + /*bypass_limits=*/false, /*test_accept=*/!single_submit)); if (!single_submit && result_package.m_state.GetResult() != PackageValidationResult::PCKG_POLICY) { // We don't know anything about the validity since transactions were randomly generated, so diff --git a/src/test/fuzz/tx_pool.cpp b/src/test/fuzz/tx_pool.cpp index 4245d3e1246..1db32a6dadc 100644 --- a/src/test/fuzz/tx_pool.cpp +++ b/src/test/fuzz/tx_pool.cpp @@ -296,7 +296,6 @@ FUZZ_TARGET(tx_pool_standard, .init = initialize_tx_pool) std::set added; auto txr = std::make_shared(removed, added); node.validation_signals->RegisterSharedValidationInterface(txr); - const bool bypass_limits = fuzzed_data_provider.ConsumeBool(); // Make sure ProcessNewPackage on one transaction works. // The result is not guaranteed to be the same as what is returned by ATMP. @@ -311,7 +310,7 @@ FUZZ_TARGET(tx_pool_standard, .init = initialize_tx_pool) it->second.m_result_type == MempoolAcceptResult::ResultType::INVALID); } - const auto res = WITH_LOCK(::cs_main, return AcceptToMemoryPool(chainstate, tx, GetTime(), bypass_limits, /*test_accept=*/false)); + const auto res = WITH_LOCK(::cs_main, return AcceptToMemoryPool(chainstate, tx, GetTime(), /*bypass_limits=*/false, /*test_accept=*/false)); const bool accepted = res.m_result_type == MempoolAcceptResult::ResultType::VALID; node.validation_signals->SyncWithValidationInterfaceQueue(); node.validation_signals->UnregisterSharedValidationInterface(txr); @@ -394,6 +393,9 @@ FUZZ_TARGET(tx_pool, .init = initialize_tx_pool) chainstate.SetMempool(&tx_pool); + // If we ever bypass limits, do not do TRUC invariants checks + bool ever_bypassed_limits{false}; + LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 300) { const auto mut_tx = ConsumeTransaction(fuzzed_data_provider, txids); @@ -412,13 +414,17 @@ FUZZ_TARGET(tx_pool, .init = initialize_tx_pool) tx_pool.PrioritiseTransaction(txid, delta); } + const bool bypass_limits{fuzzed_data_provider.ConsumeBool()}; + ever_bypassed_limits |= bypass_limits; + const auto tx = MakeTransactionRef(mut_tx); - const bool bypass_limits = fuzzed_data_provider.ConsumeBool(); const auto res = WITH_LOCK(::cs_main, return AcceptToMemoryPool(chainstate, tx, GetTime(), bypass_limits, /*test_accept=*/false)); const bool accepted = res.m_result_type == MempoolAcceptResult::ResultType::VALID; if (accepted) { txids.push_back(tx->GetHash()); - CheckMempoolTRUCInvariants(tx_pool); + if (!ever_bypassed_limits) { + CheckMempoolTRUCInvariants(tx_pool); + } } } Finish(fuzzed_data_provider, tx_pool, chainstate); diff --git a/src/validation.cpp b/src/validation.cpp index 8fcc719a684..3f77955da62 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1044,26 +1044,28 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) // Even though just checking direct mempool parents for inheritance would be sufficient, we // check using the full ancestor set here because it's more convenient to use what we have // already calculated. - if (const auto err{SingleTRUCChecks(ws.m_ptx, ws.m_ancestors, ws.m_conflicts, ws.m_vsize)}) { - // Single transaction contexts only. - if (args.m_allow_sibling_eviction && err->second != nullptr) { - // We should only be considering where replacement is considered valid as well. - Assume(args.m_allow_replacement); + if (!args.m_bypass_limits) { + if (const auto err{SingleTRUCChecks(ws.m_ptx, ws.m_ancestors, ws.m_conflicts, ws.m_vsize)}) { + // Single transaction contexts only. + if (args.m_allow_sibling_eviction && err->second != nullptr) { + // We should only be considering where replacement is considered valid as well. + Assume(args.m_allow_replacement); - // Potential sibling eviction. Add the sibling to our list of mempool conflicts to be - // included in RBF checks. - ws.m_conflicts.insert(err->second->GetHash()); - // Adding the sibling to m_iters_conflicting here means that it doesn't count towards - // RBF Carve Out above. This is correct, since removing to-be-replaced transactions from - // the descendant count is done separately in SingleTRUCChecks for TRUC transactions. - ws.m_iters_conflicting.insert(m_pool.GetIter(err->second->GetHash()).value()); - ws.m_sibling_eviction = true; - // The sibling will be treated as part of the to-be-replaced set in ReplacementChecks. - // Note that we are not checking whether it opts in to replaceability via BIP125 or TRUC - // (which is normally done in PreChecks). However, the only way a TRUC transaction can - // have a non-TRUC and non-BIP125 descendant is due to a reorg. - } else { - return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "TRUC-violation", err->first); + // Potential sibling eviction. Add the sibling to our list of mempool conflicts to be + // included in RBF checks. + ws.m_conflicts.insert(err->second->GetHash()); + // Adding the sibling to m_iters_conflicting here means that it doesn't count towards + // RBF Carve Out above. This is correct, since removing to-be-replaced transactions from + // the descendant count is done separately in SingleTRUCChecks for TRUC transactions. + ws.m_iters_conflicting.insert(m_pool.GetIter(err->second->GetHash()).value()); + ws.m_sibling_eviction = true; + // The sibling will be treated as part of the to-be-replaced set in ReplacementChecks. + // Note that we are not checking whether it opts in to replaceability via BIP125 or TRUC + // (which is normally done in PreChecks). However, the only way a TRUC transaction can + // have a non-TRUC and non-BIP125 descendant is due to a reorg. + } else { + return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "TRUC-violation", err->first); + } } } diff --git a/test/functional/data/README.md b/test/functional/data/README.md index bb03422f95f..956394e385c 100644 --- a/test/functional/data/README.md +++ b/test/functional/data/README.md @@ -11,9 +11,10 @@ The alternate mainnet chain was generated as follows: - restart node with a faketime 2 minutes later ```sh -for i in {1..2015} +for i in {1..2016} do - faketime "`date -d @"$(( 1231006505 + $i * 120 ))" +'%Y-%m-%d %H:%M:%S'`" \ + t=$(( 1231006505 + $i * 120 )) + faketime "`date -d @$t +'%Y-%m-%d %H:%M:%S'`" \ bitcoind -connect=0 -nocheckpoints -stopatheight=$i done ``` @@ -21,7 +22,9 @@ done The CPU miner is kept running as follows: ```sh -./minerd --coinbase-addr 1NQpH6Nf8QtR2HphLRcvuVqfhXBXsiWn8r --no-stratum --algo sha256d --no-longpoll --scantime 3 --retry-pause 1 +./minerd -u ... -p ... -o http://127.0.0.1:8332 --no-stratum \ + --coinbase-addr 1NQpH6Nf8QtR2HphLRcvuVqfhXBXsiWn8r \ + --algo sha256d --no-longpoll --scantime 3 --retry-pause 1 ``` The payout address is derived from first BIP32 test vector master key: @@ -40,3 +43,8 @@ The timestamp was not kept constant because at difficulty 1 it's not sufficient to only grind the nonce. Grinding the extra_nonce or version field instead would have required additional (stratum) software. It would also make it more complicated to reconstruct the blocks in this test. + +The `getblocktemplate` RPC code needs to be patched to ignore not being connected +to any peers, and to ignore the IBD status check. + +On macOS use `faketime "@$t"` instead. diff --git a/test/functional/data/mainnet_alt.json b/test/functional/data/mainnet_alt.json index a4a072d2c5b..96821a36f41 100644 --- a/test/functional/data/mainnet_alt.json +++ b/test/functional/data/mainnet_alt.json @@ -2014,7 +2014,8 @@ 1231247971, 1231248071, 1231248198, - 1231248322 + 1231248322, + 1231248621 ], "nonces": [ 2345621585, @@ -4031,6 +4032,7 @@ 3658502865, 2519048297, 1915965760, - 1183846025 + 1183846025, + 2713372123 ] } diff --git a/test/functional/mempool_datacarrier.py b/test/functional/mempool_datacarrier.py index 40d3d2b3ab9..ca113fcbceb 100755 --- a/test/functional/mempool_datacarrier.py +++ b/test/functional/mempool_datacarrier.py @@ -100,17 +100,5 @@ class DataCarrierTest(BitcoinTestFramework): self.test_null_data_transaction(node=self.nodes[2], data=one_byte, success=True) self.test_null_data_transaction(node=self.nodes[3], data=one_byte, success=False) - # Clean shutdown boilerplate due to deprecation - self.expected_stderr = [ - "", # node 0 has no deprecated options - "Warning: Options '-datacarrier' or '-datacarriersize' are set but are marked as deprecated and are expected to be removed in a future version.", - "Warning: Options '-datacarrier' or '-datacarriersize' are set but are marked as deprecated and are expected to be removed in a future version.", - "Warning: Options '-datacarrier' or '-datacarriersize' are set but are marked as deprecated and are expected to be removed in a future version.", - ] - - for i in range(self.num_nodes): - self.stop_node(i, expected_stderr=self.expected_stderr[i]) - - if __name__ == '__main__': DataCarrierTest(__file__).main() diff --git a/test/functional/mempool_truc.py b/test/functional/mempool_truc.py index 562afcd34dd..098631b5c41 100755 --- a/test/functional/mempool_truc.py +++ b/test/functional/mempool_truc.py @@ -165,23 +165,36 @@ class MempoolTRUC(BitcoinTestFramework): def test_truc_reorg(self): node = self.nodes[0] self.log.info("Test that, during a reorg, TRUC rules are not enforced") - tx_v2_block = self.wallet.send_self_transfer(from_node=node, version=2) - tx_v3_block = self.wallet.send_self_transfer(from_node=node, version=3) - tx_v3_block2 = self.wallet.send_self_transfer(from_node=node, version=3) - self.check_mempool([tx_v3_block["txid"], tx_v2_block["txid"], tx_v3_block2["txid"]]) + self.check_mempool([]) + + # Testing 2<-3 versions allowed + tx_v2_block = self.wallet.create_self_transfer(version=2) + + # Testing 3<-2 versions allowed + tx_v3_block = self.wallet.create_self_transfer(version=3) + + # Testing overly-large child size + tx_v3_block2 = self.wallet.create_self_transfer(version=3) + + # Also create a linear chain of 3 TRUC transactions that will be directly mined, followed by one v2 in-mempool after block is made + tx_chain_1 = self.wallet.create_self_transfer(version=3) + tx_chain_2 = self.wallet.create_self_transfer(utxo_to_spend=tx_chain_1["new_utxo"], version=3) + tx_chain_3 = self.wallet.create_self_transfer(utxo_to_spend=tx_chain_2["new_utxo"], version=3) + + tx_to_mine = [tx_v3_block["hex"], tx_v2_block["hex"], tx_v3_block2["hex"], tx_chain_1["hex"], tx_chain_2["hex"], tx_chain_3["hex"]] + block = self.generateblock(node, output="raw(42)", transactions=tx_to_mine) - block = self.generate(node, 1) self.check_mempool([]) tx_v2_from_v3 = self.wallet.send_self_transfer(from_node=node, utxo_to_spend=tx_v3_block["new_utxo"], version=2) tx_v3_from_v2 = self.wallet.send_self_transfer(from_node=node, utxo_to_spend=tx_v2_block["new_utxo"], version=3) tx_v3_child_large = self.wallet.send_self_transfer(from_node=node, utxo_to_spend=tx_v3_block2["new_utxo"], target_vsize=1250, version=3) assert_greater_than(node.getmempoolentry(tx_v3_child_large["txid"])["vsize"], TRUC_CHILD_MAX_VSIZE) - self.check_mempool([tx_v2_from_v3["txid"], tx_v3_from_v2["txid"], tx_v3_child_large["txid"]]) - node.invalidateblock(block[0]) - self.check_mempool([tx_v3_block["txid"], tx_v2_block["txid"], tx_v3_block2["txid"], tx_v2_from_v3["txid"], tx_v3_from_v2["txid"], tx_v3_child_large["txid"]]) - # This is needed because generate() will create the exact same block again. - node.reconsiderblock(block[0]) + tx_chain_4 = self.wallet.send_self_transfer(from_node=node, utxo_to_spend=tx_chain_3["new_utxo"], version=2) + self.check_mempool([tx_v2_from_v3["txid"], tx_v3_from_v2["txid"], tx_v3_child_large["txid"], tx_chain_4["txid"]]) + # Reorg should have all block transactions re-accepted, ignoring TRUC enforcement + node.invalidateblock(block["hash"]) + self.check_mempool([tx_v3_block["txid"], tx_v2_block["txid"], tx_v3_block2["txid"], tx_v2_from_v3["txid"], tx_v3_from_v2["txid"], tx_v3_child_large["txid"], tx_chain_1["txid"], tx_chain_2["txid"], tx_chain_3["txid"], tx_chain_4["txid"]]) @cleanup(extra_args=["-limitdescendantsize=10"]) def test_nondefault_package_limits(self): diff --git a/test/functional/mining_mainnet.py b/test/functional/mining_mainnet.py index dbe6248fd74..672191006d2 100755 --- a/test/functional/mining_mainnet.py +++ b/test/functional/mining_mainnet.py @@ -53,15 +53,15 @@ class MiningMainnetTest(BitcoinTestFramework): help='Block data file (default: %(default)s)', ) - def mine(self, height, prev_hash, blocks, node, fees=0): + def mine(self, height, prev_hash, blocks, node): self.log.debug(f"height={height}") block = CBlock() block.nVersion = 0x20000000 block.hashPrevBlock = int(prev_hash, 16) block.nTime = blocks['timestamps'][height - 1] - block.nBits = DIFF_1_N_BITS + block.nBits = DIFF_1_N_BITS if height < 2016 else DIFF_4_N_BITS block.nNonce = blocks['nonces'][height - 1] - block.vtx = [create_coinbase(height=height, script_pubkey=bytes.fromhex(COINBASE_SCRIPT_PUBKEY), retarget_period=2016)] + block.vtx = [create_coinbase(height=height, script_pubkey=bytes.fromhex(COINBASE_SCRIPT_PUBKEY), halving_period=210000)] # The alternate mainnet chain was mined with non-timelocked coinbase txs. block.vtx[0].nLockTime = 0 block.vtx[0].vin[0].nSequence = SEQUENCE_FINAL @@ -82,12 +82,15 @@ class MiningMainnetTest(BitcoinTestFramework): self.log.info("Load alternative mainnet blocks") path = os.path.join(os.path.dirname(os.path.realpath(__file__)), self.options.datafile) prev_hash = node.getbestblockhash() + blocks = None with open(path, encoding='utf-8') as f: blocks = json.load(f) n_blocks = len(blocks['timestamps']) - assert_equal(n_blocks, 2015) - for i in range(2015): - prev_hash = self.mine(i + 1, prev_hash, blocks, node) + assert_equal(n_blocks, 2016) + + # Mine up to the last block of the first retarget period + for i in range(2015): + prev_hash = self.mine(i + 1, prev_hash, blocks, node) assert_equal(node.getblockcount(), 2015) @@ -102,5 +105,21 @@ class MiningMainnetTest(BitcoinTestFramework): assert_equal(mining_info['next']['bits'], nbits_str(DIFF_4_N_BITS)) assert_equal(mining_info['next']['target'], target_str(DIFF_4_TARGET)) + # Mine first block of the second retarget period + height = 2016 + prev_hash = self.mine(height, prev_hash, blocks, node) + assert_equal(node.getblockcount(), height) + + mining_info = node.getmininginfo() + assert_equal(mining_info['difficulty'], 4) + + self.log.info("getblock RPC should show historical target") + block_info = node.getblock(node.getblockhash(1)) + + assert_equal(block_info['difficulty'], 1) + assert_equal(block_info['bits'], nbits_str(DIFF_1_N_BITS)) + assert_equal(block_info['target'], target_str(DIFF_1_TARGET)) + + if __name__ == '__main__': MiningMainnetTest(__file__).main() diff --git a/test/functional/test_framework/blocktools.py b/test/functional/test_framework/blocktools.py index fa4182c6cf9..eb1d3b0542b 100644 --- a/test/functional/test_framework/blocktools.py +++ b/test/functional/test_framework/blocktools.py @@ -144,7 +144,7 @@ def script_BIP34_coinbase_height(height): return CScript([CScriptNum(height)]) -def create_coinbase(height, pubkey=None, *, script_pubkey=None, extra_output_script=None, fees=0, nValue=50, retarget_period=REGTEST_RETARGET_PERIOD): +def create_coinbase(height, pubkey=None, *, script_pubkey=None, extra_output_script=None, fees=0, nValue=50, halving_period=REGTEST_RETARGET_PERIOD): """Create a coinbase transaction. If pubkey is passed in, the coinbase output will be a P2PK output; @@ -158,7 +158,7 @@ def create_coinbase(height, pubkey=None, *, script_pubkey=None, extra_output_scr coinbaseoutput = CTxOut() coinbaseoutput.nValue = nValue * COIN if nValue == 50: - halvings = int(height / retarget_period) + halvings = int(height / halving_period) coinbaseoutput.nValue >>= halvings coinbaseoutput.nValue += fees if pubkey is not None: