Skip to content

Instantly share code, notes, and snippets.

@glozow
Last active July 26, 2021 14:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save glozow/7064717e727a3eb27fad4f8504513add to your computer and use it in GitHub Desktop.
Save glozow/7064717e727a3eb27fad4f8504513add to your computer and use it in GitHub Desktop.

Packages

Framework / Background

The purpose of the mempool is to store the best candidates for inclusion in a block, i.e., the ones with the highest fees (including fee-bumped ones). Non-mining nodes use the mempool to make block validation faster and to aid transaction relay. If transaction relay and mempool logic are working well, all transactions paying reasonable fees should make it to miners, and all nodes with (even small) mempools should have the transactions that will be in the next blocks.

Currently, we limit the size of our mempool (default 300MB) and only validate transactions one at a time - this creates a limitation in a node's ability to determine which transactions have the highest fees, because a low fee transaction can have a high fee child. (Essentially, CPFP only makes a difference for transactions that make it into a miner's mempool). Increasing the default size is not an option.

"Package Relay" End Goal: we can use package validation to accept a group of transactions that might not all meet our minimum fee requirements with individual base fees, but are attractive as a package. When receiving/sending transactions on the P2P network, we are able to decide and communicate when package validation (rather than individual transaction validation) should be used.

Of course, we want to achieve this without creating new DoS and pinning attack vectors.

Previous work on Package Relay:

Open Questions

Q: What is the minimum package type that is sufficient for your use cases?

Examples:

  • Simply 1 parent + 1 child
  • Two generations only, with 1 or more sponsored parents + 1 sponsoring child
  • Two generations only, with 1 or more sponsored parents + 1 or more children
  • More than 2 generations, with the bottom transaction serving as the sole sponsor
  • Any group of transactions, with a maximum number of X transactions

Q: Similarly, what other simplifications can we make?

  • In #20833, we decided to disable BIP125 for now. Is this okay?
  • Can we assume a certain level of connectivity within packages? Will you ever need independent packages?

Q: Should we do witness replacements? (i.e. #19645)

TODOs

There has been a lot of focus on the P2P side of package relay but we are quite far from it. Here is a sequence of work that needs to be done (imo) before it's safe to expose package validation on the P2P network:

(1) Package Validation and Package-specific policies

These PRs implement local package mempool acceptance. Any feedback on approach or implementation is very welcome:

  • #20833 was merged recently, it adds a chunk of package validation code. It's also the base PR for a separate project for test-accepting L2 transaction chains (see #21413 which is a RFC).
  • #21800 is open, it implements mempool ancestor/descendant checking for packages
  • #22290 is my first draft of package mempool submission, still WIP but I would like to be transparent about my work
  • #22252 is a package policy that I think is relevant

(2) Deciding when to use package validation + Communicating with peers about when they should

Since package validation and individual transaction validation may have different policies (e.g. no RBF in packages) and one might be more appropriate than the other, it does not make sense to always use package validation. If your node supports package validation, you can decide when to use it, whether or not your peers tell you to. You could start using package validation when you feel like it (e.g. orphan + parent rejected for low feerate heuristic like in #16401 commit). I think this would be called receiver-side package relay, and perhaps doesn't require P2P messages.

If we decide to make P2P changes... Personally, I don't actually think we need to send tx data in packages; nodes can still send transactions via regular tx relay (+ Erlay when we have that). Once nodes have a package validation module, I think the only P2P communication that needs to happen in addition to transaction relay is a hint saying "psst, you should use package validation on these transactions." Also, some kind of sendpackages message to say "I can validate packages" and "please only send me these types of packages".

(3) Stuff for client software

This will probably just require an RPC and maybe a BroadcastPackage() similar to BroadcastTransaction() in our interface code. I don't think lay users should have to think about packages beyond telling their wallet to fee-bump their transactions and still having their maxfeerate configurations respected when doing so.

@t-bast
Copy link

t-bast commented Jun 22, 2021

I had an afterthought from the IRC meeting about package RBF. We said we'd likely go with 1 parent + 1 child packages and allow a package to replace another (ie we could submit [A', B'] to replace [A, B]).

@harding mentioned reusing BIP 125 logic, however I believe rule 5 ("the number of original transactions to be replaced and their descendant transactions which will be evicted from the mempool must not exceed a total of 100 transactions.") would be a real problem: an attacker could easily pin a package [A, B] in some mempools by adding 98 child transactions to B (and having B pay a low enough fee to ensure A and B won't confirm quickly). If that makes it irreplaceable by [A', B'], it would be a problem for lightning (and potentially other L2 protocols?), it means we're unable to relay our package regardless of how much fees we're ready to pay.

The CPFP carve-out rule had to be hacked in to work around this issue for single transactions (such as lightning commitment txs), but I don't think it can save us here in the general case.

WDYT?

@harding
Copy link

harding commented Jun 22, 2021

@t-bast I'm not sure that specific attack works because Bitcoin Core's current mempool limits won't let A have more than 26 children. But other existing pinning attacks would still work (like making B 100,000 vbytes so [A',B'] is would cost too much).

@t-bast
Copy link

t-bast commented Jun 23, 2021

Thanks for the clarification. My take-away is that package-RBF will be quite a thorny problem if we want it to solve pinning attack vectors!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment