-
Notifications
You must be signed in to change notification settings - Fork 2.5k
mempool+rpc: add SubmitPackage RPC call, implement Rule 6 of BIP 431 along w/ pacakge-level RBF #2454
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
Draft
Roasbeef
wants to merge
6
commits into
btcsuite:truc-v2-impl
Choose a base branch
from
Roasbeef:truc-v2-submit-package
base: truc-v2-impl
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
In this commit, we add the foundational types and validation logic needed to support package relay via the submitpackage RPC. Package relay enables submitting multiple related transactions together, which is essential for BIP 431 TRUC transactions where zero-fee parents can be combined with fee-paying children. The PackageAcceptResult and TxAcceptResult types provide detailed per-transaction feedback including acceptance status, fees, virtual sizes, and rejection reasons. This granular reporting allows clients to understand exactly which transactions in a package were accepted or rejected and why. The ValidatePackageTopology function enforces the requirements for package relay: topological sorting (parents before children), count limits (maximum 25 transactions matching Bitcoin Core), and weight limits (404000 weight units). The topology validation catches circular dependencies and ensures packages can be processed without deadlocks.
…ackages In this commit, we implement BIP 431 Rule 6 which allows individual TRUC (v3) transactions to be below the minimum relay fee when they are part of a valid package that meets the mempool's feerate requirements. The implementation adds a PackageContext type that tracks whether a transaction is being validated as part of a TRUC package along with the aggregate package feerate. The BuildPackageContext method leverages the existing txgraph infrastructure (BuildPackageNodes, CreatePackage with dry-run mode, and AnalyzePackageType) to properly classify packages and calculate aggregate metrics without duplicating logic. The PolicyEnforcer interface is extended with BuildPackageContext and the PolicyGraph interface gains BuildPackageNodes and CreatePackage methods to expose the necessary txgraph operations. The StandardPolicyEnforcer.ValidateRelayFee method now checks the package context before enforcing minimum relay fees, allowing zero-fee TRUC transactions to skip the individual fee check when the package as a whole meets requirements. The packageContext parameter is threaded through the entire validation chain from checkMempoolAcceptance through maybeAcceptTransactionLocked to ValidateRelayFee, enabling the policy enforcer to make informed decisions about fee exemptions.
…age relay In this commit, we implement the core package submission methods that enable the submitpackage RPC functionality. ProcessPackage accepts a package of transactions and processes them progressively with proper deduplication, while CheckPackageAcceptance provides dry-run validation without modifying mempool state. The ProcessPackage method implements Bitcoin Core's progressive acceptance model where transactions are validated and accepted one-by-one. Transactions already in the mempool are automatically deduplicated (skipped), allowing clients to resubmit packages without errors. The implementation properly tracks package-level metrics including total fees, total virtual size, and aggregate feerate for validation purposes. Package RBF (Replace-By-Fee) is fully supported through pre-calculation of package fees, validation via ValidatePackageReplacement, and atomic removal of all conflicting transactions before accepting the new package. The package context is built to include fees from both new transactions and deduplicated mempool transactions, ensuring accurate feerate calculations for replacement validation. When conflicts are detected, the entire conflict set is removed atomically before any new transactions are added, preventing partial state and ensuring all-or-nothing package replacement semantics. The package context is passed through to each transaction's validation via maybeAcceptTransactionLocked, enabling BIP 431 Rule 6 support where zero-fee TRUC transactions are allowed as part of valid packages. After successful acceptance, orphan transactions that may now have all parents available are processed, and the result includes comprehensive per-transaction details including acceptance status, fees, vsizes, and any errors encountered. CheckPackageAcceptance mirrors ProcessPackage but uses dry-run validation (checkMempoolAcceptance directly with read lock) to test package acceptance without modifying the mempool. This is useful for clients to validate packages before actual submission.
In this commit, we add the submitpackage RPC handler which enables clients to submit packages of raw transactions to the mempool.
In this commit, we add the rpcclient wrapper methods for the submitpackage RPC call, enabling programmatic package submission from Go code. This completes the client-side API surface for package relay functionality.
In this commit, we add integration tests that validate the complete submitpackage RPC functionality from end-to-end using the rpctest harness. These tests verify the critical functionality needed for BIP 431 TRUC transaction relay and package RBF. The test suite covers five essential scenarios. First, basic package submission with a valid 1-parent-1-child v3 package ensures the fundamental flow works. Second, topology validation is tested by submitting transactions in the wrong order (child before parent), verifying that improper packages are rejected with clear error messages. Third, we test BIP 431 Rule 6 support by submitting a package with a zero-fee v3 parent and high-fee v3 child. This verifies that the parent is accepted despite having zero fees because the package as a whole meets the mempool's feerate requirements. This is the critical use case for Lightning Network commitment transactions with anchor outputs. Fourth, we test package RBF where an existing package [A, B] is replaced by [A, B'] where A is deduplicated (already in mempool) and B' replaces the original child B. This tests deduplication logic combined with package-level RBF validation and verifies that the final mempool state contains A + B' with B removed. Fifth and most importantly, we test true package RBF where both transactions conflict. Using the rpctest harness's WithInputs functional option, we create A' that spends the same inputs as A, forcing a double-spend conflict. When package [A', B''] is submitted, our implementation correctly validates the package-level feerate against the existing package, atomically removes both A and B, and accepts both A' and B''. This demonstrates that full package-level RBF works correctly with proper conflict aggregation and atomic replacement. All tests include proper mempool cleanup to ensure isolated test execution, and they verify both the RPC result structure and the actual mempool state to catch bugs where transactions might be marked "accepted" but not actually added to the graph.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
In this PR, we continue our v2 mempool series with the addition of a new
SubmitPackageRPC call. As is, the submit package RPC call is piece-wise, in that it's possbile for some transactions to be accepted while others are rejected. I went a bit back and forth on this, w.r.t if it's better and more consistent for an end-user if we instead implement atomic package submission (all or nothing). For now, I settled on keeping it incremental, as this matchesbitcoind's behavior today. Perhaps we'll add a new flag to signal that the package should instead be all or nothing.Integration tests for basic cases of package-RBF have been added along-side unit tests. We also implement BIP 431 that enables a zero or low fee v3 transaction to be accepted into the mempool, as long as it's a part of the final package.
There're quite a few things I don't really like about the current implementation. One is the split of responsibilities between the new
txgraph, and thePolicyEnforcer, at times it feels like we're doing redundant work, and one of the two systems should gain more responsibility.One follow up is to extend
testmempoolacceptto be able to accept multiple transactions, basically calling the newCheckPackageAcceptancemethod that we've built out.After that, the next PRs in this series include: