mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-04-29 14:59:39 -04:00
Merge 47e713ea5a
into 65714c162c
This commit is contained in:
commit
570b245d1a
30 changed files with 90 additions and 197 deletions
|
@ -635,12 +635,6 @@ void SetupServerArgs(ArgsManager& argsman, bool can_listen_ipc)
|
||||||
argsman.AddArg("-dustrelayfee=<amt>", strprintf("Fee rate (in %s/kvB) used to define dust, the value of an output such that it will cost more than its value in fees at this fee rate to spend it. (default: %s)", CURRENCY_UNIT, FormatMoney(DUST_RELAY_TX_FEE)), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::NODE_RELAY);
|
argsman.AddArg("-dustrelayfee=<amt>", strprintf("Fee rate (in %s/kvB) used to define dust, the value of an output such that it will cost more than its value in fees at this fee rate to spend it. (default: %s)", CURRENCY_UNIT, FormatMoney(DUST_RELAY_TX_FEE)), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::NODE_RELAY);
|
||||||
argsman.AddArg("-acceptstalefeeestimates", strprintf("Read fee estimates even if they are stale (%sdefault: %u) fee estimates are considered stale if they are %s hours old", "regtest only; ", DEFAULT_ACCEPT_STALE_FEE_ESTIMATES, Ticks<std::chrono::hours>(MAX_FILE_AGE)), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
|
argsman.AddArg("-acceptstalefeeestimates", strprintf("Read fee estimates even if they are stale (%sdefault: %u) fee estimates are considered stale if they are %s hours old", "regtest only; ", DEFAULT_ACCEPT_STALE_FEE_ESTIMATES, Ticks<std::chrono::hours>(MAX_FILE_AGE)), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
|
||||||
argsman.AddArg("-bytespersigop", strprintf("Equivalent bytes per sigop in transactions for relay and mining (default: %u)", DEFAULT_BYTES_PER_SIGOP), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
|
argsman.AddArg("-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)",
|
|
||||||
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,
|
argsman.AddArg("-permitbaremultisig", strprintf("Relay transactions creating non-P2SH multisig outputs (default: %u)", DEFAULT_PERMIT_BAREMULTISIG), ArgsManager::ALLOW_ANY,
|
||||||
OptionsCategory::NODE_RELAY);
|
OptionsCategory::NODE_RELAY);
|
||||||
argsman.AddArg("-minrelaytxfee=<amt>", strprintf("Fees (in %s/kvB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s)",
|
argsman.AddArg("-minrelaytxfee=<amt>", strprintf("Fees (in %s/kvB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s)",
|
||||||
|
|
|
@ -43,14 +43,6 @@ struct MemPoolOptions {
|
||||||
/** A fee rate smaller than this is considered zero fee (for relaying, mining and transaction creation) */
|
/** A fee rate smaller than this is considered zero fee (for relaying, mining and transaction creation) */
|
||||||
CFeeRate min_relay_feerate{DEFAULT_MIN_RELAY_TX_FEE};
|
CFeeRate min_relay_feerate{DEFAULT_MIN_RELAY_TX_FEE};
|
||||||
CFeeRate dust_relay_feerate{DUST_RELAY_TX_FEE};
|
CFeeRate dust_relay_feerate{DUST_RELAY_TX_FEE};
|
||||||
/**
|
|
||||||
* A data carrying output is an unspendable output containing data. The script
|
|
||||||
* type is designated as TxoutType::NULL_DATA.
|
|
||||||
*
|
|
||||||
* Maximum size of TxoutType::NULL_DATA scripts that this node considers standard.
|
|
||||||
* If nullopt, any size is nonstandard.
|
|
||||||
*/
|
|
||||||
std::optional<unsigned> max_datacarrier_bytes{DEFAULT_ACCEPT_DATACARRIER ? std::optional{MAX_OP_RETURN_RELAY} : std::nullopt};
|
|
||||||
bool permit_bare_multisig{DEFAULT_PERMIT_BAREMULTISIG};
|
bool permit_bare_multisig{DEFAULT_PERMIT_BAREMULTISIG};
|
||||||
bool require_standard{true};
|
bool require_standard{true};
|
||||||
bool persist_v1_dat{DEFAULT_PERSIST_V1_DAT};
|
bool persist_v1_dat{DEFAULT_PERSIST_V1_DAT};
|
||||||
|
|
|
@ -81,12 +81,6 @@ util::Result<void> ApplyArgsManOptions(const ArgsManager& argsman, const CChainP
|
||||||
|
|
||||||
mempool_opts.permit_bare_multisig = argsman.GetBoolArg("-permitbaremultisig", DEFAULT_PERMIT_BAREMULTISIG);
|
mempool_opts.permit_bare_multisig = argsman.GetBoolArg("-permitbaremultisig", DEFAULT_PERMIT_BAREMULTISIG);
|
||||||
|
|
||||||
if (argsman.GetBoolArg("-datacarrier", DEFAULT_ACCEPT_DATACARRIER)) {
|
|
||||||
mempool_opts.max_datacarrier_bytes = argsman.GetIntArg("-datacarriersize", MAX_OP_RETURN_RELAY);
|
|
||||||
} else {
|
|
||||||
mempool_opts.max_datacarrier_bytes = std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
mempool_opts.require_standard = !argsman.GetBoolArg("-acceptnonstdtxn", DEFAULT_ACCEPT_NON_STD_TXN);
|
mempool_opts.require_standard = !argsman.GetBoolArg("-acceptnonstdtxn", DEFAULT_ACCEPT_NON_STD_TXN);
|
||||||
if (!chainparams.IsTestChain() && !mempool_opts.require_standard) {
|
if (!chainparams.IsTestChain() && !mempool_opts.require_standard) {
|
||||||
return util::Error{Untranslated(strprintf("acceptnonstdtxn is not currently supported for %s chain", chainparams.GetChainTypeString()))};
|
return util::Error{Untranslated(strprintf("acceptnonstdtxn is not currently supported for %s chain", chainparams.GetChainTypeString()))};
|
||||||
|
|
|
@ -76,7 +76,7 @@ std::vector<uint32_t> GetDust(const CTransaction& tx, CFeeRate dust_relay_rate)
|
||||||
return dust_outputs;
|
return dust_outputs;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsStandard(const CScript& scriptPubKey, const std::optional<unsigned>& max_datacarrier_bytes, TxoutType& whichType)
|
bool IsStandard(const CScript& scriptPubKey, TxoutType& whichType)
|
||||||
{
|
{
|
||||||
std::vector<std::vector<unsigned char> > vSolutions;
|
std::vector<std::vector<unsigned char> > vSolutions;
|
||||||
whichType = Solver(scriptPubKey, vSolutions);
|
whichType = Solver(scriptPubKey, vSolutions);
|
||||||
|
@ -91,16 +91,12 @@ bool IsStandard(const CScript& scriptPubKey, const std::optional<unsigned>& max_
|
||||||
return false;
|
return false;
|
||||||
if (m < 1 || m > n)
|
if (m < 1 || m > n)
|
||||||
return false;
|
return false;
|
||||||
} else if (whichType == TxoutType::NULL_DATA) {
|
|
||||||
if (!max_datacarrier_bytes || scriptPubKey.size() > *max_datacarrier_bytes) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsStandardTx(const CTransaction& tx, const std::optional<unsigned>& max_datacarrier_bytes, bool permit_bare_multisig, const CFeeRate& dust_relay_fee, std::string& reason)
|
bool IsStandardTx(const CTransaction& tx, bool permit_bare_multisig, const CFeeRate& dust_relay_fee, std::string& reason)
|
||||||
{
|
{
|
||||||
if (tx.version > TX_MAX_STANDARD_VERSION || tx.version < 1) {
|
if (tx.version > TX_MAX_STANDARD_VERSION || tx.version < 1) {
|
||||||
reason = "version";
|
reason = "version";
|
||||||
|
@ -137,17 +133,14 @@ bool IsStandardTx(const CTransaction& tx, const std::optional<unsigned>& max_dat
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int nDataOut = 0;
|
|
||||||
TxoutType whichType;
|
TxoutType whichType;
|
||||||
for (const CTxOut& txout : tx.vout) {
|
for (const CTxOut& txout : tx.vout) {
|
||||||
if (!::IsStandard(txout.scriptPubKey, max_datacarrier_bytes, whichType)) {
|
if (!::IsStandard(txout.scriptPubKey, whichType)) {
|
||||||
reason = "scriptpubkey";
|
reason = "scriptpubkey";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (whichType == TxoutType::NULL_DATA)
|
if ((whichType == TxoutType::MULTISIG) && (!permit_bare_multisig)) {
|
||||||
nDataOut++;
|
|
||||||
else if ((whichType == TxoutType::MULTISIG) && (!permit_bare_multisig)) {
|
|
||||||
reason = "bare-multisig";
|
reason = "bare-multisig";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -159,12 +152,6 @@ bool IsStandardTx(const CTransaction& tx, const std::optional<unsigned>& max_dat
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// only one OP_RETURN txout is permitted
|
|
||||||
if (nDataOut > 1) {
|
|
||||||
reason = "multi-op-return";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -70,13 +70,6 @@ static constexpr unsigned int DEFAULT_ANCESTOR_SIZE_LIMIT_KVB{101};
|
||||||
static constexpr unsigned int DEFAULT_DESCENDANT_LIMIT{25};
|
static constexpr unsigned int DEFAULT_DESCENDANT_LIMIT{25};
|
||||||
/** Default for -limitdescendantsize, maximum kilobytes of in-mempool descendants */
|
/** Default for -limitdescendantsize, maximum kilobytes of in-mempool descendants */
|
||||||
static constexpr unsigned int DEFAULT_DESCENDANT_SIZE_LIMIT_KVB{101};
|
static constexpr unsigned int DEFAULT_DESCENDANT_SIZE_LIMIT_KVB{101};
|
||||||
/** Default for -datacarrier */
|
|
||||||
static const bool DEFAULT_ACCEPT_DATACARRIER = true;
|
|
||||||
/**
|
|
||||||
* Default setting for -datacarriersize. 80 bytes of data, +1 for OP_RETURN,
|
|
||||||
* +2 for the pushdata opcodes.
|
|
||||||
*/
|
|
||||||
static const unsigned int MAX_OP_RETURN_RELAY = 83;
|
|
||||||
/**
|
/**
|
||||||
* An extra transaction can be added to a package, as long as it only has one
|
* An extra transaction can be added to a package, as long as it only has one
|
||||||
* ancestor and is no larger than this. Not really any reason to make this
|
* ancestor and is no larger than this. Not really any reason to make this
|
||||||
|
@ -136,7 +129,7 @@ CAmount GetDustThreshold(const CTxOut& txout, const CFeeRate& dustRelayFee);
|
||||||
|
|
||||||
bool IsDust(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, TxoutType& whichType);
|
||||||
|
|
||||||
/** Get the vout index numbers of all dust outputs */
|
/** Get the vout index numbers of all dust outputs */
|
||||||
std::vector<uint32_t> GetDust(const CTransaction& tx, CFeeRate dust_relay_rate);
|
std::vector<uint32_t> GetDust(const CTransaction& tx, CFeeRate dust_relay_rate);
|
||||||
|
@ -150,7 +143,7 @@ static constexpr decltype(CTransaction::version) TX_MAX_STANDARD_VERSION{3};
|
||||||
* Check for standard transaction types
|
* Check for standard transaction types
|
||||||
* @return True if all outputs (scriptPubKeys) use only standard transaction forms
|
* @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& reason);
|
bool IsStandardTx(const CTransaction& tx, bool permit_bare_multisig, const CFeeRate& dust_relay_fee, std::string& reason);
|
||||||
/**
|
/**
|
||||||
* Check for standard transaction types
|
* Check for standard transaction types
|
||||||
* @param[in] mapInputs Map of previous transactions that have outputs we're spending
|
* @param[in] mapInputs Map of previous transactions that have outputs we're spending
|
||||||
|
|
|
@ -151,12 +151,12 @@ FUZZ_TARGET(key, .init = initialize_key)
|
||||||
assert(fillable_signing_provider_pub.HaveKey(pubkey.GetID()));
|
assert(fillable_signing_provider_pub.HaveKey(pubkey.GetID()));
|
||||||
|
|
||||||
TxoutType which_type_tx_pubkey;
|
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, which_type_tx_pubkey);
|
||||||
assert(is_standard_tx_pubkey);
|
assert(is_standard_tx_pubkey);
|
||||||
assert(which_type_tx_pubkey == TxoutType::PUBKEY);
|
assert(which_type_tx_pubkey == TxoutType::PUBKEY);
|
||||||
|
|
||||||
TxoutType which_type_tx_multisig;
|
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, which_type_tx_multisig);
|
||||||
assert(is_standard_tx_multisig);
|
assert(is_standard_tx_multisig);
|
||||||
assert(which_type_tx_multisig == TxoutType::MULTISIG);
|
assert(which_type_tx_multisig == TxoutType::MULTISIG);
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@ FUZZ_TARGET(script, .init = initialize_script)
|
||||||
}
|
}
|
||||||
|
|
||||||
TxoutType which_type;
|
TxoutType which_type;
|
||||||
bool is_standard_ret = IsStandard(script, std::nullopt, which_type);
|
bool is_standard_ret = IsStandard(script, which_type);
|
||||||
if (!is_standard_ret) {
|
if (!is_standard_ret) {
|
||||||
assert(which_type == TxoutType::NONSTANDARD ||
|
assert(which_type == TxoutType::NONSTANDARD ||
|
||||||
which_type == TxoutType::NULL_DATA ||
|
which_type == TxoutType::NULL_DATA ||
|
||||||
|
|
|
@ -61,8 +61,8 @@ FUZZ_TARGET(transaction, .init = initialize_transaction)
|
||||||
|
|
||||||
const CFeeRate dust_relay_fee{DUST_RELAY_TX_FEE};
|
const CFeeRate dust_relay_fee{DUST_RELAY_TX_FEE};
|
||||||
std::string reason;
|
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_with_permit_bare_multisig = IsStandardTx(tx, /* 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_without_permit_bare_multisig = IsStandardTx(tx, /* permit_bare_multisig= */ false, dust_relay_fee, reason);
|
||||||
if (is_standard_without_permit_bare_multisig) {
|
if (is_standard_without_permit_bare_multisig) {
|
||||||
assert(is_standard_with_permit_bare_multisig);
|
assert(is_standard_with_permit_bare_multisig);
|
||||||
}
|
}
|
||||||
|
|
|
@ -144,7 +144,7 @@ BOOST_AUTO_TEST_CASE(multisig_IsStandard)
|
||||||
|
|
||||||
const auto is_standard{[](const CScript& spk) {
|
const auto is_standard{[](const CScript& spk) {
|
||||||
TxoutType type;
|
TxoutType type;
|
||||||
bool res{::IsStandard(spk, std::nullopt, type)};
|
bool res{::IsStandard(spk, type)};
|
||||||
if (res) {
|
if (res) {
|
||||||
BOOST_CHECK_EQUAL(type, TxoutType::MULTISIG);
|
BOOST_CHECK_EQUAL(type, TxoutType::MULTISIG);
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,13 +21,13 @@
|
||||||
// Helpers:
|
// Helpers:
|
||||||
static bool IsStandardTx(const CTransaction& tx, bool permit_bare_multisig, std::string& reason)
|
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, permit_bare_multisig, CFeeRate{DUST_RELAY_TX_FEE}, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool IsStandardTx(const CTransaction& tx, std::string& 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) &&
|
return IsStandardTx(tx, /*permit_bare_multisig=*/true, CFeeRate{DUST_RELAY_TX_FEE}, reason) &&
|
||||||
IsStandardTx(tx, std::nullopt, /*permit_bare_multisig=*/false, CFeeRate{DUST_RELAY_TX_FEE}, reason);
|
IsStandardTx(tx, /*permit_bare_multisig=*/false, CFeeRate{DUST_RELAY_TX_FEE}, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::vector<unsigned char> Serialize(const CScript& s)
|
static std::vector<unsigned char> Serialize(const CScript& s)
|
||||||
|
|
|
@ -799,12 +799,12 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
|
||||||
|
|
||||||
constexpr auto CheckIsStandard = [](const auto& t) {
|
constexpr auto CheckIsStandard = [](const auto& t) {
|
||||||
std::string reason;
|
std::string reason;
|
||||||
BOOST_CHECK(IsStandardTx(CTransaction{t}, MAX_OP_RETURN_RELAY, g_bare_multi, g_dust, reason));
|
BOOST_CHECK(IsStandardTx(CTransaction{t}, g_bare_multi, g_dust, reason));
|
||||||
BOOST_CHECK(reason.empty());
|
BOOST_CHECK(reason.empty());
|
||||||
};
|
};
|
||||||
constexpr auto CheckIsNotStandard = [](const auto& t, const std::string& reason_in) {
|
constexpr auto CheckIsNotStandard = [](const auto& t, const std::string& reason_in) {
|
||||||
std::string reason;
|
std::string reason;
|
||||||
BOOST_CHECK(!IsStandardTx(CTransaction{t}, MAX_OP_RETURN_RELAY, g_bare_multi, g_dust, reason));
|
BOOST_CHECK(!IsStandardTx(CTransaction{t}, g_bare_multi, g_dust, reason));
|
||||||
BOOST_CHECK_EQUAL(reason_in, reason);
|
BOOST_CHECK_EQUAL(reason_in, reason);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -858,15 +858,13 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
|
||||||
t.vout[0].scriptPubKey = CScript() << OP_1;
|
t.vout[0].scriptPubKey = CScript() << OP_1;
|
||||||
CheckIsNotStandard(t, "scriptpubkey");
|
CheckIsNotStandard(t, "scriptpubkey");
|
||||||
|
|
||||||
// MAX_OP_RETURN_RELAY-byte TxoutType::NULL_DATA (standard)
|
// TxoutType::NULL_DATA
|
||||||
t.vout[0].scriptPubKey = CScript() << OP_RETURN << "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"_hex;
|
//
|
||||||
BOOST_CHECK_EQUAL(MAX_OP_RETURN_RELAY, t.vout[0].scriptPubKey.size());
|
// Until v30 OP_RETURN was limited to 83 bytes (80 bytes of data, +1 for
|
||||||
CheckIsStandard(t);
|
// OP_RETURN, +2 for the pushdata opcodes). Here we test with 84 bytes.
|
||||||
|
|
||||||
// MAX_OP_RETURN_RELAY+1-byte TxoutType::NULL_DATA (non-standard)
|
|
||||||
t.vout[0].scriptPubKey = CScript() << OP_RETURN << "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3800"_hex;
|
t.vout[0].scriptPubKey = CScript() << OP_RETURN << "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3800"_hex;
|
||||||
BOOST_CHECK_EQUAL(MAX_OP_RETURN_RELAY + 1, t.vout[0].scriptPubKey.size());
|
BOOST_CHECK_EQUAL(84, t.vout[0].scriptPubKey.size());
|
||||||
CheckIsNotStandard(t, "scriptpubkey");
|
CheckIsStandard(t);
|
||||||
|
|
||||||
// Data payload can be encoded in any way...
|
// Data payload can be encoded in any way...
|
||||||
t.vout[0].scriptPubKey = CScript() << OP_RETURN << ""_hex;
|
t.vout[0].scriptPubKey = CScript() << OP_RETURN << ""_hex;
|
||||||
|
@ -888,21 +886,21 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
|
||||||
t.vout[0].scriptPubKey = CScript() << OP_RETURN;
|
t.vout[0].scriptPubKey = CScript() << OP_RETURN;
|
||||||
CheckIsStandard(t);
|
CheckIsStandard(t);
|
||||||
|
|
||||||
// Only one TxoutType::NULL_DATA permitted in all cases
|
// Multiple TxoutType::NULL_DATA outputs are permitted
|
||||||
t.vout.resize(2);
|
t.vout.resize(2);
|
||||||
t.vout[0].scriptPubKey = CScript() << OP_RETURN << "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"_hex;
|
t.vout[0].scriptPubKey = CScript() << OP_RETURN << "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"_hex;
|
||||||
t.vout[0].nValue = 0;
|
t.vout[0].nValue = 0;
|
||||||
t.vout[1].scriptPubKey = CScript() << OP_RETURN << "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"_hex;
|
t.vout[1].scriptPubKey = CScript() << OP_RETURN << "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"_hex;
|
||||||
t.vout[1].nValue = 0;
|
t.vout[1].nValue = 0;
|
||||||
CheckIsNotStandard(t, "multi-op-return");
|
CheckIsStandard(t);
|
||||||
|
|
||||||
t.vout[0].scriptPubKey = CScript() << OP_RETURN << "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"_hex;
|
t.vout[0].scriptPubKey = CScript() << OP_RETURN << "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"_hex;
|
||||||
t.vout[1].scriptPubKey = CScript() << OP_RETURN;
|
t.vout[1].scriptPubKey = CScript() << OP_RETURN;
|
||||||
CheckIsNotStandard(t, "multi-op-return");
|
CheckIsStandard(t);
|
||||||
|
|
||||||
t.vout[0].scriptPubKey = CScript() << OP_RETURN;
|
t.vout[0].scriptPubKey = CScript() << OP_RETURN;
|
||||||
t.vout[1].scriptPubKey = CScript() << OP_RETURN;
|
t.vout[1].scriptPubKey = CScript() << OP_RETURN;
|
||||||
CheckIsNotStandard(t, "multi-op-return");
|
CheckIsStandard(t);
|
||||||
|
|
||||||
// Check large scriptSig (non-standard if size is >1650 bytes)
|
// Check large scriptSig (non-standard if size is >1650 bytes)
|
||||||
t.vout.resize(1);
|
t.vout.resize(1);
|
||||||
|
|
|
@ -790,7 +790,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
|
||||||
|
|
||||||
// Rather not work on nonstandard transactions (unless -testnet/-regtest)
|
// Rather not work on nonstandard transactions (unless -testnet/-regtest)
|
||||||
std::string reason;
|
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)) {
|
if (m_pool.m_opts.require_standard && !IsStandardTx(tx, m_pool.m_opts.permit_bare_multisig, m_pool.m_opts.dust_relay_feerate, reason)) {
|
||||||
return state.Invalid(TxValidationResult::TX_NOT_STANDARD, reason);
|
return state.Invalid(TxValidationResult::TX_NOT_STANDARD, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,6 @@ class BlocksXORTest(BitcoinTestFramework):
|
||||||
self.extra_args = [[
|
self.extra_args = [[
|
||||||
'-blocksxor=1',
|
'-blocksxor=1',
|
||||||
'-fastprune=1', # use smaller block files
|
'-fastprune=1', # use smaller block files
|
||||||
'-datacarriersize=100000', # needed to pad transaction with MiniWallet
|
|
||||||
]]
|
]]
|
||||||
|
|
||||||
def run_test(self):
|
def run_test(self):
|
||||||
|
|
|
@ -51,7 +51,6 @@ class MaxUploadTest(BitcoinTestFramework):
|
||||||
self.num_nodes = 1
|
self.num_nodes = 1
|
||||||
self.extra_args = [[
|
self.extra_args = [[
|
||||||
f"-maxuploadtarget={UPLOAD_TARGET_MB}M",
|
f"-maxuploadtarget={UPLOAD_TARGET_MB}M",
|
||||||
"-datacarriersize=100000",
|
|
||||||
]]
|
]]
|
||||||
self.supports_cli = False
|
self.supports_cli = False
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ from decimal import Decimal
|
||||||
import math
|
import math
|
||||||
|
|
||||||
from test_framework.test_framework import BitcoinTestFramework
|
from test_framework.test_framework import BitcoinTestFramework
|
||||||
|
from test_framework.blocktools import MAX_STANDARD_TX_WEIGHT
|
||||||
from test_framework.messages import (
|
from test_framework.messages import (
|
||||||
MAX_BIP125_RBF_SEQUENCE,
|
MAX_BIP125_RBF_SEQUENCE,
|
||||||
COIN,
|
COIN,
|
||||||
|
@ -326,11 +327,50 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
||||||
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'dust'}],
|
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'dust'}],
|
||||||
rawtxs=[tx.serialize().hex()],
|
rawtxs=[tx.serialize().hex()],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# OP_RETURN followed by non-push
|
||||||
tx = tx_from_hex(raw_tx_reference)
|
tx = tx_from_hex(raw_tx_reference)
|
||||||
tx.vout[0].scriptPubKey = CScript([OP_RETURN, b'\xff'])
|
tx.vout[0].scriptPubKey = CScript([OP_RETURN, OP_HASH160])
|
||||||
tx.vout = [tx.vout[0]] * 2
|
tx.vout = [tx.vout[0]] * 2
|
||||||
self.check_mempool_result(
|
self.check_mempool_result(
|
||||||
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'multi-op-return'}],
|
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'scriptpubkey'}],
|
||||||
|
rawtxs=[tx.serialize().hex()],
|
||||||
|
)
|
||||||
|
|
||||||
|
# Multiple OP_RETURN and more than 83 bytes are standard since v30
|
||||||
|
tx = tx_from_hex(raw_tx_reference)
|
||||||
|
tx.vout.append(CTxOut(0, CScript([OP_RETURN, b'\xff'])))
|
||||||
|
tx.vout.append(CTxOut(0, CScript([OP_RETURN, b'\xff' * 90])))
|
||||||
|
|
||||||
|
self.check_mempool_result(
|
||||||
|
result_expected=[{'txid': tx.rehash(), 'allowed': True, 'vsize': tx.get_vsize(), 'fees': {'base': Decimal('0.05')}}],
|
||||||
|
rawtxs=[tx.serialize().hex()],
|
||||||
|
maxfeerate=0
|
||||||
|
)
|
||||||
|
|
||||||
|
self.log.info("A transaction with several OP_RETURN outputs.")
|
||||||
|
tx = tx_from_hex(raw_tx_reference)
|
||||||
|
op_return_count = 42
|
||||||
|
tx.vout[0].nValue = int(tx.vout[0].nValue / op_return_count)
|
||||||
|
tx.vout[0].scriptPubKey = CScript([OP_RETURN, b'\xff'])
|
||||||
|
tx.vout = [tx.vout[0]] * op_return_count
|
||||||
|
self.check_mempool_result(
|
||||||
|
result_expected=[{"txid": tx.rehash(), "allowed": True, "vsize": tx.get_vsize(), "fees": {"base": Decimal("0.05000026")}}],
|
||||||
|
rawtxs=[tx.serialize().hex()],
|
||||||
|
)
|
||||||
|
|
||||||
|
self.log.info("A transaction with an OP_RETUN output that bumps into the max standardness tx size.")
|
||||||
|
tx = tx_from_hex(raw_tx_reference)
|
||||||
|
tx.vout[0].scriptPubKey = CScript([OP_RETURN])
|
||||||
|
data_len = int(MAX_STANDARD_TX_WEIGHT / 4) - tx.get_vsize() - 5 - 4 # -5 for PUSHDATA4 and -4 for script size
|
||||||
|
tx.vout[0].scriptPubKey = CScript([OP_RETURN, b"\xff" * (data_len)])
|
||||||
|
self.check_mempool_result(
|
||||||
|
result_expected=[{"txid": tx.rehash(), "allowed": True, "vsize": tx.get_vsize(), "fees": {"base": Decimal("0.1") - Decimal("0.05")}}],
|
||||||
|
rawtxs=[tx.serialize().hex()],
|
||||||
|
)
|
||||||
|
tx.vout[0].scriptPubKey = CScript([OP_RETURN, b"\xff" * (data_len + 1)])
|
||||||
|
self.check_mempool_result(
|
||||||
|
result_expected=[{"txid": tx.rehash(), "allowed": False, "reject-reason": "tx-size"}],
|
||||||
rawtxs=[tx.serialize().hex()],
|
rawtxs=[tx.serialize().hex()],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,91 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
# Copyright (c) 2020-2022 The Bitcoin Core developers
|
|
||||||
# Distributed under the MIT software license, see the accompanying
|
|
||||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
||||||
"""Test datacarrier functionality"""
|
|
||||||
from test_framework.messages import (
|
|
||||||
CTxOut,
|
|
||||||
MAX_OP_RETURN_RELAY,
|
|
||||||
)
|
|
||||||
from test_framework.script import (
|
|
||||||
CScript,
|
|
||||||
OP_RETURN,
|
|
||||||
)
|
|
||||||
from test_framework.test_framework import BitcoinTestFramework
|
|
||||||
from test_framework.test_node import TestNode
|
|
||||||
from test_framework.util import assert_raises_rpc_error
|
|
||||||
from test_framework.wallet import MiniWallet
|
|
||||||
|
|
||||||
from random import randbytes
|
|
||||||
|
|
||||||
|
|
||||||
class DataCarrierTest(BitcoinTestFramework):
|
|
||||||
def set_test_params(self):
|
|
||||||
self.num_nodes = 4
|
|
||||||
self.extra_args = [
|
|
||||||
[],
|
|
||||||
["-datacarrier=0"],
|
|
||||||
["-datacarrier=1", f"-datacarriersize={MAX_OP_RETURN_RELAY - 1}"],
|
|
||||||
["-datacarrier=1", "-datacarriersize=2"],
|
|
||||||
]
|
|
||||||
|
|
||||||
def test_null_data_transaction(self, node: TestNode, data, success: bool) -> None:
|
|
||||||
tx = self.wallet.create_self_transfer(fee_rate=0)["tx"]
|
|
||||||
data = [] if data is None else [data]
|
|
||||||
tx.vout.append(CTxOut(nValue=0, scriptPubKey=CScript([OP_RETURN] + data)))
|
|
||||||
tx.vout[0].nValue -= tx.get_vsize() # simply pay 1sat/vbyte fee
|
|
||||||
|
|
||||||
tx_hex = tx.serialize().hex()
|
|
||||||
|
|
||||||
if success:
|
|
||||||
self.wallet.sendrawtransaction(from_node=node, tx_hex=tx_hex)
|
|
||||||
assert tx.rehash() in node.getrawmempool(True), f'{tx_hex} not in mempool'
|
|
||||||
else:
|
|
||||||
assert_raises_rpc_error(-26, "scriptpubkey", self.wallet.sendrawtransaction, from_node=node, tx_hex=tx_hex)
|
|
||||||
|
|
||||||
def run_test(self):
|
|
||||||
self.wallet = MiniWallet(self.nodes[0])
|
|
||||||
|
|
||||||
# By default, only 80 bytes are used for data (+1 for OP_RETURN, +2 for the pushdata opcodes).
|
|
||||||
default_size_data = randbytes(MAX_OP_RETURN_RELAY - 3)
|
|
||||||
too_long_data = randbytes(MAX_OP_RETURN_RELAY - 2)
|
|
||||||
small_data = randbytes(MAX_OP_RETURN_RELAY - 4)
|
|
||||||
one_byte = randbytes(1)
|
|
||||||
zero_bytes = randbytes(0)
|
|
||||||
|
|
||||||
self.log.info("Testing null data transaction with default -datacarrier and -datacarriersize values.")
|
|
||||||
self.test_null_data_transaction(node=self.nodes[0], data=default_size_data, success=True)
|
|
||||||
|
|
||||||
self.log.info("Testing a null data transaction larger than allowed by the default -datacarriersize value.")
|
|
||||||
self.test_null_data_transaction(node=self.nodes[0], data=too_long_data, success=False)
|
|
||||||
|
|
||||||
self.log.info("Testing a null data transaction with -datacarrier=false.")
|
|
||||||
self.test_null_data_transaction(node=self.nodes[1], data=default_size_data, success=False)
|
|
||||||
|
|
||||||
self.log.info("Testing a null data transaction with a size larger than accepted by -datacarriersize.")
|
|
||||||
self.test_null_data_transaction(node=self.nodes[2], data=default_size_data, success=False)
|
|
||||||
|
|
||||||
self.log.info("Testing a null data transaction with a size smaller than accepted by -datacarriersize.")
|
|
||||||
self.test_null_data_transaction(node=self.nodes[2], data=small_data, success=True)
|
|
||||||
|
|
||||||
self.log.info("Testing a null data transaction with no data.")
|
|
||||||
self.test_null_data_transaction(node=self.nodes[0], data=None, success=True)
|
|
||||||
self.test_null_data_transaction(node=self.nodes[1], data=None, success=False)
|
|
||||||
self.test_null_data_transaction(node=self.nodes[2], data=None, success=True)
|
|
||||||
self.test_null_data_transaction(node=self.nodes[3], data=None, success=True)
|
|
||||||
|
|
||||||
self.log.info("Testing a null data transaction with zero bytes of data.")
|
|
||||||
self.test_null_data_transaction(node=self.nodes[0], data=zero_bytes, success=True)
|
|
||||||
self.test_null_data_transaction(node=self.nodes[1], data=zero_bytes, success=False)
|
|
||||||
self.test_null_data_transaction(node=self.nodes[2], data=zero_bytes, success=True)
|
|
||||||
self.test_null_data_transaction(node=self.nodes[3], data=zero_bytes, success=True)
|
|
||||||
|
|
||||||
self.log.info("Testing a null data transaction with one byte of data.")
|
|
||||||
self.test_null_data_transaction(node=self.nodes[0], data=one_byte, success=True)
|
|
||||||
self.test_null_data_transaction(node=self.nodes[1], data=one_byte, success=False)
|
|
||||||
self.test_null_data_transaction(node=self.nodes[2], data=one_byte, success=True)
|
|
||||||
self.test_null_data_transaction(node=self.nodes[3], data=one_byte, success=False)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
DataCarrierTest(__file__).main()
|
|
|
@ -29,7 +29,6 @@ class MempoolLimitTest(BitcoinTestFramework):
|
||||||
self.setup_clean_chain = True
|
self.setup_clean_chain = True
|
||||||
self.num_nodes = 1
|
self.num_nodes = 1
|
||||||
self.extra_args = [[
|
self.extra_args = [[
|
||||||
"-datacarriersize=100000",
|
|
||||||
"-maxmempool=5",
|
"-maxmempool=5",
|
||||||
]]
|
]]
|
||||||
self.supports_cli = False
|
self.supports_cli = False
|
||||||
|
|
|
@ -52,8 +52,7 @@ class MempoolPackageLimitsTest(BitcoinTestFramework):
|
||||||
self.test_anc_count_limits_2()
|
self.test_anc_count_limits_2()
|
||||||
self.test_anc_count_limits_bushy()
|
self.test_anc_count_limits_bushy()
|
||||||
|
|
||||||
# The node will accept (nonstandard) extra large OP_RETURN outputs
|
self.restart_node(0)
|
||||||
self.restart_node(0, extra_args=["-datacarriersize=100000"])
|
|
||||||
self.test_anc_size_limits()
|
self.test_anc_size_limits()
|
||||||
self.test_desc_size_limits()
|
self.test_desc_size_limits()
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,6 @@ class PackageRBFTest(BitcoinTestFramework):
|
||||||
self.setup_clean_chain = True
|
self.setup_clean_chain = True
|
||||||
# Required for fill_mempool()
|
# Required for fill_mempool()
|
||||||
self.extra_args = [[
|
self.extra_args = [[
|
||||||
"-datacarriersize=100000",
|
|
||||||
"-maxmempool=5",
|
"-maxmempool=5",
|
||||||
]] * self.num_nodes
|
]] * self.num_nodes
|
||||||
|
|
||||||
|
|
|
@ -44,8 +44,6 @@ MAX_PUBKEYS_PER_MULTISIG = 20
|
||||||
class BytesPerSigOpTest(BitcoinTestFramework):
|
class BytesPerSigOpTest(BitcoinTestFramework):
|
||||||
def set_test_params(self):
|
def set_test_params(self):
|
||||||
self.num_nodes = 1
|
self.num_nodes = 1
|
||||||
# allow large datacarrier output to pad transactions
|
|
||||||
self.extra_args = [['-datacarriersize=100000']]
|
|
||||||
|
|
||||||
def create_p2wsh_spending_tx(self, witness_script, output_script):
|
def create_p2wsh_spending_tx(self, witness_script, output_script):
|
||||||
"""Create a 1-input-1-output P2WSH spending transaction with only the
|
"""Create a 1-input-1-output P2WSH spending transaction with only the
|
||||||
|
@ -139,7 +137,7 @@ class BytesPerSigOpTest(BitcoinTestFramework):
|
||||||
self.log.info("Test a overly-large sigops-vbyte hits package limits")
|
self.log.info("Test a overly-large sigops-vbyte hits package limits")
|
||||||
# Make a 2-transaction package which fails vbyte checks even though
|
# Make a 2-transaction package which fails vbyte checks even though
|
||||||
# separately they would work.
|
# separately they would work.
|
||||||
self.restart_node(0, extra_args=["-bytespersigop=5000","-permitbaremultisig=1"] + self.extra_args[0])
|
self.restart_node(0, extra_args=["-bytespersigop=5000","-permitbaremultisig=1"])
|
||||||
|
|
||||||
def create_bare_multisig_tx(utxo_to_spend=None):
|
def create_bare_multisig_tx(utxo_to_spend=None):
|
||||||
_, pubkey = generate_keypair()
|
_, pubkey = generate_keypair()
|
||||||
|
@ -185,7 +183,7 @@ class BytesPerSigOpTest(BitcoinTestFramework):
|
||||||
else:
|
else:
|
||||||
bytespersigop_parameter = f"-bytespersigop={bytes_per_sigop}"
|
bytespersigop_parameter = f"-bytespersigop={bytes_per_sigop}"
|
||||||
self.log.info(f"Test sigops limit setting {bytespersigop_parameter}...")
|
self.log.info(f"Test sigops limit setting {bytespersigop_parameter}...")
|
||||||
self.restart_node(0, extra_args=[bytespersigop_parameter] + self.extra_args[0])
|
self.restart_node(0, extra_args=[bytespersigop_parameter])
|
||||||
|
|
||||||
for num_sigops in (69, 101, 142, 183, 222):
|
for num_sigops in (69, 101, 142, 183, 222):
|
||||||
self.test_sigops_limit(bytes_per_sigop, num_sigops)
|
self.test_sigops_limit(bytes_per_sigop, num_sigops)
|
||||||
|
|
|
@ -49,7 +49,7 @@ class MempoolTRUC(BitcoinTestFramework):
|
||||||
assert_equal(len(txids), len(mempool_contents))
|
assert_equal(len(txids), len(mempool_contents))
|
||||||
assert all([txid in txids for txid in mempool_contents])
|
assert all([txid in txids for txid in mempool_contents])
|
||||||
|
|
||||||
@cleanup(extra_args=["-datacarriersize=20000"])
|
@cleanup()
|
||||||
def test_truc_max_vsize(self):
|
def test_truc_max_vsize(self):
|
||||||
node = self.nodes[0]
|
node = self.nodes[0]
|
||||||
self.log.info("Test TRUC-specific maximum transaction vsize")
|
self.log.info("Test TRUC-specific maximum transaction vsize")
|
||||||
|
@ -63,7 +63,7 @@ class MempoolTRUC(BitcoinTestFramework):
|
||||||
tx_v2_heavy = self.wallet.send_self_transfer(from_node=node, target_vsize=TRUC_MAX_VSIZE + 1, version=2)
|
tx_v2_heavy = self.wallet.send_self_transfer(from_node=node, target_vsize=TRUC_MAX_VSIZE + 1, version=2)
|
||||||
self.check_mempool([tx_v2_heavy["txid"]])
|
self.check_mempool([tx_v2_heavy["txid"]])
|
||||||
|
|
||||||
@cleanup(extra_args=["-datacarriersize=1000"])
|
@cleanup()
|
||||||
def test_truc_acceptance(self):
|
def test_truc_acceptance(self):
|
||||||
node = self.nodes[0]
|
node = self.nodes[0]
|
||||||
self.log.info("Test a child of a TRUC transaction cannot be more than 1000vB")
|
self.log.info("Test a child of a TRUC transaction cannot be more than 1000vB")
|
||||||
|
@ -160,7 +160,7 @@ class MempoolTRUC(BitcoinTestFramework):
|
||||||
self.check_mempool([tx_v3_bip125_rbf_v2["txid"], tx_v3_parent["txid"], tx_v3_child["txid"]])
|
self.check_mempool([tx_v3_bip125_rbf_v2["txid"], tx_v3_parent["txid"], tx_v3_child["txid"]])
|
||||||
|
|
||||||
|
|
||||||
@cleanup(extra_args=["-datacarriersize=40000"])
|
@cleanup()
|
||||||
def test_truc_reorg(self):
|
def test_truc_reorg(self):
|
||||||
node = self.nodes[0]
|
node = self.nodes[0]
|
||||||
self.log.info("Test that, during a reorg, TRUC rules are not enforced")
|
self.log.info("Test that, during a reorg, TRUC rules are not enforced")
|
||||||
|
@ -182,7 +182,7 @@ class MempoolTRUC(BitcoinTestFramework):
|
||||||
node.reconsiderblock(block[0])
|
node.reconsiderblock(block[0])
|
||||||
|
|
||||||
|
|
||||||
@cleanup(extra_args=["-limitdescendantsize=10", "-datacarriersize=40000"])
|
@cleanup(extra_args=["-limitdescendantsize=10"])
|
||||||
def test_nondefault_package_limits(self):
|
def test_nondefault_package_limits(self):
|
||||||
"""
|
"""
|
||||||
Max standard tx size + TRUC rules imply the ancestor/descendant rules (at their default
|
Max standard tx size + TRUC rules imply the ancestor/descendant rules (at their default
|
||||||
|
@ -215,7 +215,7 @@ class MempoolTRUC(BitcoinTestFramework):
|
||||||
self.generate(node, 1)
|
self.generate(node, 1)
|
||||||
|
|
||||||
self.log.info("Test that a decreased limitancestorsize also applies to v3 parent")
|
self.log.info("Test that a decreased limitancestorsize also applies to v3 parent")
|
||||||
self.restart_node(0, extra_args=["-limitancestorsize=10", "-datacarriersize=40000"])
|
self.restart_node(0, extra_args=["-limitancestorsize=10"])
|
||||||
tx_v3_parent_large2 = self.wallet.send_self_transfer(
|
tx_v3_parent_large2 = self.wallet.send_self_transfer(
|
||||||
from_node=node,
|
from_node=node,
|
||||||
target_vsize=parent_target_vsize,
|
target_vsize=parent_target_vsize,
|
||||||
|
@ -235,7 +235,7 @@ class MempoolTRUC(BitcoinTestFramework):
|
||||||
assert_raises_rpc_error(-26, "too-long-mempool-chain, exceeds ancestor size limit", node.sendrawtransaction, tx_v3_child_large2["hex"])
|
assert_raises_rpc_error(-26, "too-long-mempool-chain, exceeds ancestor size limit", node.sendrawtransaction, tx_v3_child_large2["hex"])
|
||||||
self.check_mempool([tx_v3_parent_large2["txid"]])
|
self.check_mempool([tx_v3_parent_large2["txid"]])
|
||||||
|
|
||||||
@cleanup(extra_args=["-datacarriersize=1000"])
|
@cleanup()
|
||||||
def test_truc_ancestors_package(self):
|
def test_truc_ancestors_package(self):
|
||||||
self.log.info("Test that TRUC ancestor limits are checked within the package")
|
self.log.info("Test that TRUC ancestor limits are checked within the package")
|
||||||
node = self.nodes[0]
|
node = self.nodes[0]
|
||||||
|
@ -384,7 +384,7 @@ class MempoolTRUC(BitcoinTestFramework):
|
||||||
assert_equal(result_package_cpfp["tx-results"][tx_sibling_3['wtxid']]['error'], expected_error_cpfp)
|
assert_equal(result_package_cpfp["tx-results"][tx_sibling_3['wtxid']]['error'], expected_error_cpfp)
|
||||||
|
|
||||||
|
|
||||||
@cleanup(extra_args=["-datacarriersize=1000"])
|
@cleanup()
|
||||||
def test_truc_package_inheritance(self):
|
def test_truc_package_inheritance(self):
|
||||||
self.log.info("Test that TRUC inheritance is checked within package")
|
self.log.info("Test that TRUC inheritance is checked within package")
|
||||||
node = self.nodes[0]
|
node = self.nodes[0]
|
||||||
|
|
|
@ -186,6 +186,9 @@ class MiningTest(BitcoinTestFramework):
|
||||||
assert tx_below_min_feerate['txid'] not in block_template_txids
|
assert tx_below_min_feerate['txid'] not in block_template_txids
|
||||||
assert tx_below_min_feerate['txid'] not in block_txids
|
assert tx_below_min_feerate['txid'] not in block_txids
|
||||||
|
|
||||||
|
# Restart node to clear mempool for the next test
|
||||||
|
self.restart_node(0)
|
||||||
|
|
||||||
def test_timewarp(self):
|
def test_timewarp(self):
|
||||||
self.log.info("Test timewarp attack mitigation (BIP94)")
|
self.log.info("Test timewarp attack mitigation (BIP94)")
|
||||||
node = self.nodes[0]
|
node = self.nodes[0]
|
||||||
|
@ -279,11 +282,9 @@ class MiningTest(BitcoinTestFramework):
|
||||||
def test_block_max_weight(self):
|
def test_block_max_weight(self):
|
||||||
self.log.info("Testing default and custom -blockmaxweight startup options.")
|
self.log.info("Testing default and custom -blockmaxweight startup options.")
|
||||||
|
|
||||||
# Restart the node to allow large transactions
|
|
||||||
LARGE_TXS_COUNT = 10
|
LARGE_TXS_COUNT = 10
|
||||||
LARGE_VSIZE = int(((MAX_BLOCK_WEIGHT - DEFAULT_BLOCK_RESERVED_WEIGHT) / WITNESS_SCALE_FACTOR) / LARGE_TXS_COUNT)
|
LARGE_VSIZE = int(((MAX_BLOCK_WEIGHT - DEFAULT_BLOCK_RESERVED_WEIGHT) / WITNESS_SCALE_FACTOR) / LARGE_TXS_COUNT)
|
||||||
HIGH_FEERATE = Decimal("0.0003")
|
HIGH_FEERATE = Decimal("0.0003")
|
||||||
self.restart_node(0, extra_args=[f"-datacarriersize={LARGE_VSIZE}"])
|
|
||||||
|
|
||||||
# Ensure the mempool is empty
|
# Ensure the mempool is empty
|
||||||
assert_equal(len(self.nodes[0].getrawmempool()), 0)
|
assert_equal(len(self.nodes[0].getrawmempool()), 0)
|
||||||
|
@ -311,7 +312,7 @@ class MiningTest(BitcoinTestFramework):
|
||||||
# Test block template creation with custom -blockmaxweight
|
# Test block template creation with custom -blockmaxweight
|
||||||
custom_block_weight = MAX_BLOCK_WEIGHT - 2000
|
custom_block_weight = MAX_BLOCK_WEIGHT - 2000
|
||||||
# Reducing the weight by 2000 units will prevent 1 large transaction from fitting into the block.
|
# Reducing the weight by 2000 units will prevent 1 large transaction from fitting into the block.
|
||||||
self.restart_node(0, extra_args=[f"-datacarriersize={LARGE_VSIZE}", f"-blockmaxweight={custom_block_weight}"])
|
self.restart_node(0, extra_args=[f"-blockmaxweight={custom_block_weight}"])
|
||||||
|
|
||||||
self.log.info("Testing the block template with custom -blockmaxweight to include 9 large and 2 normal transactions.")
|
self.log.info("Testing the block template with custom -blockmaxweight to include 9 large and 2 normal transactions.")
|
||||||
self.verify_block_template(
|
self.verify_block_template(
|
||||||
|
@ -321,7 +322,7 @@ class MiningTest(BitcoinTestFramework):
|
||||||
|
|
||||||
# Ensure the block weight does not exceed the maximum
|
# Ensure the block weight does not exceed the maximum
|
||||||
self.log.info(f"Testing that the block weight will never exceed {MAX_BLOCK_WEIGHT - DEFAULT_BLOCK_RESERVED_WEIGHT}.")
|
self.log.info(f"Testing that the block weight will never exceed {MAX_BLOCK_WEIGHT - DEFAULT_BLOCK_RESERVED_WEIGHT}.")
|
||||||
self.restart_node(0, extra_args=[f"-datacarriersize={LARGE_VSIZE}", f"-blockmaxweight={MAX_BLOCK_WEIGHT}"])
|
self.restart_node(0, extra_args=[f"-blockmaxweight={MAX_BLOCK_WEIGHT}"])
|
||||||
self.log.info("Sending 2 additional normal transactions to fill the mempool to the maximum block weight.")
|
self.log.info("Sending 2 additional normal transactions to fill the mempool to the maximum block weight.")
|
||||||
self.send_transactions(utxos[LARGE_TXS_COUNT + 2:], NORMAL_FEERATE, NORMAL_VSIZE)
|
self.send_transactions(utxos[LARGE_TXS_COUNT + 2:], NORMAL_FEERATE, NORMAL_VSIZE)
|
||||||
self.log.info(f"Testing that the mempool's weight matches the maximum block weight: {MAX_BLOCK_WEIGHT}.")
|
self.log.info(f"Testing that the mempool's weight matches the maximum block weight: {MAX_BLOCK_WEIGHT}.")
|
||||||
|
@ -335,7 +336,7 @@ class MiningTest(BitcoinTestFramework):
|
||||||
|
|
||||||
self.log.info("Test -blockreservedweight startup option.")
|
self.log.info("Test -blockreservedweight startup option.")
|
||||||
# Lowering the -blockreservedweight by 4000 will allow for two more transactions.
|
# Lowering the -blockreservedweight by 4000 will allow for two more transactions.
|
||||||
self.restart_node(0, extra_args=[f"-datacarriersize={LARGE_VSIZE}", "-blockreservedweight=4000"])
|
self.restart_node(0, extra_args=["-blockreservedweight=4000"])
|
||||||
self.verify_block_template(
|
self.verify_block_template(
|
||||||
expected_tx_count=12,
|
expected_tx_count=12,
|
||||||
expected_weight=MAX_BLOCK_WEIGHT - 4000,
|
expected_weight=MAX_BLOCK_WEIGHT - 4000,
|
||||||
|
|
|
@ -27,7 +27,6 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
|
||||||
self.num_nodes = 1
|
self.num_nodes = 1
|
||||||
self.extra_args = [[
|
self.extra_args = [[
|
||||||
"-printpriority=1",
|
"-printpriority=1",
|
||||||
"-datacarriersize=100000",
|
|
||||||
]] * self.num_nodes
|
]] * self.num_nodes
|
||||||
self.supports_cli = False
|
self.supports_cli = False
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,6 @@ class PackageRelayTest(BitcoinTestFramework):
|
||||||
# hugely speeds up the test, as it involves multiple hops of tx relay.
|
# hugely speeds up the test, as it involves multiple hops of tx relay.
|
||||||
self.noban_tx_relay = True
|
self.noban_tx_relay = True
|
||||||
self.extra_args = [[
|
self.extra_args = [[
|
||||||
"-datacarriersize=100000",
|
|
||||||
"-maxmempool=5",
|
"-maxmempool=5",
|
||||||
]] * self.num_nodes
|
]] * self.num_nodes
|
||||||
self.supports_cli = False
|
self.supports_cli = False
|
||||||
|
|
|
@ -59,7 +59,6 @@ class PackageRelayTest(BitcoinTestFramework):
|
||||||
self.setup_clean_chain = True
|
self.setup_clean_chain = True
|
||||||
self.num_nodes = 1
|
self.num_nodes = 1
|
||||||
self.extra_args = [[
|
self.extra_args = [[
|
||||||
"-datacarriersize=100000",
|
|
||||||
"-maxmempool=5",
|
"-maxmempool=5",
|
||||||
]]
|
]]
|
||||||
self.supports_cli = False
|
self.supports_cli = False
|
||||||
|
|
|
@ -68,7 +68,7 @@ class ConnectionType(Enum):
|
||||||
class TxDownloadTest(BitcoinTestFramework):
|
class TxDownloadTest(BitcoinTestFramework):
|
||||||
def set_test_params(self):
|
def set_test_params(self):
|
||||||
self.num_nodes = 2
|
self.num_nodes = 2
|
||||||
self.extra_args= [['-datacarriersize=100000', '-maxmempool=5', '-persistmempool=0']] * self.num_nodes
|
self.extra_args= [['-maxmempool=5', '-persistmempool=0']] * self.num_nodes
|
||||||
|
|
||||||
def test_tx_requests(self):
|
def test_tx_requests(self):
|
||||||
self.log.info("Test that we request transactions from all our peers, eventually")
|
self.log.info("Test that we request transactions from all our peers, eventually")
|
||||||
|
|
|
@ -438,7 +438,6 @@ class RPCPackagesTest(BitcoinTestFramework):
|
||||||
# but child is too high fee
|
# but child is too high fee
|
||||||
# Lower mempool limit to make it easier to fill_mempool
|
# Lower mempool limit to make it easier to fill_mempool
|
||||||
self.restart_node(0, extra_args=[
|
self.restart_node(0, extra_args=[
|
||||||
"-datacarriersize=100000",
|
|
||||||
"-maxmempool=5",
|
"-maxmempool=5",
|
||||||
"-persistmempool=0",
|
"-persistmempool=0",
|
||||||
])
|
])
|
||||||
|
@ -467,7 +466,7 @@ class RPCPackagesTest(BitcoinTestFramework):
|
||||||
assert parent["txid"] not in node.getrawmempool()
|
assert parent["txid"] not in node.getrawmempool()
|
||||||
assert child["txid"] not in node.getrawmempool()
|
assert child["txid"] not in node.getrawmempool()
|
||||||
|
|
||||||
# Reset maxmempool, datacarriersize, reset dynamic mempool minimum feerate, and empty mempool.
|
# Reset maxmempool, reset dynamic mempool minimum feerate, and empty mempool.
|
||||||
self.restart_node(0)
|
self.restart_node(0)
|
||||||
self.wallet.rescan_utxos()
|
self.wallet.rescan_utxos()
|
||||||
|
|
||||||
|
|
|
@ -41,8 +41,8 @@ def fill_mempool(test_framework, node, *, tx_sync_fun=None):
|
||||||
"""Fill mempool until eviction.
|
"""Fill mempool until eviction.
|
||||||
|
|
||||||
Allows for simpler testing of scenarios with floating mempoolminfee > minrelay
|
Allows for simpler testing of scenarios with floating mempoolminfee > minrelay
|
||||||
Requires -datacarriersize=100000 and -maxmempool=5 and assumes -minrelaytxfee
|
Requires -maxmempool=5 and assumes -minrelaytxfee is 1 sat/vbyte.
|
||||||
is 1 sat/vbyte.
|
|
||||||
To avoid unintentional tx dependencies, the mempool filling txs are created with a
|
To avoid unintentional tx dependencies, the mempool filling txs are created with a
|
||||||
tagged ephemeral miniwallet instance.
|
tagged ephemeral miniwallet instance.
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -73,9 +73,6 @@ WITNESS_SCALE_FACTOR = 4
|
||||||
DEFAULT_ANCESTOR_LIMIT = 25 # default max number of in-mempool ancestors
|
DEFAULT_ANCESTOR_LIMIT = 25 # default max number of in-mempool ancestors
|
||||||
DEFAULT_DESCENDANT_LIMIT = 25 # default max number of in-mempool descendants
|
DEFAULT_DESCENDANT_LIMIT = 25 # default max number of in-mempool descendants
|
||||||
|
|
||||||
# Default setting for -datacarriersize. 80 bytes of data, +1 for OP_RETURN, +2 for the pushdata opcodes.
|
|
||||||
MAX_OP_RETURN_RELAY = 83
|
|
||||||
|
|
||||||
DEFAULT_MEMPOOL_EXPIRY_HOURS = 336 # hours
|
DEFAULT_MEMPOOL_EXPIRY_HOURS = 336 # hours
|
||||||
|
|
||||||
MAGIC_BYTES = {
|
MAGIC_BYTES = {
|
||||||
|
|
|
@ -338,7 +338,6 @@ BASE_SCRIPTS = [
|
||||||
'feature_unsupported_utxo_db.py',
|
'feature_unsupported_utxo_db.py',
|
||||||
'feature_logging.py',
|
'feature_logging.py',
|
||||||
'feature_anchors.py',
|
'feature_anchors.py',
|
||||||
'mempool_datacarrier.py',
|
|
||||||
'feature_coinstatsindex.py',
|
'feature_coinstatsindex.py',
|
||||||
'wallet_orphanedreward.py',
|
'wallet_orphanedreward.py',
|
||||||
'wallet_timelock.py',
|
'wallet_timelock.py',
|
||||||
|
|
Loading…
Add table
Reference in a new issue