mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-02-02 09:46:52 -05:00
Replace MAX_PACKAGE_SIZE with MAX_PACKAGE_WEIGHT to avoid vbyte confusion
While allowing submitted packages to be slightly larger than what may be allowed in the mempool to allow simpler reasoning about contextual-less checks vs chain limits.
This commit is contained in:
parent
3966b0a0b6
commit
533660c58a
4 changed files with 29 additions and 22 deletions
|
@ -18,16 +18,19 @@ tip or some preceding transaction in the package.
|
|||
|
||||
The following rules are enforced for all packages:
|
||||
|
||||
* Packages cannot exceed `MAX_PACKAGE_COUNT=25` count and `MAX_PACKAGE_SIZE=101KvB` total size
|
||||
* Packages cannot exceed `MAX_PACKAGE_COUNT=25` count and `MAX_PACKAGE_WEIGHT=404000` total weight
|
||||
(#20833)
|
||||
|
||||
- *Rationale*: This is already enforced as mempool ancestor/descendant limits. If
|
||||
transactions in a package are all related, exceeding this limit would mean that the package
|
||||
can either be split up or it wouldn't pass individual mempool policy.
|
||||
- *Rationale*: We want package size to be as small as possible to mitigate DoS via package
|
||||
validation. However, we want to make sure that the limit does not restrict ancestor
|
||||
packages that would be allowed if submitted individually.
|
||||
|
||||
- Note that, if these mempool limits change, package limits should be reconsidered. Users may
|
||||
also configure their mempool limits differently.
|
||||
|
||||
- Note that the this is transaction weight, not "virtual" size as with other limits to allow
|
||||
simpler context-less checks.
|
||||
|
||||
* Packages must be topologically sorted. (#20833)
|
||||
|
||||
* Packages cannot have conflicting transactions, i.e. no two transactions in a package can spend
|
||||
|
|
|
@ -23,10 +23,10 @@ bool CheckPackage(const Package& txns, PackageValidationState& state)
|
|||
return state.Invalid(PackageValidationResult::PCKG_POLICY, "package-too-many-transactions");
|
||||
}
|
||||
|
||||
const int64_t total_size = std::accumulate(txns.cbegin(), txns.cend(), 0,
|
||||
[](int64_t sum, const auto& tx) { return sum + GetVirtualTransactionSize(*tx); });
|
||||
// If the package only contains 1 tx, it's better to report the policy violation on individual tx size.
|
||||
if (package_count > 1 && total_size > MAX_PACKAGE_SIZE * 1000) {
|
||||
const int64_t total_weight = std::accumulate(txns.cbegin(), txns.cend(), 0,
|
||||
[](int64_t sum, const auto& tx) { return sum + GetTransactionWeight(*tx); });
|
||||
// If the package only contains 1 tx, it's better to report the policy violation on individual tx weight.
|
||||
if (package_count > 1 && total_weight > MAX_PACKAGE_WEIGHT) {
|
||||
return state.Invalid(PackageValidationResult::PCKG_POLICY, "package-too-large");
|
||||
}
|
||||
|
||||
|
|
|
@ -15,18 +15,22 @@
|
|||
|
||||
/** Default maximum number of transactions in a package. */
|
||||
static constexpr uint32_t MAX_PACKAGE_COUNT{25};
|
||||
/** Default maximum total virtual size of transactions in a package in KvB. */
|
||||
static constexpr uint32_t MAX_PACKAGE_SIZE{101};
|
||||
static_assert(MAX_PACKAGE_SIZE * WITNESS_SCALE_FACTOR * 1000 >= MAX_STANDARD_TX_WEIGHT);
|
||||
/** Default maximum total weight of transactions in a package in weight
|
||||
to allow for context-less checks. This must allow a superset of sigops
|
||||
weighted vsize limited transactions to not disallow transactions we would
|
||||
have otherwise accepted individually. */
|
||||
static constexpr uint32_t MAX_PACKAGE_WEIGHT = 404'000;
|
||||
static_assert(MAX_PACKAGE_WEIGHT >= MAX_STANDARD_TX_WEIGHT);
|
||||
|
||||
// If a package is submitted, it must be within the mempool's ancestor/descendant limits. Since a
|
||||
// submitted package must be child-with-unconfirmed-parents (all of the transactions are an ancestor
|
||||
// If a package is to be evaluated, it must be at least as large as the mempool's ancestor/descendant limits,
|
||||
// otherwise transactions that would be individually accepted may be rejected in a package erroneously.
|
||||
// Since a submitted package must be child-with-unconfirmed-parents (all of the transactions are an ancestor
|
||||
// of the child), package limits are ultimately bounded by mempool package limits. Ensure that the
|
||||
// defaults reflect this constraint.
|
||||
static_assert(DEFAULT_DESCENDANT_LIMIT >= MAX_PACKAGE_COUNT);
|
||||
static_assert(DEFAULT_ANCESTOR_LIMIT >= MAX_PACKAGE_COUNT);
|
||||
static_assert(DEFAULT_ANCESTOR_SIZE_LIMIT_KVB >= MAX_PACKAGE_SIZE);
|
||||
static_assert(DEFAULT_DESCENDANT_SIZE_LIMIT_KVB >= MAX_PACKAGE_SIZE);
|
||||
static_assert(MAX_PACKAGE_WEIGHT >= DEFAULT_ANCESTOR_SIZE_LIMIT_KVB * WITNESS_SCALE_FACTOR * 1000);
|
||||
static_assert(MAX_PACKAGE_WEIGHT >= DEFAULT_DESCENDANT_SIZE_LIMIT_KVB * WITNESS_SCALE_FACTOR * 1000);
|
||||
|
||||
/** A "reason" why a package was invalid. It may be that one or more of the included
|
||||
* transactions is invalid or the package itself violates our rules.
|
||||
|
@ -47,7 +51,7 @@ class PackageValidationState : public ValidationState<PackageValidationResult> {
|
|||
|
||||
/** Context-free package policy checks:
|
||||
* 1. The number of transactions cannot exceed MAX_PACKAGE_COUNT.
|
||||
* 2. The total virtual size cannot exceed MAX_PACKAGE_SIZE.
|
||||
* 2. The total weight cannot exceed MAX_PACKAGE_WEIGHT.
|
||||
* 3. If any dependencies exist between transactions, parents must appear before children.
|
||||
* 4. Transactions cannot conflict, i.e., spend the same inputs.
|
||||
*/
|
||||
|
|
|
@ -51,14 +51,14 @@ BOOST_FIXTURE_TEST_CASE(package_sanitization_tests, TestChain100Setup)
|
|||
BOOST_CHECK_EQUAL(state_too_many.GetResult(), PackageValidationResult::PCKG_POLICY);
|
||||
BOOST_CHECK_EQUAL(state_too_many.GetRejectReason(), "package-too-many-transactions");
|
||||
|
||||
// Packages can't have a total size of more than 101KvB.
|
||||
// Packages can't have a total weight of more than 404'000WU.
|
||||
CTransactionRef large_ptx = create_placeholder_tx(150, 150);
|
||||
Package package_too_large;
|
||||
auto size_large = GetVirtualTransactionSize(*large_ptx);
|
||||
size_t total_size{0};
|
||||
while (total_size <= MAX_PACKAGE_SIZE * 1000) {
|
||||
auto size_large = GetTransactionWeight(*large_ptx);
|
||||
size_t total_weight{0};
|
||||
while (total_weight <= MAX_PACKAGE_WEIGHT) {
|
||||
package_too_large.push_back(large_ptx);
|
||||
total_size += size_large;
|
||||
total_weight += size_large;
|
||||
}
|
||||
BOOST_CHECK(package_too_large.size() <= MAX_PACKAGE_COUNT);
|
||||
PackageValidationState state_too_large;
|
||||
|
@ -122,7 +122,7 @@ BOOST_FIXTURE_TEST_CASE(package_validation_tests, TestChain100Setup)
|
|||
|
||||
// A single, giant transaction submitted through ProcessNewPackage fails on single tx policy.
|
||||
CTransactionRef giant_ptx = create_placeholder_tx(999, 999);
|
||||
BOOST_CHECK(GetVirtualTransactionSize(*giant_ptx) > MAX_PACKAGE_SIZE * 1000);
|
||||
BOOST_CHECK(GetVirtualTransactionSize(*giant_ptx) > DEFAULT_ANCESTOR_SIZE_LIMIT_KVB * 1000);
|
||||
auto result_single_large = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool, {giant_ptx}, /*test_accept=*/true);
|
||||
BOOST_CHECK(result_single_large.m_state.IsInvalid());
|
||||
BOOST_CHECK_EQUAL(result_single_large.m_state.GetResult(), PackageValidationResult::PCKG_TX);
|
||||
|
|
Loading…
Add table
Reference in a new issue