mirror of
https://github.com/Retropex/bitcoin.git
synced 2025-05-28 13:02:38 +02:00
refactor: policy: Pass kernel::MemPoolOptions to IsStandard[Tx] rather than long list of individual options
Github-Pull: #30232 Rebased-From: d4c3c2e9ae2536c345cc8f20c2de3a466eef7ced
This commit is contained in:
parent
bfaf703665
commit
734576e3e3
@ -11,6 +11,7 @@
|
||||
#include <consensus/amount.h>
|
||||
#include <consensus/consensus.h>
|
||||
#include <consensus/validation.h>
|
||||
#include <kernel/mempool_options.h>
|
||||
#include <policy/feerate.h>
|
||||
#include <primitives/transaction.h>
|
||||
#include <script/interpreter.h>
|
||||
@ -71,7 +72,7 @@ bool IsDust(const CTxOut& txout, const CFeeRate& dustRelayFeeIn)
|
||||
* Note this must assign whichType even if returning false, in case
|
||||
* IsStandardTx ignores the "scriptpubkey" rejection.
|
||||
*/
|
||||
bool IsStandard(const CScript& scriptPubKey, const std::optional<unsigned>& max_datacarrier_bytes, TxoutType& whichType)
|
||||
bool IsStandard(const CScript& scriptPubKey, const kernel::MemPoolOptions& opts, TxoutType& whichType)
|
||||
{
|
||||
std::vector<std::vector<unsigned char> > vSolutions;
|
||||
whichType = Solver(scriptPubKey, vSolutions);
|
||||
@ -87,7 +88,7 @@ bool IsStandard(const CScript& scriptPubKey, const std::optional<unsigned>& max_
|
||||
if (m < 1 || m > n)
|
||||
return false;
|
||||
} else if (whichType == TxoutType::NULL_DATA) {
|
||||
if (!max_datacarrier_bytes || scriptPubKey.size() > *max_datacarrier_bytes) {
|
||||
if (!opts.max_datacarrier_bytes || scriptPubKey.size() > *opts.max_datacarrier_bytes) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -110,7 +111,7 @@ static inline bool MaybeReject_(std::string& out_reason, const std::string& reas
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
bool IsStandardTx(const CTransaction& tx, const std::optional<unsigned>& max_datacarrier_bytes, bool permit_bare_multisig, const CFeeRate& dust_relay_fee, std::string& out_reason, const ignore_rejects_type& ignore_rejects)
|
||||
bool IsStandardTx(const CTransaction& tx, const kernel::MemPoolOptions& opts, std::string& out_reason, const ignore_rejects_type& ignore_rejects)
|
||||
{
|
||||
const std::string reason_prefix;
|
||||
|
||||
@ -148,7 +149,7 @@ bool IsStandardTx(const CTransaction& tx, const std::optional<unsigned>& max_dat
|
||||
unsigned int nDataOut = 0;
|
||||
TxoutType whichType;
|
||||
for (const CTxOut& txout : tx.vout) {
|
||||
if (!::IsStandard(txout.scriptPubKey, max_datacarrier_bytes, whichType)) {
|
||||
if (!::IsStandard(txout.scriptPubKey, opts, whichType)) {
|
||||
if (whichType == TxoutType::WITNESS_UNKNOWN) {
|
||||
MaybeReject("scriptpubkey-unknown-witnessversion");
|
||||
} else {
|
||||
@ -160,10 +161,10 @@ bool IsStandardTx(const CTransaction& tx, const std::optional<unsigned>& max_dat
|
||||
nDataOut++;
|
||||
continue;
|
||||
}
|
||||
else if ((whichType == TxoutType::MULTISIG) && (!permit_bare_multisig)) {
|
||||
else if ((whichType == TxoutType::MULTISIG) && (!opts.permit_bare_multisig)) {
|
||||
MaybeReject("bare-multisig");
|
||||
}
|
||||
if (IsDust(txout, dust_relay_fee)) {
|
||||
if (IsDust(txout, opts.dust_relay_feerate)) {
|
||||
MaybeReject("dust");
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,9 @@
|
||||
class CCoinsViewCache;
|
||||
class CFeeRate;
|
||||
class CScript;
|
||||
namespace kernel {
|
||||
struct MemPoolOptions;
|
||||
};
|
||||
|
||||
/** Default for -blockmaxweight, which controls the range of block weights the mining code will create **/
|
||||
static constexpr unsigned int DEFAULT_BLOCK_MAX_WEIGHT{MAX_BLOCK_WEIGHT - 4000};
|
||||
@ -129,7 +132,7 @@ CAmount GetDustThreshold(const CTxOut& txout, const CFeeRate& dustRelayFee);
|
||||
|
||||
bool IsDust(const CTxOut& txout, const CFeeRate& dustRelayFee);
|
||||
|
||||
bool IsStandard(const CScript& scriptPubKey, const std::optional<unsigned>& max_datacarrier_bytes, TxoutType& whichType);
|
||||
bool IsStandard(const CScript& scriptPubKey, const kernel::MemPoolOptions& opts, TxoutType& whichType);
|
||||
|
||||
|
||||
// Changing the default transaction version requires a two step process: first
|
||||
@ -141,7 +144,7 @@ static constexpr decltype(CTransaction::version) TX_MAX_STANDARD_VERSION{3};
|
||||
* Check for standard transaction types
|
||||
* @return True if all outputs (scriptPubKeys) use only standard transaction forms
|
||||
*/
|
||||
bool IsStandardTx(const CTransaction& tx, const std::optional<unsigned>& max_datacarrier_bytes, bool permit_bare_multisig, const CFeeRate& dust_relay_fee, std::string& out_reason, const ignore_rejects_type& ignore_rejects=empty_ignore_rejects);
|
||||
bool IsStandardTx(const CTransaction& tx, const kernel::MemPoolOptions& opts, std::string& out_reason, const ignore_rejects_type& ignore_rejects=empty_ignore_rejects);
|
||||
/**
|
||||
* Check for standard transaction types
|
||||
* @param[in] mapInputs Map of previous transactions that have outputs we're spending
|
||||
|
@ -3,6 +3,7 @@
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <chainparams.h>
|
||||
#include <kernel/mempool_options.h>
|
||||
#include <key.h>
|
||||
#include <key_io.h>
|
||||
#include <outputtype.h>
|
||||
@ -149,12 +150,12 @@ FUZZ_TARGET(key, .init = initialize_key)
|
||||
assert(fillable_signing_provider_pub.HaveKey(pubkey.GetID()));
|
||||
|
||||
TxoutType which_type_tx_pubkey;
|
||||
const bool is_standard_tx_pubkey = IsStandard(tx_pubkey_script, std::nullopt, which_type_tx_pubkey);
|
||||
const bool is_standard_tx_pubkey = IsStandard(tx_pubkey_script, kernel::MemPoolOptions{}, which_type_tx_pubkey);
|
||||
assert(is_standard_tx_pubkey);
|
||||
assert(which_type_tx_pubkey == TxoutType::PUBKEY);
|
||||
|
||||
TxoutType which_type_tx_multisig;
|
||||
const bool is_standard_tx_multisig = IsStandard(tx_multisig_script, std::nullopt, which_type_tx_multisig);
|
||||
const bool is_standard_tx_multisig = IsStandard(tx_multisig_script, kernel::MemPoolOptions{.permit_bare_multisig = true}, which_type_tx_multisig);
|
||||
assert(is_standard_tx_multisig);
|
||||
assert(which_type_tx_multisig == TxoutType::MULTISIG);
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <compressor.h>
|
||||
#include <core_io.h>
|
||||
#include <core_memusage.h>
|
||||
#include <kernel/mempool_options.h>
|
||||
#include <key_io.h>
|
||||
#include <policy/policy.h>
|
||||
#include <pubkey.h>
|
||||
@ -53,7 +54,7 @@ FUZZ_TARGET(script, .init = initialize_script)
|
||||
}
|
||||
|
||||
TxoutType which_type;
|
||||
bool is_standard_ret = IsStandard(script, std::nullopt, which_type);
|
||||
bool is_standard_ret = IsStandard(script, kernel::MemPoolOptions{}, which_type);
|
||||
if (!is_standard_ret) {
|
||||
assert(which_type == TxoutType::NONSTANDARD ||
|
||||
which_type == TxoutType::NULL_DATA ||
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <consensus/validation.h>
|
||||
#include <core_io.h>
|
||||
#include <core_memusage.h>
|
||||
#include <kernel/mempool_options.h>
|
||||
#include <policy/policy.h>
|
||||
#include <policy/settings.h>
|
||||
#include <primitives/transaction.h>
|
||||
@ -57,10 +58,9 @@ FUZZ_TARGET(transaction, .init = initialize_transaction)
|
||||
Assert(res == state_with_dupe_check.IsValid());
|
||||
}
|
||||
|
||||
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, kernel::MemPoolOptions{.permit_bare_multisig = true}, reason);
|
||||
const bool is_standard_without_permit_bare_multisig = IsStandardTx(tx, kernel::MemPoolOptions{.permit_bare_multisig = false}, reason);
|
||||
if (is_standard_without_permit_bare_multisig) {
|
||||
assert(is_standard_with_permit_bare_multisig);
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <kernel/mempool_options.h>
|
||||
#include <key.h>
|
||||
#include <policy/policy.h>
|
||||
#include <script/interpreter.h>
|
||||
@ -143,7 +144,7 @@ BOOST_AUTO_TEST_CASE(multisig_IsStandard)
|
||||
|
||||
const auto is_standard{[](const CScript& spk) {
|
||||
TxoutType type;
|
||||
bool res{::IsStandard(spk, std::nullopt, type)};
|
||||
bool res{::IsStandard(spk, kernel::MemPoolOptions{.max_datacarrier_bytes = std::nullopt}, type)};
|
||||
if (res) {
|
||||
BOOST_CHECK_EQUAL(type, TxoutType::MULTISIG);
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <consensus/tx_verify.h>
|
||||
#include <kernel/mempool_options.h>
|
||||
#include <key.h>
|
||||
#include <policy/policy.h>
|
||||
#include <policy/settings.h>
|
||||
@ -20,13 +21,20 @@
|
||||
// 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);
|
||||
const kernel::MemPoolOptions opts{
|
||||
.permit_bare_multisig = permit_bare_multisig,
|
||||
};
|
||||
return IsStandardTx(tx, opts, 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);
|
||||
kernel::MemPoolOptions opts{
|
||||
.permit_bare_multisig = true,
|
||||
};
|
||||
if (!IsStandardTx(tx, opts, reason)) return false;
|
||||
opts.permit_bare_multisig = false;
|
||||
return IsStandardTx(tx, opts, reason);
|
||||
}
|
||||
|
||||
static std::vector<unsigned char> Serialize(const CScript& s)
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <consensus/tx_check.h>
|
||||
#include <consensus/validation.h>
|
||||
#include <core_io.h>
|
||||
#include <kernel/mempool_options.h>
|
||||
#include <key.h>
|
||||
#include <policy/policy.h>
|
||||
#include <policy/settings.h>
|
||||
@ -44,8 +45,7 @@ using util::ToString;
|
||||
|
||||
typedef std::vector<unsigned char> valtype;
|
||||
|
||||
static CFeeRate g_dust{DUST_RELAY_TX_FEE};
|
||||
static bool g_bare_multi{DEFAULT_PERMIT_BAREMULTISIG};
|
||||
static kernel::MemPoolOptions g_mempool_opts;
|
||||
|
||||
static std::map<std::string, unsigned int> mapFlagNames = {
|
||||
{std::string("P2SH"), (unsigned int)SCRIPT_VERIFY_P2SH},
|
||||
@ -798,19 +798,19 @@ 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}, g_mempool_opts, 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}, g_mempool_opts, reason));
|
||||
BOOST_CHECK_EQUAL(reason_in, reason);
|
||||
};
|
||||
|
||||
CheckIsStandard(t);
|
||||
|
||||
// Check dust with default relay fee:
|
||||
CAmount nDustThreshold = 182 * g_dust.GetFeePerK() / 1000;
|
||||
CAmount nDustThreshold = 182 * g_mempool_opts.dust_relay_feerate.GetFeePerK() / 1000;
|
||||
BOOST_CHECK_EQUAL(nDustThreshold, 546);
|
||||
// dust:
|
||||
t.vout[0].nValue = nDustThreshold - 1;
|
||||
@ -838,14 +838,14 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
|
||||
|
||||
// Check dust with odd relay fee to verify rounding:
|
||||
// nDustThreshold = 182 * 3702 / 1000
|
||||
g_dust = CFeeRate(3702);
|
||||
g_mempool_opts.dust_relay_feerate = CFeeRate(3702);
|
||||
// dust:
|
||||
t.vout[0].nValue = 674 - 1;
|
||||
CheckIsNotStandard(t, "dust");
|
||||
// not dust:
|
||||
t.vout[0].nValue = 674;
|
||||
CheckIsStandard(t);
|
||||
g_dust = CFeeRate{DUST_RELAY_TX_FEE};
|
||||
g_mempool_opts.dust_relay_feerate = CFeeRate{DUST_RELAY_TX_FEE};
|
||||
|
||||
t.vout[0].scriptPubKey = CScript() << OP_1;
|
||||
CheckIsNotStandard(t, "scriptpubkey");
|
||||
@ -958,15 +958,15 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
|
||||
CheckIsNotStandard(t, "tx-size");
|
||||
|
||||
// Check bare multisig (standard if policy flag g_bare_multi is set)
|
||||
g_bare_multi = true;
|
||||
g_mempool_opts.permit_bare_multisig = true;
|
||||
t.vout[0].scriptPubKey = GetScriptForMultisig(1, {key.GetPubKey()}); // simple 1-of-1
|
||||
t.vin.resize(1);
|
||||
t.vin[0].scriptSig = CScript() << std::vector<unsigned char>(65, 0);
|
||||
CheckIsStandard(t);
|
||||
|
||||
g_bare_multi = false;
|
||||
g_mempool_opts.permit_bare_multisig = false;
|
||||
CheckIsNotStandard(t, "bare-multisig");
|
||||
g_bare_multi = DEFAULT_PERMIT_BAREMULTISIG;
|
||||
g_mempool_opts.permit_bare_multisig = DEFAULT_PERMIT_BAREMULTISIG;
|
||||
|
||||
// Check compressed P2PK outputs dust threshold (must have leading 02 or 03)
|
||||
t.vout[0].scriptPubKey = CScript() << std::vector<unsigned char>(33, 0x02) << OP_CHECKSIG;
|
||||
|
@ -810,7 +810,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
|
||||
|
||||
// Rather not work on nonstandard transactions (unless -testnet/-regtest)
|
||||
std::string reason;
|
||||
if (m_pool.m_opts.require_standard && !IsStandardTx(tx, m_pool.m_opts.max_datacarrier_bytes, m_pool.m_opts.permit_bare_multisig, m_pool.m_opts.dust_relay_feerate, reason, ignore_rejects)) {
|
||||
if (m_pool.m_opts.require_standard && !IsStandardTx(tx, m_pool.m_opts, reason, ignore_rejects)) {
|
||||
return state.Invalid(TxValidationResult::TX_NOT_STANDARD, reason);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user