-
Notifications
You must be signed in to change notification settings - Fork 37.8k
Package Mempool Submission with Package Fee-Bumping #22290
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
Conversation
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. ConflictsReviewers, this pull request conflicts with the following ones:
If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first. |
7ebf83a
to
1bc51d4
Compare
I have some concerns around what semantics are desired for bypassing the fee rate checks for a single transaction and using a notion of package fee rate instead. I think the logic here — of using the descendant fee rate as an alternate to the transaction’s fee rate — is insufficient for preventing free relay. Consider a 3 transaction package where one child transaction C has two parents, A and B, all of equal size. Suppose A and B are zero-fee transactions and C has a fee rate of 2. Then each of A and B would evaluate to having a fee rate of 1 (with C), but as a package the fee rate would be just 2/3. If the mempool min fee or min relay fee is 1, then this package would make it in despite being below the required fee rate. I think this type of issue may be somewhat difficult to avoid if we don’t tailor our semantics to the use case(s) we are trying to support. Right now, if I understand correctly, we don’t enforce any particular topology on the packages we accept — in fact I think the package acceptance logic would even accept unrelated transactions as well? One idea I had was to require the whole package’s fee rate to be above the min relay and mempool min fee as well, but that doesn’t work very well if we allow someone to bundle in an unrelated high fee transaction to “pay” for some low fee rate package. We could check that a package is connected (from a graph theory perspective) as a condition for acceptance, but that is also not quite sufficient for achieving the semantics that I think we want. For instance, if we are processing some package that has a sub graph of transactions which would not make it in on its own, we probably wouldn’t want to admit that whole graph? I’m not quite sure. It seems like if there is a detachable sub graph that would get evicted shortly after acceptance because it’s below the mempool min fee, that might still admit some kind of free relay problem, similar to the issue with unrelated transactions. My previous approach to the package relay problem was to define packages in a future p2p protocol extension as being the set of unconfirmed ancestors of a single target transaction. If that is sufficient for the use cases we are currently trying to support, then I think that simplifies the concerns a great deal — in this simple case I believe we could just look at two things: (a) check the target transaction’s own fee rate is sufficient to get in, and (b) check that the entire ancestor package for that target transaction also has a total fee rate sufficient to get in. (Of course we’d have to add a check that validates a package only contains ancestor transactions of the target, too.) The other benefit of using a target transaction’s ancestors as how we define a package is that it lines up better with how the mining algorithm currently works. If multiple children paying for multiple parents is some desired use case, I’m not sure the mempool and mining code are set up well enough to support that, so it would be helpful to analyze those use cases better to make sure our implementation will work okay. |
This seems reasonable. |
Thank you for the thoughtful review @sdaftuar!
Great point. I had been thinking of descendant feerate as a good marker since that's how we evict from mempool, but it is imperfect: I think we already have the case where a transaction's ancestor score is too low to be mined, but descendant score too high to be evicted. And it's additionally problematic with package relay. A proposal: if the mempool is intended to store the best candidates for mining, then we should evict in the opposite order we include in blocks, which is ancestor score. If we replaced descendant feerate with (Very far down the line, but just throwing a thought out there: considering feefilters with package relay, I think we would also want to use [unmodified] |
I think we should consider these two things separately: (1) whether to change the eviction algorithm used by the mempool, and (2) whether to change the fee rate heuristic used to evaluate transaction / package acceptance. Regarding the use of the miner score based on maximum-ancestor-feerate-of-descendants, I think that heuristic doesn't work very well for eviction. Imagine this scenario: the mempool has a very large, very low fee rate transaction A, with children B and C. C also is a child of another low feerate parent D. It is possible then that B has such a high feerate that A and B would be selected for the next block, and then that C and D would be selected as well (once A is paid for by B, C's ancestor feerate score would go up). However, if A is in fact very large, then C's own ancestor fee rate could be quite low, so that D's (As an aside I think the worst-case computation required to maintain this score would be worse than the status quo, too -- going from O(n) to O(n^2) to update statistics in the mempool when transactions are added/removed, where n = ancestor/descendant count.) However regarding the heuristic we use for admitting a package to the mempool, I think using this max-ancestor-feerate-of-descendants as an additional check that we compare to the min-relay-fee and mempool-min-fee probably does work. It might mean that packages which include a transaction that would be relying on some in-mempool-sibling to pay for a low fee parent might not make it in, but if that's not a use case we're worried about then probably this is fine (if conservative)? That seems to be a generalization of what I had proposed; I had suggested requiring a single ancestor-package that passes the fee rate check in total, while you're saying we can just require that every transaction in the package be part of some ancestor package that would pass the fee rate check. I'll give that more thought but it seems like a plausible solution. EDIT: One additional thought, assuming this idea works at all I think it ought to be sufficient to restrict the calculation of the score to the package transactions alone. That is, for each transaction, calculate its fee rate for mempool acceptance as |
Right, I agree with the separation between mempool eviction policy and evaluation of package transactions. Won't pursue the former much further here...
Edit: I'm going for 1 child + multiple parents instead, so package feerate is what I'll use.
Good point!!! |
1bc51d4
to
9d08189
Compare
9d08189
to
4fa69ab
Compare
4fa69ab
to
12876ac
Compare
This allows CPFP within a package prior to submission to mempool.
Update the existing unit test to have 0 fees in parent, 1BTC fees in child. This makes the parent too-low-fee by itself, but enough with its child.
No change in behavior. For single transaction acceptance, this is a simple refactor: Workspace::m_all_conflicting -> MemPoolAccept::m_all_conflicts Workspace::m_replacement_transaction -> MemPoolAccept::m_rbf Workspace::m_conflicting_fees -> MemPoolAccept::m_conflicting_fees Workspace::m_conflicting_size -> MemPoolAccept::m_conflicting_size Workspace::m_replaced_transactions -> MemPoolAccept::m_replaced_transactions For package acceptance, we don't enable RBF yet, but we want these to be package-wide variables because: - Transactions will never have the same conflict by prevout in the package, but they could have the same conflict by tx, and their conflicts could share descendants. - We want to compare conflicts with the package fee rather than individual transaction fee.
Created a new file because rpc_packages.py is for testing that the RPCs are returning the results we want. feature_package_relay is for testing the special policies and behaviors like CPFP and RBF.
Gated on an ATMPARgs value until later, so there are no behavior changes in this commit.
As node operators are free to set their mempool policies however they please, it's possible for package transaction(s) to already be in the mempool. We definitely don't want to reject the entire package in that case (as that could be a censorship vector). We still need to return the successful result to the caller, so add another result type to MempoolAcceptResult.
6591eb3
to
535f311
Compare
🐙 This pull request conflicts with the target branch and needs rebase. Want to unsubscribe from rebase notifications on this pull request? Just convert this pull request to a "draft". |
…ges of 1 child + parents 046e8ff [unit test] package submission (glozow) e12fafd [validation] de-duplicate package transactions already in mempool (glozow) 8310d94 [packages] add sanity checks for package vs mempool limits (glozow) be3ff15 [validation] full package accept + mempool submission (glozow) 144a290 [policy] require submitted packages to be child-with-unconfirmed-parents (glozow) d59ddc5 [packages/doc] define and document package rules (glozow) ba26169 [unit test] context-free package checks (glozow) 9b2fdca [packages] add static IsChildWithParents function (glozow) Pull request description: This is 1 chunk of [Package Mempool Accept](https://gist.github.com/glozow/dc4e9d5c5b14ade7cdfac40f43adb18a); it restricts packages to 1 child with its parents, doesn't allow conflicts, and doesn't have CPFP (yet). Future PRs (see #22290) will add RBF and CPFP within packages. ACKs for top commit: laanwj: Code review ACK 046e8ff Tree-SHA512: 37dbba37d527712f8efef71ee05c90a8308992615af35f5e0cfeafc60d859cc792737d125aac526e37742fe7683ac8c155ac24af562426213904333c01260c95
Next PR ready for review is #24152. |
Hi @sdaftuar, regarding your comment:
This is an interesting problem, after some thought I wrote a little demo to better understand these concepts, and I think it addresses some of these questions. I thought you and @glozow might find this helpful: |
9bebf35 [validation] don't package validate if not policy or missing inputs (glozow) 51edcff [unit test] package feerate and package cpfp (glozow) 1b93748 [validation] try individual validation before package validation (glozow) 17a8ffd [packages/policy] use package feerate in package validation (glozow) 09f32cf [docs] package feerate (glozow) Pull request description: Part of #22290, aka [Package Mempool Accept](https://gist.github.com/glozow/dc4e9d5c5b14ade7cdfac40f43adb18a). This enables CPFP fee bumping in child-with-unconfirmed-parents packages by introducing [package feerate](https://gist.github.com/glozow/dc4e9d5c5b14ade7cdfac40f43adb18a#fee-related-checks-use-package-feerate) (total modified fees divided by total virtual size) and using it in place of individual feerate. We also always [validate individual transactions first](https://gist.github.com/glozow/dc4e9d5c5b14ade7cdfac40f43adb18a#always-try-individual-submission-first) to avoid incentive-incompatible policies like "parents pay for children" or "siblings pay for siblings" behavior. ACKs for top commit: instagibbs: reACK 9bebf35 mzumsande: Code review ACK 9bebf35 t-bast: ACK 9bebf35 Tree-SHA512: 5117cfcc3ce55c00384d9e8003a0589ceac1e6f738b1c299007d9cd9cdd2d7c530d31cfd23658b041a6604d39073bcc6e81f0639a300082a92097682a6ea8c8f
There hasn't been much activity lately and the patch still needs rebase. What is the status here?
|
Actually that's a good point @DrahtBot - this PR was made to track progress on package relay / package mempool stuff but it's not great at it since there are now multiple branches, v3 is separated, and there are things in multiple repos. |
@glozow that link gives a 404 for me. Also the board you mention isn't listed in https://github.com/orgs/bitcoin/projects?query=is%3Aopen. Or is it only accessible to members? |
@flack apologies I didn't realize! It should be public now. |
This implements mempool validation logic for fee-bumping transactions using CPFP and RBFing mempool transactions within a package, and the combination of both (i.e. a child in a package can pay to RBF its parents' conflicts). This does not implement package relay; there are no P2P changes.
For more info, see full proposal gist.
Package Mempool Accept Progress:
Note that, until package relay exists, fee-bumped package transactions that are otherwise too-low-fee won't go any further than the user's mempool. This PR doesn't expose the package validation codepath to users because it would be misleading.