From 8c1114aa61c46e58efb44368b5428d3ccb65f9d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojt=C4=9Bch=20Strnad?= <43024885+vostrnad@users.noreply.github.com> Date: Thu, 25 Jan 2024 05:16:05 +0100 Subject: [PATCH] Add a `-permitbarepubkey` option --- src/init.cpp | 2 ++ src/kernel/mempool_options.h | 1 + src/node/mempool_args.cpp | 2 ++ src/policy/policy.cpp | 6 +++++- src/policy/policy.h | 4 +++- src/test/fuzz/transaction.cpp | 4 ++-- src/test/script_p2sh_tests.cpp | 6 +++--- src/test/transaction_tests.cpp | 5 +++-- src/txmempool.cpp | 1 + src/txmempool.h | 1 + src/validation.cpp | 2 +- 11 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index b825c8ce21..321c3ea4a2 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -635,6 +635,8 @@ void SetupServerArgs(ArgsManager& argsman) MAX_OP_RETURN_RELAY), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY); argsman.AddArg("-mempoolfullrbf", strprintf("Accept transaction replace-by-fee without requiring replaceability signaling (default: %u)", DEFAULT_MEMPOOL_FULL_RBF), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY); + argsman.AddArg("-permitbarepubkey", strprintf("Relay legacy pubkey outputs (default: %u)", DEFAULT_PERMIT_BAREPUBKEY), ArgsManager::ALLOW_ANY, + OptionsCategory::NODE_RELAY); argsman.AddArg("-permitbaremultisig", strprintf("Relay non-P2SH multisig (default: %u)", DEFAULT_PERMIT_BAREMULTISIG), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY); argsman.AddArg("-minrelaytxfee=", strprintf("Fees (in %s/kvB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s)", diff --git a/src/kernel/mempool_options.h b/src/kernel/mempool_options.h index 753aebd455..bd1e9bc30e 100644 --- a/src/kernel/mempool_options.h +++ b/src/kernel/mempool_options.h @@ -51,6 +51,7 @@ struct MemPoolOptions { * If nullopt, any size is nonstandard. */ std::optional max_datacarrier_bytes{DEFAULT_ACCEPT_DATACARRIER ? std::optional{MAX_OP_RETURN_RELAY} : std::nullopt}; + bool permit_bare_pubkey{DEFAULT_PERMIT_BAREPUBKEY}; bool permit_bare_multisig{DEFAULT_PERMIT_BAREMULTISIG}; bool require_standard{true}; bool full_rbf{DEFAULT_MEMPOOL_FULL_RBF}; diff --git a/src/node/mempool_args.cpp b/src/node/mempool_args.cpp index ac26600919..70aeb120a1 100644 --- a/src/node/mempool_args.cpp +++ b/src/node/mempool_args.cpp @@ -78,6 +78,8 @@ util::Result ApplyArgsManOptions(const ArgsManager& argsman, const CChainP } } + mempool_opts.permit_bare_pubkey = argsman.GetBoolArg("-permitbarepubkey", DEFAULT_PERMIT_BAREPUBKEY); + mempool_opts.permit_bare_multisig = argsman.GetBoolArg("-permitbaremultisig", DEFAULT_PERMIT_BAREMULTISIG); if (argsman.GetBoolArg("-datacarrier", DEFAULT_ACCEPT_DATACARRIER)) { diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp index d08ec4fb7f..023136b161 100644 --- a/src/policy/policy.cpp +++ b/src/policy/policy.cpp @@ -91,7 +91,7 @@ bool IsStandard(const CScript& scriptPubKey, const std::optional& max_ return true; } -bool IsStandardTx(const CTransaction& tx, const std::optional& max_datacarrier_bytes, bool permit_bare_multisig, const CFeeRate& dust_relay_fee, std::string& reason) +bool IsStandardTx(const CTransaction& tx, const std::optional& max_datacarrier_bytes, bool permit_bare_pubkey, bool permit_bare_multisig, const CFeeRate& dust_relay_fee, std::string& reason) { if (tx.nVersion > TX_MAX_STANDARD_VERSION || tx.nVersion < 1) { reason = "version"; @@ -138,6 +138,10 @@ bool IsStandardTx(const CTransaction& tx, const std::optional& max_dat if (whichType == TxoutType::NULL_DATA) nDataOut++; + else if ((whichType == TxoutType::PUBKEY) && (!permit_bare_pubkey)) { + reason = "bare-pubkey"; + return false; + } else if ((whichType == TxoutType::MULTISIG) && (!permit_bare_multisig)) { reason = "bare-multisig"; return false; diff --git a/src/policy/policy.h b/src/policy/policy.h index 6a7980c312..a66dd800ac 100644 --- a/src/policy/policy.h +++ b/src/policy/policy.h @@ -35,6 +35,8 @@ static constexpr unsigned int MAX_STANDARD_TX_SIGOPS_COST{MAX_BLOCK_SIGOPS_COST/ static constexpr unsigned int DEFAULT_INCREMENTAL_RELAY_FEE{1000}; /** Default for -bytespersigop */ static constexpr unsigned int DEFAULT_BYTES_PER_SIGOP{20}; +/** Default for -permitbarepubkey */ +static constexpr bool DEFAULT_PERMIT_BAREPUBKEY{true}; /** Default for -permitbaremultisig */ static constexpr bool DEFAULT_PERMIT_BAREMULTISIG{true}; /** The maximum number of witness stack items in a standard P2WSH script */ @@ -137,7 +139,7 @@ static constexpr decltype(CTransaction::nVersion) TX_MAX_STANDARD_VERSION{2}; * Check for standard transaction types * @return True if all outputs (scriptPubKeys) use only standard transaction forms */ -bool IsStandardTx(const CTransaction& tx, const std::optional& max_datacarrier_bytes, bool permit_bare_multisig, const CFeeRate& dust_relay_fee, std::string& reason); +bool IsStandardTx(const CTransaction& tx, const std::optional& max_datacarrier_bytes, bool permit_bare_pubkey, bool permit_bare_multisig, const CFeeRate& dust_relay_fee, std::string& reason); /** * Check for standard transaction types * @param[in] mapInputs Map of previous transactions that have outputs we're spending diff --git a/src/test/fuzz/transaction.cpp b/src/test/fuzz/transaction.cpp index 2a043f7458..a740876bba 100644 --- a/src/test/fuzz/transaction.cpp +++ b/src/test/fuzz/transaction.cpp @@ -59,8 +59,8 @@ FUZZ_TARGET(transaction, .init = initialize_transaction) const CFeeRate dust_relay_fee{DUST_RELAY_TX_FEE}; std::string reason; - const bool is_standard_with_permit_bare_multisig = IsStandardTx(tx, std::nullopt, /* permit_bare_multisig= */ true, dust_relay_fee, reason); - const bool is_standard_without_permit_bare_multisig = IsStandardTx(tx, std::nullopt, /* permit_bare_multisig= */ false, dust_relay_fee, reason); + const bool is_standard_with_permit_bare_multisig = IsStandardTx(tx, std::nullopt, /* permit_bare_pubkey= */ true, /* permit_bare_multisig= */ true, dust_relay_fee, reason); + const bool is_standard_without_permit_bare_multisig = IsStandardTx(tx, std::nullopt, /* permit_bare_pubkey= */ true, /* permit_bare_multisig= */ false, dust_relay_fee, reason); if (is_standard_without_permit_bare_multisig) { assert(is_standard_with_permit_bare_multisig); } diff --git a/src/test/script_p2sh_tests.cpp b/src/test/script_p2sh_tests.cpp index 54dcc218b9..9d7fd9d0a8 100644 --- a/src/test/script_p2sh_tests.cpp +++ b/src/test/script_p2sh_tests.cpp @@ -20,13 +20,13 @@ // Helpers: static bool IsStandardTx(const CTransaction& tx, bool permit_bare_multisig, std::string& reason) { - return IsStandardTx(tx, std::nullopt, permit_bare_multisig, CFeeRate{DUST_RELAY_TX_FEE}, reason); + return IsStandardTx(tx, std::nullopt, /*permit_bare_pubkey=*/true, permit_bare_multisig, CFeeRate{DUST_RELAY_TX_FEE}, reason); } static bool IsStandardTx(const CTransaction& tx, std::string& reason) { - return IsStandardTx(tx, std::nullopt, /*permit_bare_multisig=*/true, CFeeRate{DUST_RELAY_TX_FEE}, reason) && - IsStandardTx(tx, std::nullopt, /*permit_bare_multisig=*/false, CFeeRate{DUST_RELAY_TX_FEE}, reason); + return IsStandardTx(tx, std::nullopt, /*permit_bare_pubkey=*/true, /*permit_bare_multisig=*/true, CFeeRate{DUST_RELAY_TX_FEE}, reason) && + IsStandardTx(tx, std::nullopt, /*permit_bare_pubkey=*/true, /*permit_bare_multisig=*/false, CFeeRate{DUST_RELAY_TX_FEE}, reason); } static std::vector Serialize(const CScript& s) diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index d1cb2531aa..5c993fad4c 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -41,6 +41,7 @@ typedef std::vector valtype; static CFeeRate g_dust{DUST_RELAY_TX_FEE}; +static bool g_bare_pubkey{DEFAULT_PERMIT_BAREPUBKEY}; static bool g_bare_multi{DEFAULT_PERMIT_BAREMULTISIG}; static std::map mapFlagNames = { @@ -758,12 +759,12 @@ BOOST_AUTO_TEST_CASE(test_IsStandard) constexpr auto CheckIsStandard = [](const auto& t) { std::string reason; - BOOST_CHECK(IsStandardTx(CTransaction{t}, MAX_OP_RETURN_RELAY, g_bare_multi, g_dust, reason)); + BOOST_CHECK(IsStandardTx(CTransaction{t}, MAX_OP_RETURN_RELAY, g_bare_pubkey, g_bare_multi, g_dust, reason)); BOOST_CHECK(reason.empty()); }; constexpr auto CheckIsNotStandard = [](const auto& t, const std::string& reason_in) { std::string reason; - BOOST_CHECK(!IsStandardTx(CTransaction{t}, MAX_OP_RETURN_RELAY, g_bare_multi, g_dust, reason)); + BOOST_CHECK(!IsStandardTx(CTransaction{t}, MAX_OP_RETURN_RELAY, g_bare_pubkey, g_bare_multi, g_dust, reason)); BOOST_CHECK_EQUAL(reason_in, reason); }; diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 57a86549d9..fffac06ff1 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -401,6 +401,7 @@ CTxMemPool::CTxMemPool(const Options& opts) m_incremental_relay_feerate{opts.incremental_relay_feerate}, m_min_relay_feerate{opts.min_relay_feerate}, m_dust_relay_feerate{opts.dust_relay_feerate}, + m_permit_bare_pubkey{opts.permit_bare_pubkey}, m_permit_bare_multisig{opts.permit_bare_multisig}, m_max_datacarrier_bytes{opts.max_datacarrier_bytes}, m_require_standard{opts.require_standard}, diff --git a/src/txmempool.h b/src/txmempool.h index ca842632da..e4135fea30 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -439,6 +439,7 @@ public: const CFeeRate m_incremental_relay_feerate; const CFeeRate m_min_relay_feerate; const CFeeRate m_dust_relay_feerate; + const bool m_permit_bare_pubkey; const bool m_permit_bare_multisig; const std::optional m_max_datacarrier_bytes; const bool m_require_standard; diff --git a/src/validation.cpp b/src/validation.cpp index 8c583c586c..bf1cc7970c 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -718,7 +718,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) // Rather not work on nonstandard transactions (unless -testnet/-regtest) std::string reason; - if (m_pool.m_require_standard && !IsStandardTx(tx, m_pool.m_max_datacarrier_bytes, m_pool.m_permit_bare_multisig, m_pool.m_dust_relay_feerate, reason)) { + if (m_pool.m_require_standard && !IsStandardTx(tx, m_pool.m_max_datacarrier_bytes, m_pool.m_permit_bare_pubkey, m_pool.m_permit_bare_multisig, m_pool.m_dust_relay_feerate, reason)) { return state.Invalid(TxValidationResult::TX_NOT_STANDARD, reason); }