Page MenuHomePhabricator

Introduce a conflicting tx pool
ClosedPublic

Authored by Fabien on Aug 14 2024, 15:22.

Details

Reviewers
bytesofman
PiRK
Group Reviewers
Restricted Project
Commits
rABC2d31247bc76c: Introduce a conflicting tx pool
Summary

Store a limited quantity of conflicting transactions. This is
currently only used for an RPC but will later be used to vote on these
transactions via avalanche.

Test Plan
./test/functional/test_runner.py rpc_gettransactionstatus

Diff Detail

Repository
rABC Bitcoin ABC
Lint
Lint Not Applicable
Unit
Tests Not Applicable

Event Timeline

Fabien requested review of this revision.Aug 14 2024, 15:22
Fabien updated this revision to Diff 49215.

Fix a typo

bytesofman added a subscriber: bytesofman.
bytesofman added inline comments.
doc/release-notes.md
9 ↗(On Diff #49215)
src/net_processing.cpp
5800 ↗(On Diff #49215)

is this FIXME to be resolved in this diff?

src/txconflicting.h
12 ↗(On Diff #49215)

why 20min?

14 ↗(On Diff #49215)

why 5min?

test/functional/rpc_gettransactionpool.py
46 ↗(On Diff #49215)

in general -- the node will reject conflicting txs? this is some kind of regtest override so it is accepted?

does this diff change that node behavior? e.g. right now cashtab will not broadcast a tx if "inputs missing or spent", i.e. if a tx is constructed before cashtab has updated its utxo set, so it tries to spend something that it "just spent" ... even if this input is not confirmed -- so will this type of tx broadcast now?

This revision now requires changes to proceed.Aug 14 2024, 16:57
PiRK added inline comments.
test/functional/rpc_gettransactionpool.py
46 ↗(On Diff #49215)

The node still rejects the tx from the mempool, so as of this diff it is still technically rejected and cannot be mined by this node.

The send_txs_and_test method attempts to broadcast via the node, which may fail like it does here.

It is just kept in a new pool that currently is unused (except for the new RPC)

I'm assuming a future diff will make it possible for an avalanche vote to cause the conflicting tx to be transferred to the mempool. So it will not need to be requested again from peers if it turns out to be the final tx.

Fix the README and remove the confusing FIXME comment

src/net_processing.cpp
5800 ↗(On Diff #49215)

Leftover from the commit split, it is currently added in ProcessInvalidTx()

src/txconflicting.h
14 ↗(On Diff #49215)

There values are copied from the orphan pool and are here to try to free space in the very constrained size of the pool. Under normal circumstances there should be no conflicting tx (just like there should be no orphan) so the size shouldn't matter, but we don't want an attacker to fill the pool indefinitely and make the mechanism fail to work. So if the tx was not removed from the pool (currently only possible if it gets mined/a conflicting tx gets mined; later could be via avalanche) it will expire after a reasonable amount of time. The 20 minutes expiry (checked every 5 minutes) is 2 blocks on average, which is generous enough for a conflicting tx. The 5 minutes interval is there to help doing batch removal rather than removing txs one at a time.

test/functional/rpc_gettransactionpool.py
46 ↗(On Diff #49215)

Pierre has it 100% correct.

I think you are confusing orphans and conflicting txs. Orphans are txs for which the node doesn't have the inputs: this might be that a child transaction has been received before the parent. A conflict occurs when a tx is spending the same input as another one, aka a double spend. Under normal circumstances this should never happen, but if it does the network has to reconciliate which one of these conflicting txs is the legit one: the nodes currently apply a "first-seen rule" so the chosen one might differ between nodes depending on which tx they got first. The real "winner" of the conflict is only know when one of the tx is mined. This is the job of pre-consensus to make sure all the nodes select the same tx before it gets mined, and reject the others as well as blocks that would mine a tx that conflicts with the avalanche selected one.

Note I might change the RPC name if I can find a better one

This revision is now accepted and ready to land.Aug 15 2024, 16:15
tobias_ruck added inline comments.
src/rpc/rawtransaction.cpp
1770 ↗(On Diff #49226)

Maybe getwhichtransactionpool, when I first saw this name I thought it returned a pool of txs ( like all the mempool txs etc)

Another possible name would be gettransactionstatus; you already say this in the release notes: "retrieve the status of a non-mined transaction". It would (kinda) imply that the RPC should return "mined" for mined txs (which we can't do in the general case because the -txindex can be disabled). So either it looks that up (and returns "unknown" if the txindex is off), or the name could also be gettransactionstatusinmemory, which is I think the most precise, albeit a bit long.

Another possible name would be gettransactionstatus; you already say this in the release notes: "retrieve the status of a non-mined transaction". It would (kinda) imply that the RPC should return "mined" for mined txs (which we can't do in the general case because the -txindex can be disabled). So either it looks that up (and returns "unknown" if the txindex is off), or the name could also be gettransactionstatusinmemory, which is I think the most precise, albeit a bit long.

gettransactionstatus was my initial name which I changed just before submitting the diff because it doesn't really reflect the content. But you're the second person to suggest that name together with the mined status (which is really not going to be workable without the txindex as you noticed) so I will roll back. I can add the mined status in another diff.

Rename to gettransactionstatus

This revision was automatically updated to reflect the committed changes.