diff --git a/ci/test/00_setup_env_native_centos.sh b/ci/test/00_setup_env_native_centos.sh index af27a5ebe1b7..4ab106f94fa7 100755 --- a/ci/test/00_setup_env_native_centos.sh +++ b/ci/test/00_setup_env_native_centos.sh @@ -10,6 +10,5 @@ export CONTAINER_NAME=ci_native_centos export CI_IMAGE_NAME_TAG="quay.io/centos/centos:stream10" export CI_BASE_PACKAGES="gcc-c++ glibc-devel libstdc++-devel ccache make git python3 python3-pip which patch xz procps-ng rsync coreutils bison e2fsprogs cmake dash" export PIP_PACKAGES="pyzmq" -export DEP_OPTS="DEBUG=1" # Temporarily enable a DEBUG=1 build to check for GCC-bug-117966 regressions. This can be removed once the minimum GCC version is bumped to 12 in the previous releases task, see https://github.com/bitcoin/bitcoin/issues/31436#issuecomment-2530717875 export GOAL="install" export BITCOIN_CONFIG="-DWITH_ZMQ=ON -DBUILD_GUI=ON -DREDUCE_EXPORTS=ON -DCMAKE_BUILD_TYPE=Debug" diff --git a/depends/packages/libevent.mk b/depends/packages/libevent.mk index 1f139b1eec81..f8816fddc6be 100644 --- a/depends/packages/libevent.mk +++ b/depends/packages/libevent.mk @@ -4,6 +4,7 @@ $(package)_download_path=https://github.com/libevent/libevent/releases/download/ $(package)_file_name=$(package)-$($(package)_version).tar.gz $(package)_sha256_hash=92e6de1be9ec176428fd2367677e61ceffc2ee1cb119035037a27d346b0403bb $(package)_patches=cmake_fixups.patch +$(package)_patches += ignore_git_describe.patch $(package)_patches += netbsd_fixup.patch $(package)_patches += winver_fixup.patch $(package)_build_subdir=build @@ -26,6 +27,7 @@ endef define $(package)_preprocess_cmds patch -p1 < $($(package)_patch_dir)/cmake_fixups.patch && \ + patch -p1 < $($(package)_patch_dir)/ignore_git_describe.patch && \ patch -p1 < $($(package)_patch_dir)/netbsd_fixup.patch && \ patch -p1 < $($(package)_patch_dir)/winver_fixup.patch endef diff --git a/depends/patches/libevent/ignore_git_describe.patch b/depends/patches/libevent/ignore_git_describe.patch new file mode 100644 index 000000000000..833757182e44 --- /dev/null +++ b/depends/patches/libevent/ignore_git_describe.patch @@ -0,0 +1,11 @@ +--- a/cmake/VersionViaGit.cmake ++++ b/cmake/VersionViaGit.cmake +@@ -28,7 +28,7 @@ macro(event_fuzzy_version_from_git) + + find_package(Git) + +- if (GIT_FOUND) ++ if (0) + execute_process( + COMMAND + ${GIT_EXECUTABLE} describe --abbrev=0 --always diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index 75911d00874d..8164cc6cee4c 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -477,7 +477,7 @@ class NetinfoRequestHandler : public BaseRequestHandler std::string str; for (size_t i = 0; i < services.size(); ++i) { const std::string s{services[i].get_str()}; - str += s == "NETWORK_LIMITED" ? 'l' : s == "P2P_V2" ? '2' : ToLower(s[0]); + str += s == "NETWORK_LIMITED" ? 'l' : s == "P2P_V2" ? '2' : s == "UASF_REDUCED_DATA?" ? '4' : ToLower(s[0]); } return str; } @@ -713,6 +713,7 @@ class NetinfoRequestHandler : public BaseRequestHandler " \"c\" - COMPACT_FILTERS: peer can handle basic block filter requests (see BIPs 157 and 158)\n" " \"l\" - NETWORK_LIMITED: peer limited to serving only the last 288 blocks (~2 days)\n" " \"2\" - P2P_V2: peer supports version 2 P2P transport protocol, as defined in BIP 324\n" + " \"4\" - UASF_REDUCED_DATA? peer enforces the ReducedData User-Activated SoftFork\n" " \"u\" - UNKNOWN: unrecognized bit flag\n" " v Version of transport protocol used for the connection\n" " mping Minimum observed ping time, in milliseconds (ms)\n" diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 7cf28d69b420..4affdbfe8c15 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -68,8 +68,8 @@ void ReadRegTestArgs(const ArgsManager& args, CChainParams::RegTestOptions& opti for (const std::string& strDeployment : args.GetArgs("-vbparams")) { std::vector vDeploymentParams = SplitString(strDeployment, ':'); - if (vDeploymentParams.size() < 3 || 4 < vDeploymentParams.size()) { - throw std::runtime_error("Version bits parameters malformed, expecting deployment:start:end[:min_activation_height]"); + if (vDeploymentParams.size() < 3 || 7 < vDeploymentParams.size()) { + throw std::runtime_error("Version bits parameters malformed, expecting deployment:start:end[:min_activation_height[:max_activation_height[:active_duration[:threshold]]]]"); } CChainParams::VersionBitsParameters vbparams{}; if (!ParseInt64(vDeploymentParams[1], &vbparams.start_time)) { @@ -85,12 +85,31 @@ void ReadRegTestArgs(const ArgsManager& args, CChainParams::RegTestOptions& opti } else { vbparams.min_activation_height = 0; } + if (vDeploymentParams.size() >= 5) { + if (!ParseInt32(vDeploymentParams[4], &vbparams.max_activation_height)) { + throw std::runtime_error(strprintf("Invalid max_activation_height (%s)", vDeploymentParams[4])); + } + } + if (vDeploymentParams.size() >= 6) { + if (!ParseInt32(vDeploymentParams[5], &vbparams.active_duration)) { + throw std::runtime_error(strprintf("Invalid active_duration (%s)", vDeploymentParams[5])); + } + } + if (vDeploymentParams.size() >= 7) { + if (!ParseInt32(vDeploymentParams[6], &vbparams.threshold)) { + throw std::runtime_error(strprintf("Invalid threshold (%s)", vDeploymentParams[6])); + } + } + // Validate that timeout and max_activation_height are mutually exclusive + if (vbparams.timeout != Consensus::BIP9Deployment::NO_TIMEOUT && vbparams.max_activation_height < std::numeric_limits::max()) { + throw std::runtime_error(strprintf("Cannot specify both timeout (%ld) and max_activation_height (%d) for deployment %s. Use timeout for BIP9 or max_activation_height for UASF, not both.", vbparams.timeout, vbparams.max_activation_height, vDeploymentParams[0])); + } bool found = false; for (int j=0; j < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; ++j) { if (vDeploymentParams[0] == VersionBitsDeploymentInfo[j].name) { options.version_bits_parameters[Consensus::DeploymentPos(j)] = vbparams; found = true; - LogPrintf("Setting version bits activation parameters for %s to start=%ld, timeout=%ld, min_activation_height=%d\n", vDeploymentParams[0], vbparams.start_time, vbparams.timeout, vbparams.min_activation_height); + LogPrintf("Setting version bits activation parameters for %s to start=%ld, timeout=%ld, min_activation_height=%d, max_activation_height=%d, active_duration=%d, threshold=%d\n", vDeploymentParams[0], vbparams.start_time, vbparams.timeout, vbparams.min_activation_height, vbparams.max_activation_height, vbparams.active_duration, vbparams.threshold); break; } } diff --git a/src/clientversion.cpp b/src/clientversion.cpp index 10e9472b84ba..9d6f2ce5f304 100644 --- a/src/clientversion.cpp +++ b/src/clientversion.cpp @@ -66,7 +66,7 @@ std::string FormatSubVersion(const std::string& name, int nClientVersion, const { std::string comments_str; if (!comments.empty()) comments_str = strprintf("(%s)", Join(comments, "; ")); - return strprintf("/%s:%s%s/", name, FormatVersion(nClientVersion), comments_str); + return strprintf("/%s:%s%s/%s/", name, FormatVersion(nClientVersion), comments_str, "UASF-BIP110:0.3"); } std::string CopyrightHolders(const std::string& strPrefix) diff --git a/src/consensus/consensus.h b/src/consensus/consensus.h index cffe9cdafd79..b02773f4900b 100644 --- a/src/consensus/consensus.h +++ b/src/consensus/consensus.h @@ -34,4 +34,7 @@ static constexpr unsigned int LOCKTIME_VERIFY_SEQUENCE = (1 << 0); */ static constexpr int64_t MAX_TIMEWARP = 600; +static constexpr unsigned int MAX_OUTPUT_SCRIPT_SIZE{34}; +static constexpr unsigned int MAX_OUTPUT_DATA_SIZE{83}; + #endif // BITCOIN_CONSENSUS_CONSENSUS_H diff --git a/src/consensus/params.h b/src/consensus/params.h index dd29b9408e23..2dc76f770ad7 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -32,6 +32,7 @@ constexpr bool ValidDeployment(BuriedDeployment dep) { return dep <= DEPLOYMENT_ enum DeploymentPos : uint16_t { DEPLOYMENT_TESTDUMMY, DEPLOYMENT_TAPROOT, // Deployment of Schnorr/Taproot (BIPs 340-342) + DEPLOYMENT_REDUCED_DATA, // Temporary deployment of UASF-ReducedData // NOTE: Also add new deployments to VersionBitsDeploymentInfo in deploymentinfo.cpp MAX_VERSION_BITS_DEPLOYMENTS }; @@ -52,6 +53,16 @@ struct BIP9Deployment { * boundary. */ int min_activation_height{0}; + /** Maximum height for activation. If less than INT_MAX, the deployment will activate + * at this height regardless of signaling (similar to BIP8 flag day). + * std::numeric_limits::max() means no maximum (activation only via signaling). */ + int max_activation_height{std::numeric_limits::max()}; + /** For temporary softforks: number of blocks the deployment remains active after activation. + * std::numeric_limits::max() means permanent (never expires). */ + int active_duration{std::numeric_limits::max()}; + /** Per-deployment activation threshold. If 0, uses the global nRuleChangeActivationThreshold. + * Otherwise, specifies the number of blocks required for this specific deployment. */ + int threshold{0}; /** Constant for nTimeout very far in the future. */ static constexpr int64_t NO_TIMEOUT = std::numeric_limits::max(); diff --git a/src/consensus/tx_verify.cpp b/src/consensus/tx_verify.cpp index 95466b759cbb..84558503c708 100644 --- a/src/consensus/tx_verify.cpp +++ b/src/consensus/tx_verify.cpp @@ -161,7 +161,18 @@ int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& i return nSigOps; } -bool Consensus::CheckTxInputs(const CTransaction& tx, TxValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& txfee) +bool Consensus::CheckOutputSizes(const CTransaction& tx, TxValidationState& state) +{ + for (const auto& txout : tx.vout) { + if (txout.scriptPubKey.empty()) continue; + if (txout.scriptPubKey.size() > ((txout.scriptPubKey[0] == OP_RETURN) ? MAX_OUTPUT_DATA_SIZE : MAX_OUTPUT_SCRIPT_SIZE)) { + return state.Invalid(TxValidationResult::TX_PREMATURE_SPEND, "bad-txns-vout-script-toolarge"); + } + } + return true; +} + +bool Consensus::CheckTxInputs(const CTransaction& tx, TxValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& txfee, const CheckTxInputsRules rules) { // are the actual inputs available? if (!inputs.HaveInputs(tx)) { @@ -169,6 +180,11 @@ bool Consensus::CheckTxInputs(const CTransaction& tx, TxValidationState& state, strprintf("%s: inputs missing/spent", __func__)); } + // NOTE: CheckTransaction is arguably the more logical place to do this, but it's context-independent, so this is probably the next best place for now + if (rules.test(CheckTxInputsRules::OutputSizeLimit) && !CheckOutputSizes(tx, state)) { + return false; + } + CAmount nValueIn = 0; for (unsigned int i = 0; i < tx.vin.size(); ++i) { const COutPoint &prevout = tx.vin[i].prevout; diff --git a/src/consensus/tx_verify.h b/src/consensus/tx_verify.h index d2cf792cf3f6..4a95f49d2e90 100644 --- a/src/consensus/tx_verify.h +++ b/src/consensus/tx_verify.h @@ -17,14 +17,45 @@ class TxValidationState; /** Transaction validation functions */ +class CheckTxInputsRules { + using underlying_type = unsigned int; + underlying_type m_flags; + constexpr explicit CheckTxInputsRules(underlying_type flags) noexcept : m_flags(flags) {} + + enum class Rule { + None = 0, + OutputSizeLimit = 1 << 0, + }; + +public: + using enum Rule; + + constexpr CheckTxInputsRules(Rule rule) noexcept : m_flags(static_cast(rule)) {} + + [[nodiscard]] constexpr bool test(CheckTxInputsRules rules) const noexcept { + return (m_flags & rules.m_flags) == rules.m_flags; + } + + [[nodiscard]] constexpr CheckTxInputsRules operator|(const CheckTxInputsRules other) const noexcept { + return CheckTxInputsRules{m_flags | other.m_flags}; + } +}; + namespace Consensus { +/** + * Check whether all outputs of this transaction satisfy size limits. + * Regular outputs must be <= MAX_OUTPUT_SCRIPT_SIZE (34 bytes). + * OP_RETURN outputs must be <= MAX_OUTPUT_DATA_SIZE (83 bytes). + */ +[[nodiscard]] bool CheckOutputSizes(const CTransaction& tx, TxValidationState& state); + /** * Check whether all inputs of this transaction are valid (no double spends and amounts) * This does not modify the UTXO set. This does not check scripts and sigs. * @param[out] txfee Set to the transaction fee if successful. * Preconditions: tx.IsCoinBase() is false. */ -[[nodiscard]] bool CheckTxInputs(const CTransaction& tx, TxValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& txfee); +[[nodiscard]] bool CheckTxInputs(const CTransaction& tx, TxValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& txfee, CheckTxInputsRules rules); } // namespace Consensus /** Auxiliary functions for transaction validation (ideally should not be exposed) */ diff --git a/src/deploymentinfo.cpp b/src/deploymentinfo.cpp index 185a7dcb54ce..200f5fd26300 100644 --- a/src/deploymentinfo.cpp +++ b/src/deploymentinfo.cpp @@ -17,6 +17,10 @@ const struct VBDeploymentInfo VersionBitsDeploymentInfo[Consensus::MAX_VERSION_B /*.name =*/ "taproot", /*.gbt_force =*/ true, }, + { + /*.name =*/ "reduced_data", + /*.gbt_force =*/ true, + }, }; std::string DeploymentName(Consensus::BuriedDeployment dep) diff --git a/src/deploymentstatus.h b/src/deploymentstatus.h index 03d3c531ccec..550f38154bd6 100644 --- a/src/deploymentstatus.h +++ b/src/deploymentstatus.h @@ -20,7 +20,15 @@ inline bool DeploymentActiveAfter(const CBlockIndex* pindexPrev, const Consensus inline bool DeploymentActiveAfter(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos dep, VersionBitsCache& versionbitscache) { assert(Consensus::ValidDeployment(dep)); - return ThresholdState::ACTIVE == versionbitscache.State(pindexPrev, params, dep); + if (ThresholdState::ACTIVE != versionbitscache.State(pindexPrev, params, dep)) return false; + + const auto& deployment = params.vDeployments[dep]; + // Permanent deployment (never expires) + if (deployment.active_duration == std::numeric_limits::max()) return true; + + const int activation_height = versionbitscache.StateSinceHeight(pindexPrev, params, dep); + const int height = pindexPrev == nullptr ? 0 : pindexPrev->nHeight + 1; + return height < activation_height + deployment.active_duration; } /** Determine if a deployment is active for this block */ diff --git a/src/init.cpp b/src/init.cpp index 70615a191be1..a77be1356fb4 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -636,8 +636,8 @@ void SetupServerArgs(ArgsManager& argsman, bool can_listen_ipc) 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("Relay and mine data carrier transactions (default: %u)", DEFAULT_ACCEPT_DATACARRIER), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY); argsman.AddArg("-datacarriersize", - strprintf("Relay and mine transactions whose data-carrying raw scriptPubKey " - "is of this size or less (default: %u)", + strprintf("Maximum size of data in data carrier transactions we relay and mine, in bytes (maximum %s, default: %u)", + MAX_OUTPUT_DATA_SIZE, MAX_OP_RETURN_RELAY), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY); argsman.AddArg("-permitbaremultisig", strprintf("Relay transactions creating non-P2SH multisig outputs (default: %u)", DEFAULT_PERMIT_BAREMULTISIG), ArgsManager::ALLOW_ANY, @@ -837,7 +837,7 @@ namespace { // Variables internal to initialization process only int nMaxConnections; int available_fds; -ServiceFlags g_local_services = ServiceFlags(NODE_NETWORK_LIMITED | NODE_WITNESS); +ServiceFlags g_local_services = ServiceFlags(NODE_NETWORK_LIMITED | NODE_WITNESS | NODE_UASF_REDUCED_DATA); int64_t peer_connect_timeout; std::set g_enabled_filter_types; diff --git a/src/kernel/chainparams.cpp b/src/kernel/chainparams.cpp index 0f193eff74d9..dc3f22a95335 100644 --- a/src/kernel/chainparams.cpp +++ b/src/kernel/chainparams.cpp @@ -97,7 +97,7 @@ class CMainParams : public CChainParams { consensus.BIP66Height = 363725; // 00000000000000000379eaa19dce8c9b722d46ae6a57c2f1a988119488b50931 consensus.CSVHeight = 419328; // 000000000000000004a1b34462cb8aeebd5799177f7a29cf28f2d1961716b5b5 consensus.SegwitHeight = 481824; // 0000000000000000001c8018d9cb3b742ef25114f27563e3fc4a1902167f9893 - consensus.MinBIP9WarningHeight = 483840; // segwit activation height + miner confirmation window + consensus.MinBIP9WarningHeight = 711648; // taproot activation height + miner confirmation window consensus.powLimit = uint256{"00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff"}; consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks consensus.nPowTargetSpacing = 10 * 60; @@ -117,9 +117,19 @@ class CMainParams : public CChainParams { consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nTimeout = 1628640000; // August 11th, 2021 consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].min_activation_height = 709632; // Approximately November 12th, 2021 + consensus.nMinimumChainWork = uint256{"0000000000000000000000000000000000000000b1f3b93b65b16d035a82be84"}; consensus.defaultAssumeValid = uint256{"00000000000000000001b658dd1120e82e66d2790811f89ede9742ada3ed6d77"}; // 886157 + // Deployment of UASF-ReducedData (temporary UASF) + consensus.vDeployments[Consensus::DEPLOYMENT_REDUCED_DATA].bit = 4; + consensus.vDeployments[Consensus::DEPLOYMENT_REDUCED_DATA].nStartTime = 1764547200; // December 1st, 2025 + consensus.vDeployments[Consensus::DEPLOYMENT_REDUCED_DATA].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; + consensus.vDeployments[Consensus::DEPLOYMENT_REDUCED_DATA].min_activation_height = 0; + consensus.vDeployments[Consensus::DEPLOYMENT_REDUCED_DATA].max_activation_height = 965664; // ~September 1st, 2026 + consensus.vDeployments[Consensus::DEPLOYMENT_REDUCED_DATA].active_duration = 52416; // ~1 year + consensus.vDeployments[Consensus::DEPLOYMENT_REDUCED_DATA].threshold = 1109; // 55% of 2016 + /** * The message start string is designed to be unlikely to occur in normal data. * The characters are rarely used upper ASCII, not valid as UTF-8, and produce @@ -146,6 +156,8 @@ class CMainParams : public CChainParams { // release ASAP to avoid it where possible. vSeeds.emplace_back("seed.bitcoin.sipa.be."); // Pieter Wuille, only supports x1, x5, x9, and xd vSeeds.emplace_back("dnsseed.bluematt.me."); // Matt Corallo, only supports x9 + vSeeds.emplace_back("dnsseed.bitcoin.dashjr-list-of-p2p-nodes.us."); // Luke Dashjr, support BIP110 seeding (x8000009) + vSeeds.emplace_back("seed.bitcoin.haf.ovh."); // Léo Haf, support BIP110 seeding (x8000009) vSeeds.emplace_back("seed.bitcoin.jonasschnelli.ch."); // Jonas Schnelli, only supports x1, x5, x9, and xd vSeeds.emplace_back("seed.btc.petertodd.net."); // Peter Todd, only supports x1, x5, x9, and xd vSeeds.emplace_back("seed.bitcoin.sprovoost.nl."); // Sjors Provoost @@ -246,6 +258,14 @@ class CTestNetParams : public CChainParams { consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nTimeout = 1628640000; // August 11th, 2021 consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].min_activation_height = 0; // No activation delay + // Deployment of UASF-ReducedData (temporary UASF) + consensus.vDeployments[Consensus::DEPLOYMENT_REDUCED_DATA].bit = 4; + consensus.vDeployments[Consensus::DEPLOYMENT_REDUCED_DATA].nStartTime = 1764547200; // December 1st, 2025 + consensus.vDeployments[Consensus::DEPLOYMENT_REDUCED_DATA].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; + consensus.vDeployments[Consensus::DEPLOYMENT_REDUCED_DATA].min_activation_height = 0; + consensus.vDeployments[Consensus::DEPLOYMENT_REDUCED_DATA].active_duration = 52416; // ~1 year + consensus.vDeployments[Consensus::DEPLOYMENT_REDUCED_DATA].threshold = 1109; // 55% of 2016 + consensus.nMinimumChainWork = uint256{"0000000000000000000000000000000000000000000015f5e0c9f13455b0eb17"}; consensus.defaultAssumeValid = uint256{"00000000000003fc7967410ba2d0a8a8d50daedc318d43e8baf1a9782c236a57"}; // 3974606 @@ -345,6 +365,14 @@ class CTestNet4Params : public CChainParams { consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].min_activation_height = 0; // No activation delay + // Deployment of UASF-ReducedData (temporary UASF) + consensus.vDeployments[Consensus::DEPLOYMENT_REDUCED_DATA].bit = 4; + consensus.vDeployments[Consensus::DEPLOYMENT_REDUCED_DATA].nStartTime = 1764547200; // December 1st, 2025 + consensus.vDeployments[Consensus::DEPLOYMENT_REDUCED_DATA].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; + consensus.vDeployments[Consensus::DEPLOYMENT_REDUCED_DATA].min_activation_height = 0; + consensus.vDeployments[Consensus::DEPLOYMENT_REDUCED_DATA].active_duration = 52416; // ~1 year + consensus.vDeployments[Consensus::DEPLOYMENT_REDUCED_DATA].threshold = 1109; // 55% of 2016 + consensus.nMinimumChainWork = uint256{"0000000000000000000000000000000000000000000001d6dce8651b6094e4c1"}; consensus.defaultAssumeValid = uint256{"0000000000003ed4f08dbdf6f7d6b271a6bcffce25675cb40aa9fa43179a89f3"}; // 72600 @@ -483,6 +511,11 @@ class SigNetParams : public CChainParams { consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].min_activation_height = 0; // No activation delay + consensus.vDeployments[Consensus::DEPLOYMENT_REDUCED_DATA].bit = 4; + consensus.vDeployments[Consensus::DEPLOYMENT_REDUCED_DATA].nStartTime = Consensus::BIP9Deployment::NEVER_ACTIVE; + consensus.vDeployments[Consensus::DEPLOYMENT_REDUCED_DATA].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; + consensus.vDeployments[Consensus::DEPLOYMENT_REDUCED_DATA].min_activation_height = 0; + // message start is defined as the first 4 bytes of the sha256d of the block script HashWriter h{}; h << consensus.signet_challenge; @@ -558,6 +591,11 @@ class CRegTestParams : public CChainParams consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].min_activation_height = 0; // No activation delay + consensus.vDeployments[Consensus::DEPLOYMENT_REDUCED_DATA].bit = 4; + consensus.vDeployments[Consensus::DEPLOYMENT_REDUCED_DATA].nStartTime = Consensus::BIP9Deployment::NEVER_ACTIVE; + consensus.vDeployments[Consensus::DEPLOYMENT_REDUCED_DATA].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; + consensus.vDeployments[Consensus::DEPLOYMENT_REDUCED_DATA].min_activation_height = 0; + consensus.nMinimumChainWork = uint256{}; consensus.defaultAssumeValid = uint256{}; @@ -594,6 +632,9 @@ class CRegTestParams : public CChainParams consensus.vDeployments[deployment_pos].nStartTime = version_bits_params.start_time; consensus.vDeployments[deployment_pos].nTimeout = version_bits_params.timeout; consensus.vDeployments[deployment_pos].min_activation_height = version_bits_params.min_activation_height; + consensus.vDeployments[deployment_pos].max_activation_height = version_bits_params.max_activation_height; + consensus.vDeployments[deployment_pos].active_duration = version_bits_params.active_duration; + consensus.vDeployments[deployment_pos].threshold = version_bits_params.threshold; } genesis = CreateGenesisBlock(1296688602, 2, 0x207fffff, 1, 50 * COIN); diff --git a/src/kernel/chainparams.h b/src/kernel/chainparams.h index f7ea141c37c3..412cf74a8783 100644 --- a/src/kernel/chainparams.h +++ b/src/kernel/chainparams.h @@ -146,6 +146,9 @@ class CChainParams int64_t start_time; int64_t timeout; int min_activation_height; + int max_activation_height{std::numeric_limits::max()}; + int active_duration{std::numeric_limits::max()}; + int threshold{0}; // 0 means use global nRuleChangeActivationThreshold }; /** diff --git a/src/net.cpp b/src/net.cpp index 7684877ec352..2706637804ad 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2264,7 +2264,7 @@ void CConnman::ThreadDNSAddressSeed() break; } - outbound_connection_count = GetFullOutboundConnCount(); + outbound_connection_count = GetBIP110FullOutboundConnCount(); if (outbound_connection_count >= SEED_OUTBOUND_CONNECTION_THRESHOLD) { LogPrintf("P2P peers available. Finished fetching data from seed nodes.\n"); break; @@ -2319,7 +2319,7 @@ void CConnman::ThreadDNSAddressSeed() if (!interruptNet.sleep_for(w)) return; to_wait -= w; - if (GetFullOutboundConnCount() >= SEED_OUTBOUND_CONNECTION_THRESHOLD) { + if (GetBIP110FullOutboundConnCount() >= SEED_OUTBOUND_CONNECTION_THRESHOLD) { if (found > 0) { LogPrintf("%d addresses found from DNS seeds\n", found); LogPrintf("P2P peers available. Finished DNS seeding.\n"); @@ -2432,14 +2432,15 @@ void CConnman::StartExtraBlockRelayPeers() m_start_extra_block_relay_peers = true; } -// Return the number of outbound connections that are full relay (not blocks only) -int CConnman::GetFullOutboundConnCount() const +// Return the number of BIP110 outbound connections that are full relay (not blocks only). +// Non-BIP110 outbound peers are excluded as they are "additional" and don't count toward limits. +int CConnman::GetBIP110FullOutboundConnCount() const { int nRelevant = 0; { LOCK(m_nodes_mutex); for (const CNode* pnode : m_nodes) { - if (pnode->fSuccessfullyConnected && pnode->IsFullOutboundConn()) ++nRelevant; + if (pnode->fSuccessfullyConnected && pnode->IsFullOutboundConn() && !pnode->m_is_non_bip110_outbound) ++nRelevant; } } return nRelevant; @@ -2642,7 +2643,8 @@ void CConnman::ThreadOpenConnections(const std::vector connect, Spa { LOCK(m_nodes_mutex); for (const CNode* pnode : m_nodes) { - if (pnode->IsFullOutboundConn()) nOutboundFullRelay++; + // Non-BIP110 outbound peers are "additional" - don't count toward limits + if (pnode->IsFullOutboundConn() && !pnode->m_is_non_bip110_outbound) nOutboundFullRelay++; if (pnode->IsBlockOnlyConn()) nOutboundBlockRelay++; // Make sure our persistent outbound slots to ipv4/ipv6 peers belong to different netgroups. diff --git a/src/net.h b/src/net.h index e025b20bcdef..f0e407912b87 100644 --- a/src/net.h +++ b/src/net.h @@ -850,6 +850,10 @@ class CNode /** Whether this peer provides all services that we want. Used for eviction decisions */ std::atomic_bool m_has_all_wanted_services{false}; + /** Whether this is a non-BIP110 outbound peer (lacks NODE_UASF_REDUCED_DATA). + * Used to exclude from outbound connection counts. Limited to 2 such peers. */ + std::atomic_bool m_is_non_bip110_outbound{false}; + /** Whether we should relay transactions to this peer. This only changes * from false to true. It will never change back to false. */ std::atomic_bool m_relays_txs{false}; @@ -1191,8 +1195,8 @@ class CConnman void StartExtraBlockRelayPeers(); - // Count the number of full-relay peer we have. - int GetFullOutboundConnCount() const; + // Count the number of BIP110 full-relay peers we have (excludes non-BIP110 peers). + int GetBIP110FullOutboundConnCount() const; // Return the number of outbound peers we have in excess of our target (eg, // if we previously called SetTryNewOutboundPeer(true), and have since set // to false, we may have extra peers that we wish to disconnect). This may diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 049812763716..3b3df0cc5aee 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -796,6 +796,9 @@ class PeerManagerImpl final : public PeerManager /** Number of peers with wtxid relay. */ std::atomic m_wtxid_relay_peers{0}; + /** Number of outbound peers without NODE_UASF_REDUCED_DATA (BIP-110). Limited to 2. */ + std::atomic m_num_non_bip110_outbound{0}; + /** Number of outbound peers with m_chain_sync.m_protect. */ int m_outbound_peers_with_protect_from_disconnect GUARDED_BY(cs_main) = 0; @@ -1572,6 +1575,11 @@ void PeerManagerImpl::FinalizeNode(const CNode& node) assert(peer != nullptr); m_wtxid_relay_peers -= peer->m_wtxid_relay; assert(m_wtxid_relay_peers >= 0); + // Decrement non-BIP110 counter if this was a non-BIP110 outbound peer + if (node.m_is_non_bip110_outbound) { + --m_num_non_bip110_outbound; + assert(m_num_non_bip110_outbound >= 0); + } } CNodeState *state = State(nodeid); assert(state != nullptr); @@ -3450,6 +3458,19 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, } pfrom.m_has_all_wanted_services = HasAllDesirableServiceFlags(nServices); + // BIP-110: Allow up to 2 non-BIP110 outbound peers. + if (pfrom.ExpectServicesFromConn() && !(nServices & NODE_UASF_REDUCED_DATA)) { + if (m_num_non_bip110_outbound >= 2) { + LogDebug(BCLog::NET, "peer lacks NODE_UASF_REDUCED_DATA and already have 2 non-BIP110 outbound peers, %s\n", + pfrom.DisconnectMsg(fLogIPs)); + pfrom.fDisconnect = true; + return; + } + ++m_num_non_bip110_outbound; + pfrom.m_is_non_bip110_outbound = true; + LogDebug(BCLog::NET, "connected to non-BIP110 outbound peer (%d/2), %s\n", + m_num_non_bip110_outbound.load(), pfrom.ConnectionTypeAsString()); + } peer->m_their_services = nServices; pfrom.SetAddrLocal(addrMe); { diff --git a/src/node/mempool_args.cpp b/src/node/mempool_args.cpp index f2241f0caf51..ac72dca61150 100644 --- a/src/node/mempool_args.cpp +++ b/src/node/mempool_args.cpp @@ -93,6 +93,10 @@ util::Result ApplyArgsManOptions(const ArgsManager& argsman, const CChainP if (argsman.GetBoolArg("-datacarrier", DEFAULT_ACCEPT_DATACARRIER)) { mempool_opts.max_datacarrier_bytes = argsman.GetIntArg("-datacarriersize", MAX_OP_RETURN_RELAY); + if (mempool_opts.max_datacarrier_bytes.value() > MAX_OUTPUT_DATA_SIZE) { + LogWarning("Limiting datacarriersize to %s", MAX_OUTPUT_DATA_SIZE); + mempool_opts.max_datacarrier_bytes = MAX_OUTPUT_DATA_SIZE; + } } else { mempool_opts.max_datacarrier_bytes = std::nullopt; } diff --git a/src/policy/policy.h b/src/policy/policy.h index a6ce608bcfad..7a6d1679bd1b 100644 --- a/src/policy/policy.h +++ b/src/policy/policy.h @@ -126,7 +126,8 @@ static constexpr unsigned int STANDARD_SCRIPT_VERIFY_FLAGS{MANDATORY_SCRIPT_VERI SCRIPT_VERIFY_CONST_SCRIPTCODE | SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION | SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS | - SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE}; + SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE | + REDUCED_DATA_MANDATORY_VERIFY_FLAGS}; /** For convenience, standard but not mandatory verify flags. */ static constexpr unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS{STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS}; diff --git a/src/protocol.cpp b/src/protocol.cpp index bdf0a669863a..8e3c22e4dee0 100644 --- a/src/protocol.cpp +++ b/src/protocol.cpp @@ -99,6 +99,7 @@ static std::string serviceFlagToStr(size_t bit) case NODE_COMPACT_FILTERS: return "COMPACT_FILTERS"; case NODE_NETWORK_LIMITED: return "NETWORK_LIMITED"; case NODE_P2P_V2: return "P2P_V2"; + case NODE_UASF_REDUCED_DATA: return "UASF_REDUCED_DATA?"; // Not using default, so we get warned when a case is missing } diff --git a/src/protocol.h b/src/protocol.h index 804597b86d88..052ff452bc7b 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -336,6 +336,9 @@ enum ServiceFlags : uint64_t { // collisions and other cases where nodes may be advertising a service they // do not actually support. Other service bits should be allocated via the // BIP process. + + // NODE_UASF_REDUCED_DATA means the node enforces UASFReducedData rules as applicable + NODE_UASF_REDUCED_DATA = (1 << 27), }; /** @@ -351,7 +354,7 @@ std::vector serviceFlagsToStr(uint64_t flags); * should be updated appropriately to filter for nodes with * desired service flags (compatible with our new flags). */ -constexpr ServiceFlags SeedsServiceFlags() { return ServiceFlags(NODE_NETWORK | NODE_WITNESS); } +constexpr ServiceFlags SeedsServiceFlags() { return ServiceFlags(NODE_NETWORK | NODE_WITNESS | NODE_UASF_REDUCED_DATA); } /** * Checks if a peer with the given service flags may be capable of having a diff --git a/src/psbt.h b/src/psbt.h index 6d49864b3cdb..88a22a84aeb4 100644 --- a/src/psbt.h +++ b/src/psbt.h @@ -872,7 +872,7 @@ struct PSBTOutput s_tree >> depth; s_tree >> leaf_ver; s_tree >> script; - if (depth > TAPROOT_CONTROL_MAX_NODE_COUNT) { + if (depth > TAPROOT_CONTROL_MAX_NODE_COUNT_REDUCED) { throw std::ios_base::failure("Output Taproot tree has as leaf greater than Taproot maximum depth"); } if ((leaf_ver & ~TAPROOT_LEAF_MASK) != 0) { diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index edda17d3697a..9182624b5feb 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -1249,6 +1249,9 @@ static void SoftForkDescPushBack(const CBlockIndex* blockindex, UniValue& softfo bip9.pushKV("start_time", chainman.GetConsensus().vDeployments[id].nStartTime); bip9.pushKV("timeout", chainman.GetConsensus().vDeployments[id].nTimeout); bip9.pushKV("min_activation_height", chainman.GetConsensus().vDeployments[id].min_activation_height); + if (chainman.GetConsensus().vDeployments[id].max_activation_height < std::numeric_limits::max()) { + bip9.pushKV("max_activation_height", chainman.GetConsensus().vDeployments[id].max_activation_height); + } // BIP9 status bip9.pushKV("status", get_state_name(current_state)); @@ -1280,7 +1283,13 @@ static void SoftForkDescPushBack(const CBlockIndex* blockindex, UniValue& softfo UniValue rv(UniValue::VOBJ); rv.pushKV("type", "bip9"); if (ThresholdState::ACTIVE == next_state) { - rv.pushKV("height", chainman.m_versionbitscache.StateSinceHeight(blockindex, chainman.GetConsensus(), id)); + const int activation_height = chainman.m_versionbitscache.StateSinceHeight(blockindex, chainman.GetConsensus(), id); + rv.pushKV("height", activation_height); + // Add height_end for temporary softforks + const auto& deployment = chainman.GetConsensus().vDeployments[id]; + if (deployment.active_duration < std::numeric_limits::max()) { + rv.pushKV("height_end", activation_height + deployment.active_duration - 1); + } } rv.pushKV("active", ThresholdState::ACTIVE == next_state); rv.pushKV("bip9", std::move(bip9)); @@ -1377,7 +1386,8 @@ RPCHelpMan getblockchaininfo() namespace { const std::vector RPCHelpForDeployment{ {RPCResult::Type::STR, "type", "one of \"buried\", \"bip9\""}, - {RPCResult::Type::NUM, "height", /*optional=*/true, "height of the first block which the rules are or will be enforced (only for \"buried\" type, or \"bip9\" type with \"active\" status)"}, + {RPCResult::Type::NUM, "height", /*optional=*/true, "height of the first block which enforces the rules (only for \"buried\" type, or \"bip9\" type with \"active\" status)"}, + {RPCResult::Type::NUM, "height_end", /*optional=*/true, "height of the last block which enforces the rules (only for \"bip9\" type with \"active\" status and temporary deployments)"}, {RPCResult::Type::BOOL, "active", "true if the rules are enforced for the mempool and the next block"}, {RPCResult::Type::OBJ, "bip9", /*optional=*/true, "status of bip9 softforks (only for \"bip9\" type)", { @@ -1385,6 +1395,7 @@ const std::vector RPCHelpForDeployment{ {RPCResult::Type::NUM_TIME, "start_time", "the minimum median time past of a block at which the bit gains its meaning"}, {RPCResult::Type::NUM_TIME, "timeout", "the median time past of a block at which the deployment is considered failed if not yet locked in"}, {RPCResult::Type::NUM, "min_activation_height", "minimum height of blocks for which the rules may be enforced"}, + {RPCResult::Type::NUM, "max_activation_height", /*optional=*/true, "height at which the deployment will unconditionally activate (only for UASF deployments)"}, {RPCResult::Type::STR, "status", "status of deployment at specified block (one of \"defined\", \"started\", \"locked_in\", \"active\", \"failed\")"}, {RPCResult::Type::NUM, "since", "height of the first block to which the status applies"}, {RPCResult::Type::STR, "status_next", "status of deployment at the next block"}, @@ -1410,6 +1421,7 @@ UniValue DeploymentInfo(const CBlockIndex* blockindex, const ChainstateManager& SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_SEGWIT); SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_TESTDUMMY); SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_TAPROOT); + SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_REDUCED_DATA); return softforks; } } // anon namespace diff --git a/src/rpc/mempool.cpp b/src/rpc/mempool.cpp index 2b883322aa17..d15207d2520b 100644 --- a/src/rpc/mempool.cpp +++ b/src/rpc/mempool.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -138,6 +139,7 @@ static RPCHelpMan testmempoolaccept() {RPCResult::Type::BOOL, "allowed", /*optional=*/true, "Whether this tx would be accepted to the mempool and pass client-specified maxfeerate. " "If not present, the tx was not fully validated due to a failure in another tx in the list."}, {RPCResult::Type::NUM, "vsize", /*optional=*/true, "Virtual transaction size as defined in BIP 141. This is different from actual serialized size for witness transactions as witness data is discounted (only present when 'allowed' is true)"}, + {RPCResult::Type::NUM, "usage", "Memory usage of transaction for this node"}, {RPCResult::Type::OBJ, "fees", /*optional=*/true, "Transaction fees (only present if 'allowed' is true)", { {RPCResult::Type::STR_AMOUNT, "base", "transaction fee in " + CURRENCY_UNIT}, @@ -203,6 +205,7 @@ static RPCHelpMan testmempoolaccept() UniValue result_inner(UniValue::VOBJ); result_inner.pushKV("txid", tx->GetHash().GetHex()); result_inner.pushKV("wtxid", tx->GetWitnessHash().GetHex()); + result_inner.pushKV("usage", RecursiveDynamicUsage(tx)); if (package_result.m_state.GetResult() == PackageValidationResult::PCKG_POLICY) { result_inner.pushKV("package-error", package_result.m_state.ToString()); } diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index 9942386c7fc0..8f99c6ba319b 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -991,7 +991,7 @@ static RPCHelpMan addpeeraddress() if (net_addr.has_value()) { CService service{net_addr.value(), port}; - CAddress address{MaybeFlipIPv6toCJDNS(service), ServiceFlags{NODE_NETWORK | NODE_WITNESS}}; + CAddress address{MaybeFlipIPv6toCJDNS(service), ServiceFlags{NODE_NETWORK | NODE_WITNESS | NODE_UASF_REDUCED_DATA}}; address.nTime = Now(); // The source address is set equal to the address. This is equivalent to the peer // announcing itself. diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp index c8802d2bf893..0aadb7606ed3 100644 --- a/src/script/descriptor.cpp +++ b/src/script/descriptor.cpp @@ -1966,8 +1966,8 @@ std::vector> ParseScript(uint32_t& key_exp_index // First process all open braces. while (Const("{", expr)) { branches.push_back(false); // new left branch - if (branches.size() > TAPROOT_CONTROL_MAX_NODE_COUNT) { - error = strprintf("tr() supports at most %i nesting levels", TAPROOT_CONTROL_MAX_NODE_COUNT); + if (branches.size() > TAPROOT_CONTROL_MAX_NODE_COUNT_REDUCED) { + error = strprintf("tr() supports at most %i nesting levels", TAPROOT_CONTROL_MAX_NODE_COUNT_REDUCED); return {}; } } diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 4b7bfcedc6c5..065f2d737b66 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -433,6 +433,8 @@ bool EvalScript(std::vector >& stack, const CScript& execdata.m_codeseparator_pos = 0xFFFFFFFFUL; execdata.m_codeseparator_pos_init = true; + const unsigned int max_element_size = (flags & SCRIPT_VERIFY_REDUCED_DATA) ? MAX_SCRIPT_ELEMENT_SIZE_REDUCED : MAX_SCRIPT_ELEMENT_SIZE; + try { for (; pc < pend; ++opcode_pos) { @@ -443,7 +445,7 @@ bool EvalScript(std::vector >& stack, const CScript& // if (!script.GetOp(pc, opcode, vchPushValue)) return set_error(serror, SCRIPT_ERR_BAD_OPCODE); - if (vchPushValue.size() > MAX_SCRIPT_ELEMENT_SIZE) + if (vchPushValue.size() > max_element_size) return set_error(serror, SCRIPT_ERR_PUSH_SIZE); if (sigversion == SigVersion::BASE || sigversion == SigVersion::WITNESS_V0) { @@ -616,6 +618,9 @@ bool EvalScript(std::vector >& stack, const CScript& if (vch.size() > 1 || (vch.size() == 1 && vch[0] != 1)) { return set_error(serror, SCRIPT_ERR_TAPSCRIPT_MINIMALIF); } + if (flags & SCRIPT_VERIFY_REDUCED_DATA) { + return set_error(serror, SCRIPT_ERR_TAPSCRIPT_MINIMALIF); + } } // Under witness v0 rules it is only a policy rule, enabled through SCRIPT_VERIFY_MINIMALIF. if (sigversion == SigVersion::WITNESS_V0 && (flags & SCRIPT_VERIFY_MINIMALIF)) { @@ -1851,8 +1856,9 @@ static bool ExecuteWitnessScript(const Span& stack_span, const CS } // Disallow stack item size > MAX_SCRIPT_ELEMENT_SIZE in witness stack + const unsigned int max_element_size = (flags & SCRIPT_VERIFY_REDUCED_DATA) ? MAX_SCRIPT_ELEMENT_SIZE_REDUCED : MAX_SCRIPT_ELEMENT_SIZE; for (const valtype& elem : stack) { - if (elem.size() > MAX_SCRIPT_ELEMENT_SIZE) return set_error(serror, SCRIPT_ERR_PUSH_SIZE); + if (elem.size() > max_element_size) return set_error(serror, SCRIPT_ERR_PUSH_SIZE); } // Run the script interpreter. @@ -1946,6 +1952,9 @@ static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion, if (stack.size() >= 2 && !stack.back().empty() && stack.back()[0] == ANNEX_TAG) { // Drop annex (this is non-standard; see IsWitnessStandard) const valtype& annex = SpanPopBack(stack); + if (flags & SCRIPT_VERIFY_REDUCED_DATA) { + return set_error(serror, SCRIPT_ERR_PUSH_SIZE); + } execdata.m_annex_hash = (HashWriter{} << annex).GetSHA256(); execdata.m_annex_present = true; } else { @@ -1962,7 +1971,8 @@ static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion, // Script path spending (stack size is >1 after removing optional annex) const valtype& control = SpanPopBack(stack); const valtype& script = SpanPopBack(stack); - if (control.size() < TAPROOT_CONTROL_BASE_SIZE || control.size() > TAPROOT_CONTROL_MAX_SIZE || ((control.size() - TAPROOT_CONTROL_BASE_SIZE) % TAPROOT_CONTROL_NODE_SIZE) != 0) { + const unsigned int max_control_size = (flags & SCRIPT_VERIFY_REDUCED_DATA) ? TAPROOT_CONTROL_MAX_SIZE_REDUCED : TAPROOT_CONTROL_MAX_SIZE; + if (control.size() < TAPROOT_CONTROL_BASE_SIZE || control.size() > max_control_size || ((control.size() - TAPROOT_CONTROL_BASE_SIZE) % TAPROOT_CONTROL_NODE_SIZE) != 0) { return set_error(serror, SCRIPT_ERR_TAPROOT_WRONG_CONTROL_SIZE); } execdata.m_tapleaf_hash = ComputeTapleafHash(control[0] & TAPROOT_LEAF_MASK, script); @@ -1982,7 +1992,7 @@ static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion, } return set_success(serror); } - } else if (!is_p2sh && CScript::IsPayToAnchor(witversion, program)) { + } else if (stack.empty() && !is_p2sh && CScript::IsPayToAnchor(witversion, program)) { return true; } else { if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM) { @@ -2011,6 +2021,12 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const C // scriptSig and scriptPubKey must be evaluated sequentially on the same stack // rather than being simply concatenated (see CVE-2010-5141) std::vector > stack, stackCopy; + if (scriptPubKey.IsPayToScriptHash()) { + // Disable SCRIPT_VERIFY_REDUCED_DATA for pushing the P2SH redeemScript + if (!EvalScript(stack, scriptSig, flags & ~SCRIPT_VERIFY_REDUCED_DATA, checker, SigVersion::BASE, serror)) + // serror is set + return false; + } else if (!EvalScript(stack, scriptSig, flags, checker, SigVersion::BASE, serror)) // serror is set return false; @@ -2062,6 +2078,15 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const C CScript pubKey2(pubKeySerialized.begin(), pubKeySerialized.end()); popstack(stack); + if (flags & SCRIPT_VERIFY_REDUCED_DATA) { + // We bypassed the reduced data check above to exempt redeemScript + // Now enforce it on the rest of the stack items here + // This is sufficient because P2SH requires scriptSig to be push-only + for (const valtype& elem : stack) { + if (elem.size() > MAX_SCRIPT_ELEMENT_SIZE_REDUCED) return set_error(serror, SCRIPT_ERR_PUSH_SIZE); + } + } + if (!EvalScript(stack, pubKey2, flags, checker, SigVersion::BASE, serror)) // serror is set return false; diff --git a/src/script/interpreter.h b/src/script/interpreter.h index d613becb8f6c..249832bd77e9 100644 --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -143,11 +143,25 @@ enum : uint32_t { // Making unknown public key versions (in BIP 342 scripts) non-standard SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE = (1U << 20), + // Enforce MAX_SCRIPT_ELEMENT_SIZE_REDUCED instead of MAX_SCRIPT_ELEMENT_SIZE + // The P2SH redeemScript push is exempted + // Taproot control blocks are limited to TAPROOT_CONTROL_MAX_SIZE_REDUCED + // Taproot annex is also invalid + // OP_IF is also forbidden inside Tapscript + SCRIPT_VERIFY_REDUCED_DATA = (1U << 21), + // Constants to point to the highest flag in use. Add new flags above this line. // SCRIPT_VERIFY_END_MARKER }; +static constexpr unsigned int REDUCED_DATA_MANDATORY_VERIFY_FLAGS{0 + | SCRIPT_VERIFY_REDUCED_DATA + | SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM + | SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION + | SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS +}; + bool CheckSignatureEncoding(const std::vector &vchSig, unsigned int flags, ScriptError* serror); struct PrecomputedTransactionData @@ -234,6 +248,8 @@ static constexpr size_t TAPROOT_CONTROL_BASE_SIZE = 33; static constexpr size_t TAPROOT_CONTROL_NODE_SIZE = 32; static constexpr size_t TAPROOT_CONTROL_MAX_NODE_COUNT = 128; static constexpr size_t TAPROOT_CONTROL_MAX_SIZE = TAPROOT_CONTROL_BASE_SIZE + TAPROOT_CONTROL_NODE_SIZE * TAPROOT_CONTROL_MAX_NODE_COUNT; +static constexpr size_t TAPROOT_CONTROL_MAX_NODE_COUNT_REDUCED = 7; +static constexpr size_t TAPROOT_CONTROL_MAX_SIZE_REDUCED = TAPROOT_CONTROL_BASE_SIZE + TAPROOT_CONTROL_NODE_SIZE * TAPROOT_CONTROL_MAX_NODE_COUNT_REDUCED; extern const HashWriter HASHER_TAPSIGHASH; //!< Hasher with tag "TapSighash" pre-fed to it. extern const HashWriter HASHER_TAPLEAF; //!< Hasher with tag "TapLeaf" pre-fed to it. diff --git a/src/script/script.h b/src/script/script.h index f4579849803b..4d1a2543785c 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -26,6 +26,7 @@ // Maximum number of bytes pushable to the stack static const unsigned int MAX_SCRIPT_ELEMENT_SIZE = 520; +static const unsigned int MAX_SCRIPT_ELEMENT_SIZE_REDUCED = 256; // Maximum number of non-push operations per script static const int MAX_OPS_PER_SCRIPT = 201; diff --git a/src/script/signingprovider.cpp b/src/script/signingprovider.cpp index 597b1a1544bc..0fe284fb3620 100644 --- a/src/script/signingprovider.cpp +++ b/src/script/signingprovider.cpp @@ -353,7 +353,7 @@ void TaprootBuilder::Insert(TaprootBuilder::NodeInfo&& node, int depth) // as what Insert() performs on the m_branch variable. Instead of // storing a NodeInfo object, just remember whether or not there is one // at that depth. - if (depth < 0 || (size_t)depth > TAPROOT_CONTROL_MAX_NODE_COUNT) return false; + if (depth < 0 || (size_t)depth > TAPROOT_CONTROL_MAX_NODE_COUNT_REDUCED) return false; if ((size_t)depth + 1 < branch.size()) return false; while (branch.size() > (size_t)depth && branch[depth]) { branch.pop_back(); @@ -466,7 +466,7 @@ std::optional, int>>> Inf // Skip script records with nonsensical leaf version. if (leaf_ver < 0 || leaf_ver >= 0x100 || leaf_ver & 1) continue; // Skip script records with invalid control block sizes. - if (control.size() < TAPROOT_CONTROL_BASE_SIZE || control.size() > TAPROOT_CONTROL_MAX_SIZE || + if (control.size() < TAPROOT_CONTROL_BASE_SIZE || control.size() > TAPROOT_CONTROL_MAX_SIZE_REDUCED || ((control.size() - TAPROOT_CONTROL_BASE_SIZE) % TAPROOT_CONTROL_NODE_SIZE) != 0) continue; // Skip script records that don't match the control block. if ((control[0] & TAPROOT_LEAF_MASK) != leaf_ver) continue; diff --git a/src/test/data/tx_valid.json b/src/test/data/tx_valid.json index 70df0d0f697d..547deefe2c20 100644 --- a/src/test/data/tx_valid.json +++ b/src/test/data/tx_valid.json @@ -414,9 +414,9 @@ ["0000000000000000000000000000000000000000000000000000000000000100", 2, "0x51", 3000]], "0100000000010300010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000200000000ffffffff03e8030000000000000151d0070000000000000151b80b00000000000001510002483045022100a3cec69b52cba2d2de623ffffffffff1606184ea55476c0f8189fda231bc9cbb022003181ad597f7c380a7d1c740286b1d022b8b04ded028b833282e055e03b8efef812103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM"], -["Witness with a push of 520 bytes"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x00 0x20 0x33198a9bfef674ebddb9ffaa52928017b8472791e54c609cb95f278ac6b1e349", 1000]], -"0100000000010100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff010000000000000000015102fd08020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002755100000000", "NONE"], +["Witness with a push of 256 bytes (REDUCED_DATA limit)"], +[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x00 0x20 0xa57e25ffadd285772f5627ec6fa613bc8fb49b4db475c371dfd4eb76f25c5073", 1000]], +"0100000000010100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff010000000000000000015101fd05014d000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000755100000000", "NONE"], ["Transaction mixing all SigHash, segwit and normal inputs"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x00 0x14 0x4c9c3dfac4207d5d8cb89df5722cb3d712385e3f", 1000], diff --git a/src/test/denialofservice_tests.cpp b/src/test/denialofservice_tests.cpp index 9ee7e9c9fe24..83cc4c16f364 100644 --- a/src/test/denialofservice_tests.cpp +++ b/src/test/denialofservice_tests.cpp @@ -67,8 +67,8 @@ BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction) connman.Handshake( /*node=*/dummyNode1, /*successfully_connected=*/true, - /*remote_services=*/ServiceFlags(NODE_NETWORK | NODE_WITNESS), - /*local_services=*/ServiceFlags(NODE_NETWORK | NODE_WITNESS), + /*remote_services=*/ServiceFlags(NODE_NETWORK | NODE_WITNESS | NODE_UASF_REDUCED_DATA), + /*local_services=*/ServiceFlags(NODE_NETWORK | NODE_WITNESS | NODE_UASF_REDUCED_DATA), /*version=*/PROTOCOL_VERSION, /*relay_txs=*/true); diff --git a/src/test/descriptor_tests.cpp b/src/test/descriptor_tests.cpp index 63c53a842c1f..223d2934acf5 100644 --- a/src/test/descriptor_tests.cpp +++ b/src/test/descriptor_tests.cpp @@ -1006,7 +1006,8 @@ BOOST_AUTO_TEST_CASE(descriptor_test) CheckUnparsable("sh(and_v(vc:andor(pk(L4gM1FBdyHNpkzsFh9ipnofLhpZRp2mwobpeULy1a6dBTvw8Ywtd),pk_k(Kx9HCDjGiwFcgVNhTrS5z5NeZdD6veeam61eDxLDCkGWujvL4Gnn),and_v(v:older(1),pk_k(L4o2kDvXXDRH2VS9uBnouScLduWt4dZnM25se7kvEjJeQ285en2A))),after(10)))", "sh(and_v(vc:andor(pk(03cdabb7f2dce7bfbd8a0b9570c6fd1e712e5d64045e9d6b517b3d5072251dc204),pk_k(032707170c71d8f75e4ca4e3fce870b9409dcaf12b051d3bcadff74747fa7619c0),and_v(v:older(1),pk_k(02aa27e5eb2c185e87cd1dbc3e0efc9cb1175235e0259df1713424941c3cb40402))),after(10)))", "Miniscript expressions can only be used in wsh or tr."); CheckUnparsable("tr(and_v(vc:andor(pk(L4gM1FBdyHNpkzsFh9ipnofLhpZRp2mwobpeULy1a6dBTvw8Ywtd),pk_k(Kx9HCDjGiwFcgVNhTrS5z5NeZdD6veeam61eDxLDCkGWujvL4Gnn),and_v(v:older(1),pk_k(L4o2kDvXXDRH2VS9uBnouScLduWt4dZnM25se7kvEjJeQ285en2A))),after(10)))", "tr(and_v(vc:andor(pk(03cdabb7f2dce7bfbd8a0b9570c6fd1e712e5d64045e9d6b517b3d5072251dc204),pk_k(032707170c71d8f75e4ca4e3fce870b9409dcaf12b051d3bcadff74747fa7619c0),and_v(v:older(1),pk_k(02aa27e5eb2c185e87cd1dbc3e0efc9cb1175235e0259df1713424941c3cb40402))),after(10)))", "tr(): key 'and_v(vc:andor(pk(03cdabb7f2dce7bfbd8a0b9570c6fd1e712e5d64045e9d6b517b3d5072251dc204),pk_k(032707170c71d8f75e4ca4e3fce870b9409dcaf12b051d3bcadff74747fa7619c0),and_v(v:older(1),pk_k(02aa27e5eb2c185e87cd1dbc3e0efc9cb1175235e0259df1713424941c3cb40402))),after(10))' is not valid"); CheckUnparsable("raw(and_v(vc:andor(pk(L4gM1FBdyHNpkzsFh9ipnofLhpZRp2mwobpeULy1a6dBTvw8Ywtd),pk_k(Kx9HCDjGiwFcgVNhTrS5z5NeZdD6veeam61eDxLDCkGWujvL4Gnn),and_v(v:older(1),pk_k(L4o2kDvXXDRH2VS9uBnouScLduWt4dZnM25se7kvEjJeQ285en2A))),after(10)))", "sh(and_v(vc:andor(pk(03cdabb7f2dce7bfbd8a0b9570c6fd1e712e5d64045e9d6b517b3d5072251dc204),pk_k(032707170c71d8f75e4ca4e3fce870b9409dcaf12b051d3bcadff74747fa7619c0),and_v(v:older(1),pk_k(02aa27e5eb2c185e87cd1dbc3e0efc9cb1175235e0259df1713424941c3cb40402))),after(10)))", "Miniscript expressions can only be used in wsh or tr."); - CheckUnparsable("", "tr(034D2224bbbbbbbbbbcbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb40,{{{{{{{{{{{{{{{{{{{{{{multi(1,xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/967808'/9,xprvA1RpRA33e1JQ7ifknakTFNpgXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/968/2/5/8/5/2/5/58/58/2/5/5/5/58/588/2/6/8/5/2/8/2/5/8/2/58/2/5/8/5/2/8/5/8/3/4/5/58/55/2/5/58/58/2/5/5/5/8/5/2/8/5/85/2/8/2/5/8/5/2/5/58/58/2/5/58/58/588/2/58/2/8/5/8/5/4/5/585/2/5/58/58/2/5/5/58/588/2/58/2/5/8/5/2/8/2/5/8/5/5/58/588/2/6/8/5/2/8/2/5/8/5/2/5/58/58/2/5/58/58/2/0/8/5/2/8/5/8/5/4/5/58/588/2/6/8/5/2/8/2/5/8/5/2/5/58/58/2/5/58/58/588/2/58/2/5/8/5/8/24/5/58/52/5/8/5/2/8/24/5/58/588/246/8/5/2/8/2/5/8/5/2/5/58/58/2/5/5/5/58/588/2/6/8/5/2/8/2/5/8/2/58/2/5/8/5/2/8/5/8/5/4/5/58/55/58/2/5/8/55/2/5/8/58/555/58/2/5/8/4//2/5/58/5w/2/5/8/5/2/4/5/58/5558'/2/5/58/58/2/5/5/58/588/2/58/2/5/8/5/2/8/2/5/8/5/5/8/58/2/5/58/58/2/5/8/9/588/2/58/2/5/8/5/2/8/5/8/5/4/5/58/588/2/6/8/5/2/8/2/5/8/5/2/5/58/58/2/5/5/58/588/2/58/2/5/8/5/2/82/5/8/5/5/58/52/6/8/5/2/8/{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{}{{{{{{{{{DDD2/5/8/5/2/5/58/58/2/5/58/58/588/2/58/2/8/5/8/5/4/5/58/588/2/6/8/5/2/8/2/5/8588/246/8/5/2DLDDDDDDDbbD3DDDD/8/2/5/8/5/2/5/58/58/2/5/5/5/58/588/2/6/8/5/2/8/2/5/8/2/58/2/5/8/5/2/8/5/8/3/4/5/58/55/2/5/58/58/2/5/5/5/8/5/2/8/5/85/2/8/2/5/8D)/5/2/5/58/58/2/5/58/58/58/588/2/58/2/5/8/5/25/58/58/2/5/58/58/2/5/8/9/588/2/58/2/6780,xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFW/8/5/2/5/58678008')", "'multi(1,xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/967808'/9,xprvA1RpRA33e1JQ7ifknakTFNpgXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/968/2/5/8/5/2/5/58/58/2/5/5/5/58/588/2/6/8/5/2/8/2/5/8/2/58/2/5/8/5/2/8/5/8/3/4/5/58/55/2/5/58/58/2/5/5/5/8/5/2/8/5/85/2/8/2/5/8/5/2/5/58/58/2/5/58/58/588/2/58/2/8/5/8/5/4/5/585/2/5/58/58/2/5/5/58/588/2/58/2/5/8/5/2/8/2/5/8/5/5/58/588/2/6/8/5/2/8/2/5/8/5/2/5/58/58/2/5/58/58/2/0/8/5/2/8/5/8/5/4/5/58/588/2/6/8/5/2/8/2/5/8/5/2/5/58/58/2/5/58/58/588/2/58/2/5/8/5/8/24/5/58/52/5/8/5/2/8/24/5/58/588/246/8/5/2/8/2/5/8/5/2/5/58/58/2/5/5/5/58/588/2/6/8/5/2/8/2/5/8/2/58/2/5/8/5/2/8/5/8/5/4/5/58/55/58/2/5/8/55/2/5/8/58/555/58/2/5/8/4//2/5/58/5w/2/5/8/5/2/4/5/58/5558'/2/5/58/58/2/5/5/58/588/2/58/2/5/8/5/2/8/2/5/8/5/5/8/58/2/5/58/58/2/5/8/9/588/2/58/2/5/8/5/2/8/5/8/5/4/5/58/588/2/6/8/5/2/8/2/5/8/5/2/5/58/58/2/5/5/58/588/2/58/2/5/8/5/2/82/5/8/5/5/58/52/6/8/5/2/8/{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{}{{{{{{{{{DDD2/5/8/5/2/5/58/58/2/5/58/58/588/2/58/2/8/5/8/5/4/5/58/588/2/6/8/5/2/8/2/5/8588/246/8/5/2DLDDDDDDDbbD3DDDD/8/2/5/8/5/2/5/58/58/2/5/5/5/58/588/2/6/8/5/2/8/2/5/8/2/58/2/5/8/5/2/8/5/8/3/4/5/58/55/2/5/58/58/2/5/5/5/8/5/2/8/5/85/2/8/2/5/8D)/5/2/5/58/58/2/5/58/58/58/588/2/58/2/5/8/5/25/58/58/2/5/58/58/2/5/8/9/588/2/58/2/6780,xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFW/8/5/2/5/58678008'' is not a valid descriptor function"); + // REDUCED_DATA limits Taproot nesting to 7 levels, so this test now hits that limit before the multi() error + CheckUnparsable("", "tr(034D2224bbbbbbbbbbcbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb40,{{{{{{{{{{{{{{{{{{{{{{multi(1,xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/967808'/9,xprvA1RpRA33e1JQ7ifknakTFNpgXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/968/2/5/8/5/2/5/58/58/2/5/5/5/58/588/2/6/8/5/2/8/2/5/8/2/58/2/5/8/5/2/8/5/8/3/4/5/58/55/2/5/58/58/2/5/5/5/8/5/2/8/5/85/2/8/2/5/8/5/2/5/58/58/2/5/58/58/588/2/58/2/8/5/8/5/4/5/585/2/5/58/58/2/5/5/58/588/2/58/2/5/8/5/2/8/2/5/8/5/5/58/588/2/6/8/5/2/8/2/5/8/5/2/5/58/58/2/5/58/58/2/0/8/5/2/8/5/8/5/4/5/58/588/2/6/8/5/2/8/2/5/8/5/2/5/58/58/2/5/58/58/588/2/58/2/5/8/5/8/24/5/58/52/5/8/5/2/8/24/5/58/588/246/8/5/2/8/2/5/8/5/2/5/58/58/2/5/5/5/58/588/2/6/8/5/2/8/2/5/8/2/58/2/5/8/5/2/8/5/8/5/4/5/58/55/58/2/5/8/55/2/5/8/58/555/58/2/5/8/4//2/5/58/5w/2/5/8/5/2/4/5/58/5558'/2/5/58/58/2/5/5/58/588/2/58/2/5/8/5/2/8/2/5/8/5/5/8/58/2/5/58/58/2/5/8/9/588/2/58/2/5/8/5/2/8/5/8/5/4/5/58/588/2/6/8/5/2/8/2/5/8/5/2/5/58/58/2/5/5/58/588/2/58/2/5/8/5/2/82/5/8/5/5/58/52/6/8/5/2/8/{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{}{{{{{{{{{DDD2/5/8/5/2/5/58/58/2/5/58/58/588/2/58/2/8/5/8/5/4/5/58/588/2/6/8/5/2/8/2/5/8588/246/8/5/2DLDDDDDDDbbD3DDDD/8/2/5/8/5/2/5/58/58/2/5/5/5/58/588/2/6/8/5/2/8/2/5/8/2/58/2/5/8/5/2/8/5/8/3/4/5/58/55/2/5/58/58/2/5/5/5/8/5/2/8/5/85/2/8/2/5/8D)/5/2/5/58/58/2/5/58/58/58/588/2/58/2/5/8/5/25/58/58/2/5/58/58/2/5/8/9/588/2/58/2/6780,xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFW/8/5/2/5/58678008')", "tr() supports at most 7 nesting levels"); // No uncompressed keys allowed CheckUnparsable("", "wsh(and_v(vc:andor(pk(03cdabb7f2dce7bfbd8a0b9570c6fd1e712e5d64045e9d6b517b3d5072251dc204),pk_k(032707170c71d8f75e4ca4e3fce870b9409dcaf12b051d3bcadff74747fa7619c0),and_v(v:older(1),pk_k(049228de6902abb4f541791f6d7f925b10e2078ccb1298856e5ea5cc5fd667f930eac37a00cc07f9a91ef3c2d17bf7a17db04552ff90ac312a5b8b4caca6c97aa4))),after(10)))", "Uncompressed keys are not allowed"); // No hybrid keys allowed @@ -1047,7 +1048,8 @@ BOOST_AUTO_TEST_CASE(descriptor_test) Check("wsh(and_v(v:hash256(ae253ca2a54debcac7ecf414f6734f48c56421a08bb59182ff9f39a6fffdb588),pk(xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc)))", "wsh(and_v(v:hash256(ae253ca2a54debcac7ecf414f6734f48c56421a08bb59182ff9f39a6fffdb588),pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL)))", "wsh(and_v(v:hash256(ae253ca2a54debcac7ecf414f6734f48c56421a08bb59182ff9f39a6fffdb588),pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL)))", SIGNABLE_FAILS, {{"0020cf62bf97baf977aec69cbc290c372899f913337a9093e8f066ab59b8657a365c"}}, OutputType::BECH32, /*op_desc_id=*/uint256{"8412ba3ac20ba3a30f81442d10d32e0468fa52814960d04e959bf84a9b813b88"}, {{}}, /*spender_nlocktime=*/0, /*spender_nsequence=*/CTxIn::SEQUENCE_FINAL, {}); Check("wsh(and_v(v:hash256(ae253ca2a54debcac7ecf414f6734f48c56421a08bb59182ff9f39a6fffdb588),pk(xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc)))", "wsh(and_v(v:hash256(ae253ca2a54debcac7ecf414f6734f48c56421a08bb59182ff9f39a6fffdb588),pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL)))", "wsh(and_v(v:hash256(ae253ca2a54debcac7ecf414f6734f48c56421a08bb59182ff9f39a6fffdb588),pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL)))", SIGNABLE, {{"0020cf62bf97baf977aec69cbc290c372899f913337a9093e8f066ab59b8657a365c"}}, OutputType::BECH32, /*op_desc_id=*/uint256{"8412ba3ac20ba3a30f81442d10d32e0468fa52814960d04e959bf84a9b813b88"}, {{}}, /*spender_nlocktime=*/0, /*spender_nsequence=*/CTxIn::SEQUENCE_FINAL, {{"ae253ca2a54debcac7ecf414f6734f48c56421a08bb59182ff9f39a6fffdb588"_hex_v_u8, "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"_hex_v_u8}}); // Can have a Miniscript expression under tr() if it's alone. - Check("tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,thresh(2,pk(L1NKM8dVA1h52mwDrmk1YreTWkAZZTu2vmKLpmLEbFRqGQYjHeEV),s:pk(Kz3iCBy3HNGP5CZWDsAMmnCMFNwqdDohudVN9fvkrN7tAkzKNtM7),adv:older(42)))", "tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,thresh(2,pk(30a6069f344fb784a2b4c99540a91ee727c91e3a25ef6aae867d9c65b5f23529),s:pk(9918d400c1b8c3c478340a40117ced4054b6b58f48cdb3c89b836bdfee1f5766),adv:older(42)))", "tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,thresh(2,pk(30a6069f344fb784a2b4c99540a91ee727c91e3a25ef6aae867d9c65b5f23529),s:pk(9918d400c1b8c3c478340a40117ced4054b6b58f48cdb3c89b836bdfee1f5766),adv:older(42)))", MISSING_PRIVKEYS | XONLY_KEYS | SIGNABLE, {{"512033982eebe204dc66508e4b19cfc31b5ffc6e1bfcbf6e5597dfc2521a52270795"}}, OutputType::BECH32M); + // Note: thresh() uses OP_IF which is forbidden with REDUCED_DATA, so using and_v() instead + Check("tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,and_v(v:pk(L1NKM8dVA1h52mwDrmk1YreTWkAZZTu2vmKLpmLEbFRqGQYjHeEV),pk(Kz3iCBy3HNGP5CZWDsAMmnCMFNwqdDohudVN9fvkrN7tAkzKNtM7)))", "tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,and_v(v:pk(30a6069f344fb784a2b4c99540a91ee727c91e3a25ef6aae867d9c65b5f23529),pk(9918d400c1b8c3c478340a40117ced4054b6b58f48cdb3c89b836bdfee1f5766)))", "tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,and_v(v:pk(30a6069f344fb784a2b4c99540a91ee727c91e3a25ef6aae867d9c65b5f23529),pk(9918d400c1b8c3c478340a40117ced4054b6b58f48cdb3c89b836bdfee1f5766)))", MISSING_PRIVKEYS | XONLY_KEYS | SIGNABLE, {{"51202aca0fdcbfbc513549e2c9490e60ba54e3c345ff01d667c4f846c802c0e7b8f4"}}, OutputType::BECH32M); // Can have a pkh() expression alone as tr() script path (because pkh() is valid Miniscript). Check("tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,pkh(L1NKM8dVA1h52mwDrmk1YreTWkAZZTu2vmKLpmLEbFRqGQYjHeEV))", "tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,pkh(30a6069f344fb784a2b4c99540a91ee727c91e3a25ef6aae867d9c65b5f23529))", "tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,pkh(30a6069f344fb784a2b4c99540a91ee727c91e3a25ef6aae867d9c65b5f23529))", MISSING_PRIVKEYS | XONLY_KEYS | SIGNABLE, {{"51201e9875f690f5847404e4c5951e2f029887df0525691ee11a682afd37b608aad4"}}, OutputType::BECH32M); // Can have a Miniscript expression under tr() if it's part of a tree. diff --git a/src/test/fuzz/coins_view.cpp b/src/test/fuzz/coins_view.cpp index 9c6aa6e7a1ec..9afc0a04522b 100644 --- a/src/test/fuzz/coins_view.cpp +++ b/src/test/fuzz/coins_view.cpp @@ -255,7 +255,7 @@ FUZZ_TARGET(coins_view, .init = initialize_coins_view) // It is not allowed to call CheckTxInputs if CheckTransaction failed return; } - if (Consensus::CheckTxInputs(transaction, state, coins_view_cache, fuzzed_data_provider.ConsumeIntegralInRange(0, std::numeric_limits::max()), tx_fee_out)) { + if (Consensus::CheckTxInputs(transaction, state, coins_view_cache, fuzzed_data_provider.ConsumeIntegralInRange(0, std::numeric_limits::max()), tx_fee_out, CheckTxInputsRules::OutputSizeLimit)) { assert(MoneyRange(tx_fee_out)); } }, diff --git a/src/test/fuzz/miniscript.cpp b/src/test/fuzz/miniscript.cpp index 60d096bb5a99..132f9f9d4d28 100644 --- a/src/test/fuzz/miniscript.cpp +++ b/src/test/fuzz/miniscript.cpp @@ -1132,13 +1132,25 @@ void TestNode(const MsCtx script_ctx, const NodeRef& node, FuzzedDataProvider& p SatisfactionToWitness(script_ctx, witness_nonmal, script, builder); ScriptError serror; bool res = VerifyScript(DUMMY_SCRIPTSIG, script_pubkey, &witness_nonmal, STANDARD_SCRIPT_VERIFY_FLAGS, CHECKER_CTX, &serror); - // Non-malleable satisfactions are guaranteed to be valid if ValidSatisfactions(). - if (node->ValidSatisfactions()) assert(res); + // Non-malleable satisfactions are guaranteed to be valid if ValidSatisfactions(), unless REDUCED_DATA rules are violated. + if (node->ValidSatisfactions()) { + assert(res || + serror == ScriptError::SCRIPT_ERR_PUSH_SIZE || + serror == ScriptError::SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM || + serror == ScriptError::SCRIPT_ERR_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION || + serror == ScriptError::SCRIPT_ERR_DISCOURAGE_OP_SUCCESS || + serror == ScriptError::SCRIPT_ERR_TAPSCRIPT_MINIMALIF); + } // More detailed: non-malleable satisfactions must be valid, or could fail with ops count error (if CheckOpsLimit failed), - // or with a stack size error (if CheckStackSize check failed). + // or with a stack size error (if CheckStackSize check failed), or with REDUCED_DATA-related errors. assert(res || (!node->CheckOpsLimit() && serror == ScriptError::SCRIPT_ERR_OP_COUNT) || - (!node->CheckStackSize() && serror == ScriptError::SCRIPT_ERR_STACK_SIZE)); + (!node->CheckStackSize() && serror == ScriptError::SCRIPT_ERR_STACK_SIZE) || + serror == ScriptError::SCRIPT_ERR_PUSH_SIZE || + serror == ScriptError::SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM || + serror == ScriptError::SCRIPT_ERR_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION || + serror == ScriptError::SCRIPT_ERR_DISCOURAGE_OP_SUCCESS || + serror == ScriptError::SCRIPT_ERR_TAPSCRIPT_MINIMALIF); } if (mal_success && (!nonmal_success || witness_mal.stack != witness_nonmal.stack)) { @@ -1148,8 +1160,15 @@ void TestNode(const MsCtx script_ctx, const NodeRef& node, FuzzedDataProvider& p ScriptError serror; bool res = VerifyScript(DUMMY_SCRIPTSIG, script_pubkey, &witness_mal, STANDARD_SCRIPT_VERIFY_FLAGS, CHECKER_CTX, &serror); // Malleable satisfactions are not guaranteed to be valid under any conditions, but they can only - // fail due to stack or ops limits. - assert(res || serror == ScriptError::SCRIPT_ERR_OP_COUNT || serror == ScriptError::SCRIPT_ERR_STACK_SIZE); + // fail due to stack or ops limits, or REDUCED_DATA-related errors. + assert(res || + serror == ScriptError::SCRIPT_ERR_OP_COUNT || + serror == ScriptError::SCRIPT_ERR_STACK_SIZE || + serror == ScriptError::SCRIPT_ERR_PUSH_SIZE || + serror == ScriptError::SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM || + serror == ScriptError::SCRIPT_ERR_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION || + serror == ScriptError::SCRIPT_ERR_DISCOURAGE_OP_SUCCESS || + serror == ScriptError::SCRIPT_ERR_TAPSCRIPT_MINIMALIF); } if (node->IsSane()) { diff --git a/src/test/miniscript_tests.cpp b/src/test/miniscript_tests.cpp index 077ef498b2d9..27a2a5b57b4f 100644 --- a/src/test/miniscript_tests.cpp +++ b/src/test/miniscript_tests.cpp @@ -388,13 +388,25 @@ void TestSatisfy(const KeyConverter& converter, const std::string& testcase, con // Test non-malleable satisfaction. ScriptError serror; bool res = VerifyScript(CScript(), script_pubkey, &witness_nonmal, STANDARD_SCRIPT_VERIFY_FLAGS, checker, &serror); - // Non-malleable satisfactions are guaranteed to be valid if ValidSatisfactions(). - if (node->ValidSatisfactions()) BOOST_CHECK(res); + // Non-malleable satisfactions are guaranteed to be valid if ValidSatisfactions(), unless REDUCED_DATA rules are violated. + if (node->ValidSatisfactions()) { + BOOST_CHECK(res || + serror == ScriptError::SCRIPT_ERR_PUSH_SIZE || + serror == ScriptError::SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM || + serror == ScriptError::SCRIPT_ERR_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION || + serror == ScriptError::SCRIPT_ERR_DISCOURAGE_OP_SUCCESS || + serror == ScriptError::SCRIPT_ERR_TAPSCRIPT_MINIMALIF); + } // More detailed: non-malleable satisfactions must be valid, or could fail with ops count error (if CheckOpsLimit failed), - // or with a stack size error (if CheckStackSize check fails). + // or with a stack size error (if CheckStackSize check fails), or with REDUCED_DATA-related errors. BOOST_CHECK(res || (!node->CheckOpsLimit() && serror == ScriptError::SCRIPT_ERR_OP_COUNT) || - (!node->CheckStackSize() && serror == ScriptError::SCRIPT_ERR_STACK_SIZE)); + (!node->CheckStackSize() && serror == ScriptError::SCRIPT_ERR_STACK_SIZE) || + (serror == ScriptError::SCRIPT_ERR_PUSH_SIZE) || + (serror == ScriptError::SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM) || + (serror == ScriptError::SCRIPT_ERR_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION) || + (serror == ScriptError::SCRIPT_ERR_DISCOURAGE_OP_SUCCESS) || + (serror == ScriptError::SCRIPT_ERR_TAPSCRIPT_MINIMALIF)); } if (mal_success && (!nonmal_success || witness_mal.stack != witness_nonmal.stack)) { @@ -402,8 +414,15 @@ void TestSatisfy(const KeyConverter& converter, const std::string& testcase, con ScriptError serror; bool res = VerifyScript(CScript(), script_pubkey, &witness_mal, STANDARD_SCRIPT_VERIFY_FLAGS, checker, &serror); // Malleable satisfactions are not guaranteed to be valid under any conditions, but they can only - // fail due to stack or ops limits. - BOOST_CHECK(res || serror == ScriptError::SCRIPT_ERR_OP_COUNT || serror == ScriptError::SCRIPT_ERR_STACK_SIZE); + // fail due to stack or ops limits, or REDUCED_DATA-related errors. + BOOST_CHECK(res || + serror == ScriptError::SCRIPT_ERR_OP_COUNT || + serror == ScriptError::SCRIPT_ERR_STACK_SIZE || + serror == ScriptError::SCRIPT_ERR_PUSH_SIZE || + serror == ScriptError::SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM || + serror == ScriptError::SCRIPT_ERR_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION || + serror == ScriptError::SCRIPT_ERR_DISCOURAGE_OP_SUCCESS || + serror == ScriptError::SCRIPT_ERR_TAPSCRIPT_MINIMALIF); } if (node->IsSane()) { diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp index 62e541b5b392..54cd00ee37c9 100644 --- a/src/test/net_tests.cpp +++ b/src/test/net_tests.cpp @@ -827,7 +827,7 @@ BOOST_AUTO_TEST_CASE(initial_advertise_from_version_message) /*conn_type_in=*/ConnectionType::OUTBOUND_FULL_RELAY, /*inbound_onion=*/false}; - const uint64_t services{NODE_NETWORK | NODE_WITNESS}; + const uint64_t services{NODE_NETWORK | NODE_WITNESS | NODE_UASF_REDUCED_DATA}; const int64_t time{0}; // Force ChainstateManager::IsInitialBlockDownload() to return false. @@ -835,7 +835,7 @@ BOOST_AUTO_TEST_CASE(initial_advertise_from_version_message) auto& chainman = static_cast(*m_node.chainman); chainman.JumpOutOfIbd(); - m_node.peerman->InitializeNode(peer, NODE_NETWORK); + m_node.peerman->InitializeNode(peer, ServiceFlags(NODE_NETWORK | NODE_UASF_REDUCED_DATA)); std::atomic interrupt_dummy{false}; std::chrono::microseconds time_received_dummy{0}; diff --git a/src/test/peerman_tests.cpp b/src/test/peerman_tests.cpp index 64b13fa3cc1a..be1b350d2394 100644 --- a/src/test/peerman_tests.cpp +++ b/src/test/peerman_tests.cpp @@ -35,6 +35,7 @@ BOOST_AUTO_TEST_CASE(connections_desirable_service_flags) auto consensus = m_node.chainman->GetParams().GetConsensus(); // Check we start connecting to full nodes + // Note: NODE_UASF_REDUCED_DATA requirement is enforced separately in VERSION processing ServiceFlags peer_flags{NODE_WITNESS | NODE_NETWORK_LIMITED}; BOOST_CHECK(peerman->GetDesirableServiceFlags(peer_flags) == ServiceFlags(NODE_NETWORK | NODE_WITNESS)); diff --git a/src/test/script_standard_tests.cpp b/src/test/script_standard_tests.cpp index e9ce82ca8a6c..042a6c6275d8 100644 --- a/src/test/script_standard_tests.cpp +++ b/src/test/script_standard_tests.cpp @@ -385,9 +385,10 @@ BOOST_AUTO_TEST_CASE(script_standard_taproot_builder) BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({2,2,0}), false); BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({2,2,1}), true); BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({2,2,2}), false); - BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({2,2,2,3,4,5,6,7,8,9,10,11,12,14,14,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,31,31,31,31,31,31,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,128}), true); - BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({128,128,127,126,125,124,123,122,121,120,119,118,117,116,115,114,113,112,111,110,109,108,107,106,105,104,103,102,101,100,99,98,97,96,95,94,93,92,91,90,89,88,87,86,85,84,83,82,81,80,79,78,77,76,75,74,73,72,71,70,69,68,67,66,65,64,63,62,61,60,59,58,57,56,55,54,53,52,51,50,49,48,47,46,45,44,43,42,41,40,39,38,37,36,35,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1}), true); - BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({129,129,128,127,126,125,124,123,122,121,120,119,118,117,116,115,114,113,112,111,110,109,108,107,106,105,104,103,102,101,100,99,98,97,96,95,94,93,92,91,90,89,88,87,86,85,84,83,82,81,80,79,78,77,76,75,74,73,72,71,70,69,68,67,66,65,64,63,62,61,60,59,58,57,56,55,54,53,52,51,50,49,48,47,46,45,44,43,42,41,40,39,38,37,36,35,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1}), false); + // REDUCED_DATA limits Taproot tree depth to 7 instead of 128 + BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({2,2,2,3,4,5,6,7,7}), true); + BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({7,7,6,5,4,3,2,1}), true); + BOOST_CHECK_EQUAL(TaprootBuilder::ValidDepths({8,8,7,6,5,4,3,2,1}), false); XOnlyPubKey key_inner{"79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"_hex_u8}; XOnlyPubKey key_1{"c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5"_hex_u8}; diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index 5844ab23bc8d..5b8fafeb0611 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -71,6 +71,7 @@ static std::map mapFlagNames = { {std::string("DISCOURAGE_UPGRADABLE_PUBKEYTYPE"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE}, {std::string("DISCOURAGE_OP_SUCCESS"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS}, {std::string("DISCOURAGE_UPGRADABLE_TAPROOT_VERSION"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION}, + {std::string("REDUCED_DATA"), (unsigned int)SCRIPT_VERIFY_REDUCED_DATA}, }; unsigned int ParseScriptFlags(std::string strFlags) diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp index af36a9569315..14f2a11bf61b 100644 --- a/src/test/txvalidationcache_tests.cpp +++ b/src/test/txvalidationcache_tests.cpp @@ -2,9 +2,11 @@ // 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