-
Notifications
You must be signed in to change notification settings - Fork 38.7k
Add package evaluation fuzzer #28450
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
Add package evaluation fuzzer #28450
Conversation
|
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. ReviewsSee the guideline for information on the review process.
If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update. 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. |
|
Awesome, Concept ACK. |
glozow
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
concept ACK, really nice 🚀
f06cf5b to
ad63201
Compare
dergoegge
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Concept ACK
brunoerg
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Concept ACK
3654ad4 to
28f45d6
Compare
|
rebased on master, removed arg round-trip, un-marked WIP |
|
Concept ACK, I guess this also picks up #25778 ? |
|
Any interest in using |
|
@MarcoFalke oh, had no idea it existed. Yes I think this should subsume it. I kept it a separate fuzz target to allow more specialization for what we're covering.
I might take a subset of that, but a few parts wouldn't be useful since I'm firing off random packages that may or may not be valid, and the mempool may trim things even if they're valid? edit: In other words, please consider this PR review-ready 👍 |
src/test/fuzz/package_eval.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
future work: making the tx >40kWu sometimes, along with other invariant checks, would have likely allowed the fuzzer to catch #28472
28f45d6 to
93d7c5c
Compare
2302596 to
bf7436c
Compare
glozow
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few quick questions, looks correct to me though some bits are a little confusing. I know future updates are planned so feel free to save for later if I'm scope creeping too much.
src/test/fuzz/package_eval.cpp
Outdated
| // Single-tx packages should be rejected, so do that sometimes, and sometimes send it via single submission | ||
| // to allow it into the mempool by itself to make more interesting mempool packages | ||
| auto single_submit = txs.size() == 1 && fuzzed_data_provider.ConsumeBool(); | ||
| auto package_submit = !single_submit; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was a bit confusing. Perhaps adding this comment beforehand would help clarify things
"When there are multiple transactions in the package, we call ProcessNewPackage(txs, test_accept=false) and AcceptToMemoryPool(txs.back(), test_accept=true). When there is only 1 transaction, we might flip it (the package is a test accept and ATMP is a submission)."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also... wondering why allow num_txs to be less than 2 anyway? Isn't this test kind of the same as what's in the tx_pool fuzzer?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also... wondering why allow num_txs to be less than 2 anyway?
- it can get rejected by ProcessNewPackage
- it can cause the existing mempool to be somewhat more interesting maybe
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh I was mistaken, AcceptPackage takes package sizes of 1(I was thinking of BIP331 probably!). This PR could have been a bit simpler I think by removing single accept path.
src/test/fuzz/package_eval.cpp
Outdated
| // Cache the in-package outpoints being made | ||
| for (size_t i = 0; i < tx->vout.size(); ++i) { | ||
| package_outpoints.emplace(tx->GetHash(), i); | ||
| outpoints_value[COutPoint(tx->GetHash(), i)] = tx->vout[i].nValue; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can also go under if (!last_tx), right? There's no need to add the last tx's outputs since we won't need them
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done, had to keep the outpoints_value check outside though since it needs all generated outpoints
| } | ||
| // TODO vary transaction sizes to catch size-related issues | ||
| auto tx = MakeTransactionRef(tx_mut); | ||
| // Restore previously removed outpoints, except in-package outpoints |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Question: this means transactions in the package can conflict with each other, right? It's possible to select the same outpoint from outpoints_rbf for 2 parents in the same package?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes
src/test/fuzz/package_eval.cpp
Outdated
| // Add created outpoints, remove spent outpoints | ||
| { | ||
| // Outpoints that no longer exist at all | ||
| std::set<COutPoint> consumed_erased; | ||
| // Outpoints that no longer count toward the total supply | ||
| std::set<COutPoint> consumed_supply; | ||
| for (const auto& removed_tx : removed) { | ||
| insert_tx(/*created_by_tx=*/{consumed_erased}, /*consumed_by_tx=*/{outpoints_supply}, /*tx=*/*removed_tx); | ||
| } | ||
| for (const auto& added_tx : added) { | ||
| insert_tx(/*created_by_tx=*/{outpoints_supply, outpoints_rbf}, /*consumed_by_tx=*/{consumed_supply}, /*tx=*/*added_tx); | ||
| } | ||
| for (const auto& p : consumed_erased) { | ||
| outpoints_supply.erase(p); | ||
| outpoints_rbf.erase(p); | ||
| } | ||
| for (const auto& p : consumed_supply) { | ||
| outpoints_supply.erase(p); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is kinda convoluted... could we just update outpoints_supply and outpoints_rbf directly on the TransactionAddedToMempool and TransactionRemovedFromMempool callbacks instead of the added/removed sets? took a stab in glozow@df433f8
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
taken, thanks
|
CI failure is a functional test so I'd assume unrelated |
|
Made a coverage report: https://dergoegge.github.io/bitcoin-coverage/pr28450/fuzz.coverage/index.html |
Looks pretty good to me, noting the main missing bits:
^which have already been marked as followups. There's no package-not-child-with-unconfirmed-parents which is by design. Also looks like RBF rules are red, perhaps it'll take a while to hit them? |
The seed corpus from the report was the result of 5000+ cpu hours, so I'd say it's likely just not able to hit the rbf paths. |
2ecdc21 to
3707ed7
Compare
A couple of those cases would look difficult to hit without intention/design to do so. One I'm unsure how it hasn't been hit, something to look at later especially as we approach package rbf.
Can't find the actual place to reply(thanks github), removed outpoints_supply entirely as it's vestigial Took all suggestions, pushed |
glozow
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK 3707ed7
Code and coverage look good. Will run overnight to sanity check that outpointsupdater hasn't broken anything.
Couple more ideas for post-26711 expansions:
- add nonexistent outpoint to hit missing inputs cases
- shuffle before submission
3707ed7 to
fb4d71e
Compare
|
Removed the |
fb4d71e to
6e46822
Compare
|
Going to hold off on all subsequent nits to get this in to un-draft #26711 and start building on top |
|
https://github.com/bitcoin/bitcoin/pull/28450/checks?check_run_id=17181111860 multiprocess build having an issue of some kind |
src/test/fuzz/package_eval.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this can cause a false positive crash on line 281. In the "mempool full" case where a tx gets added and then removed in TrimToSize(), it'll fire TransactionAddedToMempool and TransactionRemovedFromMempool. Then accepted will be false but added won't be empty.
| // Transactions may be entered and booted any number of times | |
| // Transactions may be entered and booted any number of times | |
| m_added.erase(tx); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds right, surprised I haven't hit this since it quite often chooses tiny mempool sizes too small for even a single transaction to enter.
Taken.
6e46822 to
70879e4
Compare
src/test/fuzz/package_eval.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also found the new variable package_submit confusing as well. I don't see the point of creating an additional variable, especially since it’s only passed once and negated.
70879e4 to
262ab8e
Compare
|
ACK 262ab8e Note that this is the first time I review something from the package relay project, so take that for whatever it’s worth |
glozow
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reACK 262ab8e
dergoegge
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tACK 262ab8e
Will generate and submit inputs to qa-assets once this is merged
262ab8e Add package evaluation fuzzer (Greg Sanders) Pull request description: This fuzzer target caught the issue in bitcoin#28251 within 5 minutes on master branch, and an additional issue which I've applied a preliminary patch to cover. Fuzzer target does the following: 1) Picks mempool confgs, including max package size, count, mempool size, etc 2) Generates 1 to 26 transactions with arbitrary coins/fees, the first N-1 spending only confirmed outpoints 3) Nth transaction, if >1, sweeps all unconfirmed outpoints in mempool 4) If N==1, it may submit it through single-tx submission path, to allow for more interesting topologies 5) Otherwise submits through package submission interface 6) Repeat 1-5 a few hundred times per mempool instance In other words, it ends up building chains of txns in the mempool using parents-and-children packages, which is currently the topology supported on master. The test itself is a direct rip of tx_pool.cpp, with a number of assertions removed because they were failing for unknown reasons, likely due to the notification changes of single tx submission to package, which is used to track addition/removal of transactions in the test. I'll continue working on re-adding these assertions for further invariant testing. ACKs for top commit: murchandamus: ACK 262ab8e glozow: reACK 262ab8e dergoegge: tACK 262ab8e Tree-SHA512: 190784777d0f2361b051b3271db8f79b7927e3cab88596d2c30e556da721510bd17f6cc96f6bb03403bbf0589ad3f799fa54e63c1b2bd92a2084485b5e3e96a5
This fuzzer target caught the issue in #28251 within 5 minutes on master branch, and an additional issue which I've applied a preliminary patch to cover.
Fuzzer target does the following:
In other words, it ends up building chains of txns in the mempool using parents-and-children packages, which is currently the topology supported on master.
The test itself is a direct rip of tx_pool.cpp, with a number of assertions removed because they were failing for unknown reasons, likely due to the notification changes of single tx submission to package, which is used to track addition/removal of transactions in the test. I'll continue working on re-adding these assertions for further invariant testing.