New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix virtual size limit enforcement in transaction package context #28471
Conversation
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. ReviewsSee the guideline for information on the review process.
If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update. ConflictsNo conflicts as of last run. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Concept ACK, thanks for taking this over!
Can you add tests for the bug fixes? |
e4640da
to
7193055
Compare
Added. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM except worried about rounding and error strings. Also a few nits on the test.
7193055
to
0ad8369
Compare
0ad8369
to
3a4adfb
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK 3a4adfb with a doc nit
3a4adfb
to
09b64e5
Compare
doc/policy/packages.md
Outdated
@@ -18,7 +18,7 @@ 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_KWU=404` total weight | |||
(#20833) | |||
|
|||
- *Rationale*: This is already enforced as mempool ancestor/descendant limits. If |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah hold on, avoiding rounding is good but it does mean that this limit is effectively a few Wu smaller than the default ancestor size limit. (#22097 (comment) and #22097 (comment)) so this statement is untrue.
I think having this limit denominated in Wu is good and it should be distinct from the ancestor package limits anyway. But I agree with those comments that maybe it's best to not make this limit more restrictive than normal ancestor limits.
We can bake in the rounding so this limit is 404000Wu + MAX_PACKAGE_COUNT * (WITNESS_SCALE_FACTOR -1) = 404075Wu.
Also I think the primary Rationale (if you could edit this bullet point please) should be "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."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed up as suggested, and fixed some inverted static asserts.
I thought about calling it 405KWU and calling it a day, but I think that would make code history more difficult, so instead stayed precisely as calculated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops, those comments are incorrect. The rounding does mean that this weight limit across multiple transactions is different from the ancestor size limits, but it makes the package limits less restrictive, not more restrictive. That's totally fine. No change needed, we can just keep 404,000Wu.
b6679c0
to
97d53ff
Compare
Concept ACK on replacing |
rebased on latest master with all suggestions included (will discuss @ariard note) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK 5c48501
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review ACK 5c48501
Test coverage sounds it can be better.
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; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Playing with the boundary values 403’999
or 404’001
doesn’t break package_sanitization_tests
as one could expect.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should break if you make it significantly larger, I think, since it's making txns that aren't 1 WU. leaving as is for now
// Package itself is busting mempool limits; should be rejected even if no staged_ancestors exist | ||
if (pack_size > static_cast<uint64_t>(m_limits.ancestor_count)) { | ||
errString = strprintf("package count %u exceeds ancestor count limit [limit: %u]", pack_size, m_limits.ancestor_count); | ||
return false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Following diff doesn’t sound to break functional test mempool_sigoplimit.py
.
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index 324292c055..21571b9e8a 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -205,7 +205,7 @@ bool CTxMemPool::CheckPackageLimits(const Package& package,
// Package itself is busting mempool limits; should be rejected even if no staged_ancestors exist
if (pack_size > static_cast<uint64_t>(m_limits.ancestor_count)) {
errString = strprintf("package count %u exceeds ancestor count limit [limit: %u]", pack_size, m_limits.ancestor_count);
- return false;
+ return true;
} else if (pack_size > static_cast<uint64_t>(m_limits.descendant_count)) {
errString = strprintf("package count %u exceeds descendant count limit [limit: %u]", pack_size, m_limits.descendant_count);
return false;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
going to reserve for follow-up test writing
return false; | ||
} else if (pack_size > static_cast<uint64_t>(m_limits.descendant_count)) { | ||
errString = strprintf("package count %u exceeds descendant count limit [limit: %u]", pack_size, m_limits.descendant_count); | ||
return false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index 324292c055..a9d8355aa3 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -208,7 +208,7 @@ bool CTxMemPool::CheckPackageLimits(const Package& package,
return false;
} else if (pack_size > static_cast<uint64_t>(m_limits.descendant_count)) {
errString = strprintf("package count %u exceeds descendant count limit [limit: %u]", pack_size, m_limits.descendant_count);
- return false;
+ return true;
} else if (total_vsize > m_limits.ancestor_size_vbytes) {
errString = strprintf("package size %u exceeds ancestor size limit [limit: %u]", total_vsize, m_limits.ancestor_size_vbytes);
return false;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
going to reserve for follow-up test writing
return false; | ||
} else if (total_vsize > m_limits.descendant_size_vbytes) { | ||
errString = strprintf("package size %u exceeds descendant size limit [limit: %u]", total_vsize, m_limits.descendant_size_vbytes); | ||
return false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index 324292c055..20456e250c 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -214,7 +214,7 @@ bool CTxMemPool::CheckPackageLimits(const Package& package,
return false;
} else if (total_vsize > m_limits.descendant_size_vbytes) {
errString = strprintf("package size %u exceeds descendant size limit [limit: %u]", total_vsize, m_limits.descendant_size_vbytes);
- return false;
+ return true;
}
(Mutating the third check on ancestor size vbytes break the functional test)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
going to reserve for follow-up test writing
5c48501
to
ee31e72
Compare
ee31e72
to
eb8f58f
Compare
seems to be a spurious failure |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Re-Code ACK eb8f58f
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reACK eb8f58f
@@ -133,6 +136,45 @@ def test_sigops_limit(self, bytes_per_sigop, num_sigops): | |||
assert_equal(entry_parent['descendantcount'], 2) | |||
assert_equal(entry_parent['descendantsize'], parent_tx.get_vsize() + sigop_equivalent_vsize) | |||
|
|||
def test_sigops_package(self): | |||
self.log.info("Test a overly-large sigops-vbyte hits package limits") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit eb8f58f
self.log.info("Test a overly-large sigops-vbyte hits package limits") | |
self.log.info("Test a package whose sigop-adjusted vsize hits ancestor size limits") |
return (tx_utxo, tx) | ||
|
||
tx_parent_utxo, tx_parent = create_bare_multisig_tx() | ||
tx_child_utxo, tx_child = create_bare_multisig_tx(tx_parent_utxo) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit eb8f58f: unused
tx_child_utxo, tx_child = create_bare_multisig_tx(tx_parent_utxo) | |
_, tx_child = create_bare_multisig_tx(tx_parent_utxo) |
ACK eb8f58f |
post-merge light ACK eb8f58f. Still need to catchup with the past 2 years of package relay but this makes sense to me. |
This just seems to make the bug harder to fix? How does it account for sigops? |
This PR changed the first context-less size check use weight units to make it clear it doesn't check sigops at this stage. As you know (since it's your commit), virtual size adjusted for sigops is later accounted for in Lines 1302 to 1305 in b66f6dc
What bug are you talking about which is made harder to fix? |
…n package context eb8f58f Add functional test to catch too large vsize packages (Greg Sanders) 1a579f9 Handle over-sized (in virtual bytes) packages with no in-mempool ancestors (Greg Sanders) bc013fe Bugfix: Pass correct virtual size to CheckPackageLimits (Luke Dashjr) 533660c Replace MAX_PACKAGE_SIZE with MAX_PACKAGE_WEIGHT to avoid vbyte confusion (Greg Sanders) Pull request description: (Alternative) Minimal subset of bitcoin#28345 to: 1) Replace MAX_PACKAGE_SIZE with MAX_PACKAGE_WEIGHT which accounts for additional WU necessary to not exclude default chain limit transactions that would have been accepted individually. Avoids sigops vbyte confusion. 2) pass correct vsize to chain limit evaluations in package context 3) stop overly-large packages that have no existing mempool ancestors (also a bugfix by itself if someone sets non-standard chain limits) This should fix the known issues while not blocking additional refactoring later. ACKs for top commit: achow101: ACK eb8f58f ariard: Re-Code ACK eb8f58f glozow: reACK eb8f58f Tree-SHA512: 1b5cca1a526207e25d387fcc29a776a3198c3a013dc2b35c6275b9d5a64db2476c154ebf52e3a1aed0b9924c75613f21a946577aa760de28cadf0c9c7f68dc39
…n package context eb8f58f Add functional test to catch too large vsize packages (Greg Sanders) 1a579f9 Handle over-sized (in virtual bytes) packages with no in-mempool ancestors (Greg Sanders) bc013fe Bugfix: Pass correct virtual size to CheckPackageLimits (Luke Dashjr) 533660c Replace MAX_PACKAGE_SIZE with MAX_PACKAGE_WEIGHT to avoid vbyte confusion (Greg Sanders) Pull request description: (Alternative) Minimal subset of bitcoin#28345 to: 1) Replace MAX_PACKAGE_SIZE with MAX_PACKAGE_WEIGHT which accounts for additional WU necessary to not exclude default chain limit transactions that would have been accepted individually. Avoids sigops vbyte confusion. 2) pass correct vsize to chain limit evaluations in package context 3) stop overly-large packages that have no existing mempool ancestors (also a bugfix by itself if someone sets non-standard chain limits) This should fix the known issues while not blocking additional refactoring later. ACKs for top commit: achow101: ACK eb8f58f ariard: Re-Code ACK eb8f58f glozow: reACK eb8f58f Tree-SHA512: 1b5cca1a526207e25d387fcc29a776a3198c3a013dc2b35c6275b9d5a64db2476c154ebf52e3a1aed0b9924c75613f21a946577aa760de28cadf0c9c7f68dc39
…sion 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. Github-Pull: bitcoin#28471 Rebased-From: 533660c
Github-Pull: bitcoin#28471 Rebased-From: bc013fe
…stors Github-Pull: bitcoin#28471 Rebased-From: 1a579f9
Github-Pull: bitcoin#28471 Rebased-From: eb8f58f
(Alternative) Minimal subset of #28345 to:
This should fix the known issues while not blocking additional refactoring later.