Skip to content
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

Cluster size 2 package rbf #28984

Open
wants to merge 9 commits into
base: master
Choose a base branch
from

Conversation

instagibbs
Copy link
Member

@instagibbs instagibbs commented Dec 1, 2023

Allows any 2 transaction package with no in-mempool ancestors to do package RBF when directly conflicting with other mempool clusters of size two or less.

Proposed validation steps:

  1. If the transaction package is of size 1, legacy rbf rules apply.
  2. Otherwise the transaction package consists of a (parent, child) pair with no other in-mempool ancestors (or descendants, obviously), so it is also going to create a cluster of size 2. If larger, fail.
  3. The package rbf may not evict more than 100 transactions from the mempool(bip125 rule 5)
  4. The package is a single chunk
  5. Every directly conflicted mempool transaction is connected to at most 1 other in-mempool transaction (ie the cluster size of the conflict is at most 2).
  6. Diagram check: We ensure that the replacement is strictly superior, improving the mempool
  7. The total fee of the package, minus the total fee of what is being evicted, is at least the minrelayfee * size of the package (equivalent to bip125 rule 3 and 4)

Post-cluster mempool this will likely be expanded to general package rbf, but this is what we can safely support today.

@DrahtBot
Copy link
Contributor

DrahtBot commented Dec 1, 2023

The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

Code Coverage

For detailed information about the code coverage, see the test coverage report.

Reviews

See the guideline for information on the review process.

Type Reviewers
Concept ACK murchandamus, glozow
Stale ACK ismaelsadeeq

If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update.

Conflicts

Reviewers, this pull request conflicts with the following ones:

  • #27432 (contrib: add tool to convert compact-serialized UTXO set to SQLite database by theStack)
  • #26593 (tracing: Only prepare tracepoint arguments when actually tracing by 0xB10C)

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.

@glozow
Copy link
Member

glozow commented Dec 4, 2023

Added this to the tracking issue

@instagibbs instagibbs force-pushed the 2023-12-cluster-size2-package-rbf branch 3 times, most recently from 57e5fc7 to 56848f9 Compare December 4, 2023 18:54
@instagibbs instagibbs marked this pull request as ready for review December 4, 2023 18:55
@instagibbs instagibbs force-pushed the 2023-12-cluster-size2-package-rbf branch from 56848f9 to be9d163 Compare December 4, 2023 19:14
const CFeeRate replacement_miner_score(replacement_fees, replacement_vsize);

for (const auto& entry : direct_conflicts) {
const bool conflict_is_v3{entry->GetSharedTx()->nVersion == 3};
Copy link
Member Author

@instagibbs instagibbs Dec 4, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this can't be hit yet; post-v3 it can. I can remove this, or leave a note, or both. It makes some package rbfs more useful

(edit: it's used in #29001 functional tests )

@DrahtBot DrahtBot removed the CI failed label Dec 4, 2023
src/test/rbf_tests.cpp Outdated Show resolved Hide resolved
@instagibbs instagibbs mentioned this pull request Dec 5, 2023
@instagibbs instagibbs force-pushed the 2023-12-cluster-size2-package-rbf branch 2 times, most recently from 7aee728 to 1d859b0 Compare December 8, 2023 15:27
@sdaftuar
Copy link
Member

sdaftuar commented Dec 8, 2023

So thinking conceptually about this, I'm most concerned by the new CheckMinerScores() criterion, where we only check the replacement package's feerate against the ancestor feerates of the indirect conflicts.

I think there are two issues with this approach:

  1. If you look at GetModFeesWithAncestors()/GetSizeWithAncestors(), that can be greater than the transaction's individual feerate (ie if the parent of a transaction has a higher feerate than the child you're conflicting with). So this can cause the test to be too conservative and introduce some kind of weird pinning. Granted, this is a new replacement functionality so maybe not the end of the world if it is sometimes too conservative, but it seems like a bug.

  2. Also if you look at the ancestor feerate of a transaction, that can underestimate its mining score, such as if some low feerate ancestor is being paid for by another transaction. So that can allow for replacements that are not incentive compatible (similar to how this is possible today with our current single-transaction RBF rules).

Even though the current RBF logic is broken already, I'd prefer to avoid adding on to that while rolling out the package RBF implementation, just so that users don't get used to some kinds of replacements working that really shouldn't be.

So I was wondering, can we deal with this by just restricting the topology of what we allow a package RBF to conflict with? Let's say we allow a replacement if the conflict set consists of either (1) a single transaction with no ancestors (and of course no descendants, since any descendants would be in the conflict set as well), or (2) two transactions that are in a parent-child topology, and that have no other in-mempool ancestors (or descendants, of course).

In those situations, the maximum miner score you would have to consider is either the individual feerate of the parent tx or the ancestor feerate of the child, so the new logic should work perfectly.

@instagibbs
Copy link
Member Author

After offline discussion with @sdaftuar , I've worked on a set of prospective changes and pushed them to this branch as follow-on commits.

Key change is that we will now only allow package RBF when the conflicted transactions are all in "clusters" of up to size 2. This allows us to calculate mining scores for each conflicted transaction, which means that post-cluster mempool, if we did this right, IIUC, the behavior should match with more general package RBF.

@instagibbs instagibbs force-pushed the 2023-12-cluster-size2-package-rbf branch 3 times, most recently from f9ce967 to 385b6ca Compare December 11, 2023 20:04
@instagibbs instagibbs force-pushed the 2023-12-cluster-size2-package-rbf branch from 722d1a5 to 7fd321d Compare May 13, 2024 16:14
@instagibbs instagibbs force-pushed the 2023-12-cluster-size2-package-rbf branch from 7fd321d to ce3a662 Compare May 15, 2024 12:13
@instagibbs
Copy link
Member Author

rebased due to conflict

@t-bast
Copy link
Contributor

t-bast commented May 15, 2024

While I wouldn't trust myself to correctly code-review this PR, I'd be happy to work on e2e tests that would leverage this for lightning channels fee-bumping (based on eclair) if it can help validate the logic and get this PR merged.

I'd like to highlight again how important this feature is for lightning (and probably for many other L2 protocols on top of bitcoin today). This is the critical step that allows us to mitigate pinning of a commitment transaction, and guarantee that we're able to set the fees of our commitment package to a value that should ensure timely confirmation.

@instagibbs
Copy link
Member Author

sorry forgot to link #30072 here, added to OP

@instagibbs instagibbs force-pushed the 2023-12-cluster-size2-package-rbf branch from ce3a662 to d412681 Compare May 20, 2024 14:35
@instagibbs
Copy link
Member Author

rebased on latest #30072

glozow added a commit that referenced this pull request May 24, 2024
2fd34ba Add sanity checks for various ATMPArgs booleans (Greg Sanders)
20d8936 [refactor] make some members MemPoolAccept-wide (glozow)
cbbfe71 cpfp carveout is excluded in packages (glozow)
69f7ab0 Add m_allow_sibling_eviction as separate ATMPArgs flag (Greg Sanders)
57ee302 Add description for m_test_accept (Greg Sanders)

Pull request description:

  First few commits of #28984 to set the stage for the package RBF logic.

  These refactors are preparation for evaluating an RBF in a multi-proposed-transaction context instead of only a single proposed transaction. Also, carveouts and sibling evictions only should work in single RBF cases so add logic to preclude multi-tx cases in the future.

  No behavior changes aside from bailing earlier from failed carve-outs.

ACKs for top commit:
  glozow:
    reACK 2fd34ba via range-diff
  sr-gi:
    utACK [2fd34ba](2fd34ba)
  theStack:
    re-ACK 2fd34ba

Tree-SHA512: 5071c5b8d9b8d2c9faa278c8c4df31de288cb407a68e4d55544c588caff6c86160cce7825453549c6ed69e29d9ccb5ee2d4a518b18f563bfb12f2ced073fe42a
@instagibbs instagibbs force-pushed the 2023-12-cluster-size2-package-rbf branch from d412681 to d05e350 Compare May 24, 2024 13:37
@instagibbs
Copy link
Member Author

rebased on master 🚀

@@ -91,7 +91,6 @@ std::optional<std::string> PackageV3Checks(const CTransactionRef& ptx, int64_t v
const auto parent_info = [&] {
if (mempool_ancestors.size() > 0) {
auto& mempool_parent = *mempool_ancestors.begin();
Assume(mempool_parent->GetCountWithDescendants() == 1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My comment is just about the commit message for this commit, not this line of code (sorry):

Relax assumptions aabout in-mempool children of in-mempool

"aabout" --> "about"

TxA (in mempool) <- TxB' (in package, conflicts with TxB) <-
TxD (in package)

s/TxD/TxC/ ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

direct_conflict_iters.merge(ws.m_iters_conflicting);
}

for (const auto& ws : workspaces) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems weird to loop through all the workspaces, when GetEntriesForConflicts is doing all the work that needs to be done on the first invocation? Maybe just invoke once with the child's txid, as is done further down?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

right this is just a logging arg; probably should clean that up to just take Wtxid in future work. re-arranged and passed in child workspace now

}

// If the package has in-mempool ancestors, we won't consider a package RBF
// since it would result in a cluster larger than 2
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you just add a comment here that references the comment on line 1520, as a reminder that we can't relax this without revisiting how we track available inputs when processing a package?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

made an attempt at a grepp-able cautionary note

doc/policy/packages.md Show resolved Hide resolved
instagibbs and others added 2 commits May 24, 2024 14:27
Relax assumptions about in-mempool children of in-mempool
parents. With package RBF, we will allow a package of size
2 with conflicts on its parent and reconsider the parent
if its fee is insufficient on its own.

Consider:

TxA (in mempool) <- TxB (in mempool)

TxA (in mempool) <- TxB' (in package, conflicts with TxB) <-
TxC (in package)

If TxB' fails to RBF TxB due to insufficient feerate, the
package TxB' + TxC will be considered. PackageV3Checks
called on TxB' will see an in-mempool parent TxA, and
see the in-mempool child TxB. We cannot assume there is
no in-mempool sibling, rather detect it and fail normally.

Prior to package RBF, this would have failed on the first
conflict in package.
Support package RBF where the conflicting package would result
in a mempool cluster of size two, and each of its direct
conflicts are also part of an up-to-size-2 mempool cluster.

This restricted topology allows for exact calculation
of miner scores for each side of the equation, reducing
the surface area for new pins, or incentive-incompatible
replacements.

This allows wallets to create simple CPFP packages
that can fee bump other simple CPFP packages. This,
leveraged with other restrictions such as V3 transactions,
can create pin-resistant applications.

Future package RBF relaxations can be considered when appropriate.

Co-authored-by: glozow <gloriajzhao@gmail.com>
Co-authored-by: Greg Sanders <gsanders87@gmail.com>
@instagibbs instagibbs force-pushed the 2023-12-cluster-size2-package-rbf branch from d05e350 to cddd60e Compare May 24, 2024 18:38
@instagibbs instagibbs force-pushed the 2023-12-cluster-size2-package-rbf branch from cddd60e to 7b74cbf Compare May 24, 2024 18:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Priority Project Primary Blocker
Development

Successfully merging this pull request may close these issues.

None yet

8 participants