-
Notifications
You must be signed in to change notification settings - Fork 39.2k
Mempool: Do not enforce TRUC checks on reorg #33504
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1044,26 +1044,28 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) | |
| // Even though just checking direct mempool parents for inheritance would be sufficient, we | ||
| // check using the full ancestor set here because it's more convenient to use what we have | ||
| // already calculated. | ||
| if (const auto err{SingleTRUCChecks(ws.m_ptx, ws.m_ancestors, ws.m_conflicts, ws.m_vsize)}) { | ||
| // Single transaction contexts only. | ||
| if (args.m_allow_sibling_eviction && err->second != nullptr) { | ||
| // We should only be considering where replacement is considered valid as well. | ||
| Assume(args.m_allow_replacement); | ||
|
|
||
| // Potential sibling eviction. Add the sibling to our list of mempool conflicts to be | ||
| // included in RBF checks. | ||
| ws.m_conflicts.insert(err->second->GetHash()); | ||
| // Adding the sibling to m_iters_conflicting here means that it doesn't count towards | ||
| // RBF Carve Out above. This is correct, since removing to-be-replaced transactions from | ||
| // the descendant count is done separately in SingleTRUCChecks for TRUC transactions. | ||
| ws.m_iters_conflicting.insert(m_pool.GetIter(err->second->GetHash()).value()); | ||
| ws.m_sibling_eviction = true; | ||
| // The sibling will be treated as part of the to-be-replaced set in ReplacementChecks. | ||
| // Note that we are not checking whether it opts in to replaceability via BIP125 or TRUC | ||
| // (which is normally done in PreChecks). However, the only way a TRUC transaction can | ||
| // have a non-TRUC and non-BIP125 descendant is due to a reorg. | ||
| } else { | ||
| return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "TRUC-violation", err->first); | ||
| if (!args.m_bypass_limits) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. While If you'd prefer not to, I'd recommend a comment in the commit message explaining that PackageTRUCChecks are not gated here because reorgs do not ever go through |
||
| if (const auto err{SingleTRUCChecks(ws.m_ptx, ws.m_ancestors, ws.m_conflicts, ws.m_vsize)}) { | ||
| // Single transaction contexts only. | ||
| if (args.m_allow_sibling_eviction && err->second != nullptr) { | ||
| // We should only be considering where replacement is considered valid as well. | ||
| Assume(args.m_allow_replacement); | ||
|
|
||
| // Potential sibling eviction. Add the sibling to our list of mempool conflicts to be | ||
| // included in RBF checks. | ||
| ws.m_conflicts.insert(err->second->GetHash()); | ||
| // Adding the sibling to m_iters_conflicting here means that it doesn't count towards | ||
| // RBF Carve Out above. This is correct, since removing to-be-replaced transactions from | ||
| // the descendant count is done separately in SingleTRUCChecks for TRUC transactions. | ||
| ws.m_iters_conflicting.insert(m_pool.GetIter(err->second->GetHash()).value()); | ||
| ws.m_sibling_eviction = true; | ||
| // The sibling will be treated as part of the to-be-replaced set in ReplacementChecks. | ||
| // Note that we are not checking whether it opts in to replaceability via BIP125 or TRUC | ||
| // (which is normally done in PreChecks). However, the only way a TRUC transaction can | ||
| // have a non-TRUC and non-BIP125 descendant is due to a reorg. | ||
| } else { | ||
| return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "TRUC-violation", err->first); | ||
| } | ||
| } | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -165,23 +165,36 @@ def test_truc_replacement(self): | |
| def test_truc_reorg(self): | ||
| node = self.nodes[0] | ||
| self.log.info("Test that, during a reorg, TRUC rules are not enforced") | ||
| tx_v2_block = self.wallet.send_self_transfer(from_node=node, version=2) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggestion for a few more within-block test cases, if you're interested (can also just open a followup, have some other test ideas as well) |
||
| tx_v3_block = self.wallet.send_self_transfer(from_node=node, version=3) | ||
| tx_v3_block2 = self.wallet.send_self_transfer(from_node=node, version=3) | ||
| self.check_mempool([tx_v3_block["txid"], tx_v2_block["txid"], tx_v3_block2["txid"]]) | ||
| self.check_mempool([]) | ||
|
|
||
| # Testing 2<-3 versions allowed | ||
| tx_v2_block = self.wallet.create_self_transfer(version=2) | ||
|
|
||
| # Testing 3<-2 versions allowed | ||
| tx_v3_block = self.wallet.create_self_transfer(version=3) | ||
|
|
||
| # Testing overly-large child size | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In "test: add more TRUC reorg coverge" 06df14b What does "Testing overly-large child size" mean here? the tx being created has a normal size |
||
| tx_v3_block2 = self.wallet.create_self_transfer(version=3) | ||
|
|
||
| # Also create a linear chain of 3 TRUC transactions that will be directly mined, followed by one v2 in-mempool after block is made | ||
| tx_chain_1 = self.wallet.create_self_transfer(version=3) | ||
| tx_chain_2 = self.wallet.create_self_transfer(utxo_to_spend=tx_chain_1["new_utxo"], version=3) | ||
| tx_chain_3 = self.wallet.create_self_transfer(utxo_to_spend=tx_chain_2["new_utxo"], version=3) | ||
|
|
||
| tx_to_mine = [tx_v3_block["hex"], tx_v2_block["hex"], tx_v3_block2["hex"], tx_chain_1["hex"], tx_chain_2["hex"], tx_chain_3["hex"]] | ||
| block = self.generateblock(node, output="raw(42)", transactions=tx_to_mine) | ||
|
|
||
| block = self.generate(node, 1) | ||
| self.check_mempool([]) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In "test: add more TRUC reorg coverge" 06df14b This empty mempool check in between the block generation is redundant, because we have not send any transaction to the mempool. |
||
| tx_v2_from_v3 = self.wallet.send_self_transfer(from_node=node, utxo_to_spend=tx_v3_block["new_utxo"], version=2) | ||
| tx_v3_from_v2 = self.wallet.send_self_transfer(from_node=node, utxo_to_spend=tx_v2_block["new_utxo"], version=3) | ||
| tx_v3_child_large = self.wallet.send_self_transfer(from_node=node, utxo_to_spend=tx_v3_block2["new_utxo"], target_vsize=1250, version=3) | ||
| assert_greater_than(node.getmempoolentry(tx_v3_child_large["txid"])["vsize"], TRUC_CHILD_MAX_VSIZE) | ||
| self.check_mempool([tx_v2_from_v3["txid"], tx_v3_from_v2["txid"], tx_v3_child_large["txid"]]) | ||
| node.invalidateblock(block[0]) | ||
| self.check_mempool([tx_v3_block["txid"], tx_v2_block["txid"], tx_v3_block2["txid"], tx_v2_from_v3["txid"], tx_v3_from_v2["txid"], tx_v3_child_large["txid"]]) | ||
| # This is needed because generate() will create the exact same block again. | ||
| node.reconsiderblock(block[0]) | ||
| tx_chain_4 = self.wallet.send_self_transfer(from_node=node, utxo_to_spend=tx_chain_3["new_utxo"], version=2) | ||
| self.check_mempool([tx_v2_from_v3["txid"], tx_v3_from_v2["txid"], tx_v3_child_large["txid"], tx_chain_4["txid"]]) | ||
|
|
||
| # Reorg should have all block transactions re-accepted, ignoring TRUC enforcement | ||
| node.invalidateblock(block["hash"]) | ||
| self.check_mempool([tx_v3_block["txid"], tx_v2_block["txid"], tx_v3_block2["txid"], tx_v2_from_v3["txid"], tx_v3_from_v2["txid"], tx_v3_child_large["txid"], tx_chain_1["txid"], tx_chain_2["txid"], tx_chain_3["txid"], tx_chain_4["txid"]]) | ||
|
|
||
| @cleanup(extra_args=["-limitdescendantsize=10"]) | ||
| def test_nondefault_package_limits(self): | ||
|
|
||
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: documentation for
bypass_limitsin validation.h could mention that TRUC rules are not enforced and it's intended for reorgs