-
Notifications
You must be signed in to change notification settings - Fork 37.7k
fuzz: wallet, add target for Spend #28236
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
fuzz: wallet, add target for Spend #28236
Conversation
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. Code CoverageFor detailed information about the code coverage, see the test coverage report. ReviewsSee the guideline for information on the review process. 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. |
|
||
void InitializeWallet() { | ||
auto& node{g_setup->m_node}; | ||
wallet = CreateSyncedWallet(*node.chain, WITH_LOCK(Assert(node.chainman)->GetMutex(), return node.chainman->ActiveChain()), g_setup->coinbaseKey); |
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 that CreateSyncedWallet
will call SetupDescriptorScriptPubKeyMans()
which internally will make a seed.
void CWallet::SetupDescriptorScriptPubKeyMans()
{
AssertLockHeld(cs_wallet);
if (!IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER)) {
// Make a seed
CKey seed_key;
seed_key.MakeNewKey(true);
CPubKey seed = seed_key.GetPubKey();
assert(seed_key.VerifyPubKey(seed));
// Get the extended key
CExtKey master_key;
master_key.SetSeed(seed_key);
SetupDescriptorScriptPubKeyMans(master_key);
}
Not sure, but wouldn't it be non-deterministic? A solution would be to have a fuzz version of CreateSyncedWallet
which calls SetupDescriptorScriptPubKeyMans
passing a key that we created using buf.
From lint: + test/lint/all-lint.py
This diff appears to have added new lines with trailing whitespace.
The following changes were suspected:
diff --git a/src/wallet/test/fuzz/spend.cpp b/src/wallet/test/fuzz/spend.cpp
@@ -0,0 +1,254 @@
+namespace wallet {
+ * Singleton wallet class ensures that only one
+ * instance of CWallet is created and reused as required.
+ * of creating a new `Descriptor Wallet` each time and deletes
+CCoinControl GetNewCoinControl(FuzzedDataProvider& fuzzed_data_provider, CWallet& wallet, std::vector<COutput>& coins)
+
+ // Because none of the UTXO will ever be used (marked as spent), mining this many should be sufficient.
+ /*nAmount=*/ConsumeMoney(fuzzed_data_provider),
+ const CTxOut tx_out{ConsumeMoney(fuzzed_data_provider), ConsumeScript(fuzzed_data_provider)};
+
+ // Taking a random sub-sequence from available coins
+}
Success: no issues found in 269 source files
^---- failure generated from lint-whitespace.py |
b812189
to
885b037
Compare
Thanks, @brunoerg for your reviews! In the recent push, I've addressed most of your reviews.
This comment is really interesting, but I'm not sure whether the |
The |
You'll need to rebase on current master in any case |
885b037
to
dff1256
Compare
PS - There is one change in |
dff1256
to
17a5905
Compare
All CI checks passed now 💪 |
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.
Coverage looks decent: https://dergoegge.github.io/bitcoin-coverage/pr28236/fuzz.coverage/index.html
return instance; | ||
} | ||
|
||
CWallet& GetWallet() |
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.
CWallet& GetWallet() | |
const CWallet& GetWallet() | |
It's otherwise hard to tell if the global wallet instance is mutated. Same for GetCoins()
.
If the global instance is mutated, the target is likely to be non-deterministic which hurts fuzzer efficiency. The target should behave exactly the same when given the same input, but that might not be the case if global state is used and modified.
(The suggested change might not compile if wallet
or available_coins
are used as non-const/mutated)
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.
Yeah, this should make it more deterministic. As you said, it's causing some compilation errors with other code. I'll force-push once I've fixed 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.
The CreateTransaction()
and FundTransaction()
want the CWallet
parameter to be non-const. I'm struggling to find a work around but I'm trying.
Just wanted to clear this, I think the CWallet
instance inside these functions doesn't seem to be directly mutated or changed anytime. So, do we really want to make it to const. Am I understanding this correct?
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.
If CreateTransaction()
and FundTransaction()
do not mutate the wallet, then they should probably take a const reference instead. But glancing at FundTransaction
, it calls CWallet::LockCoin
which is not a const method and could probably lead to non-determinism since it appears to be modifying internal state of a wallet.
Line 1388 in fb85bb2
wallet.LockCoin(txin.prevout); |
Just wanted to clear this, I think the CWallet instance inside these functions doesn't seem to be directly mutated or changed anytime. So, do we really want to make it to const.
Marking things that should not be mutated as const
will make this a compile time check, giving us more confidence that the test is working properly.
You could try to refactor CreateTransaction
and/or FundTransaction
to take a const CWallet&
and see what happens when you compile. The LockCoin
issue mentioned above should be one of the things the compiler complains about.
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, I believe the LockCoin
function does mutate the global wallet
. I'll need to figure out how to make this deterministic then.
I apologize for the delayed response, I was/am occupied with something else. But, I'm looking forward to brainstorming this and finding a solution as soon as possible.
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've thought about it, and I think a global Singleton might not be the smartest way to save resources. The wallet
object definitely mutates during execution. I think I've to remove the Singleton pattern, but doing so will make the file very slow, as creating the Descriptor Wallet
is really time-consuming.
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.
If you removed the Singleton, did you perhaps not push the latest state of this PR?
}, | ||
[&] { | ||
// Occasionally, creating a random Transaction for Fuzzing. | ||
auto new_mtx = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider); |
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.
missing ser-params? See compile failure due to silent merge conflict.
Needs rebase
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.
Thank you! I'll rebase in the next force push.
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.
Spend.cpp coverage is not too bad already: https://maflcko.github.io/b-c-cov/fuzz.coverage/src/wallet/spend.cpp.gcov.html
It may be good to clarify the new coverage a bit.
CoinsResult wallet_coins; | ||
|
||
LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 50) |
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.
Seems like this should be a separate fuzz target?
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.
Yeah, I can create a separate PR for this immediately. Once it's ready, we can get it merged, and I can continue working on this. Thanks!
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.
Agree wtih @maflcko, since the seeds are created per target, it would be better to have a separate target for CoinsResult
.
I didn't understand. Are you suggesting that I reconsider what I want to increase coverage of in this file? Also, I have a question about the blue lines in the coverage reports. Do they represent the line coverage of the code during fuzzing? For instance, if these functions are encountered in the process of running any fuzz file, the fuzz coverage will display them in blue. If I'm understanding this correctly, wouldn't it still make sense to have a separate fuzz file for https://maflcko.github.io/b-c-cov/fuzz.coverage/src/wallet/spend.cpp.gcov.html |
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.
Hey,
Just did a quick pass. What is the status of this PR?
static auto testing_setup = MakeNoLogFileContext<TestChain100Setup>(); | ||
g_setup = testing_setup.get(); | ||
|
||
// Add 50 spendable UTXO, 50 BTC each, to the wallet (total balance 5000 BTC) |
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 comment is inconsistent:
// Add 50 spendable UTXO, 50 BTC each, to the wallet (total balance 5000 BTC) | |
// Add 50 spendable UTXO, 50 BTC each, to the wallet (total balance 2500 BTC) |
A variable set of available coins might be desirable. Smaller amounts could for example trigger behavior regarding negative effective value or having insufficient funds to create a transaction.
return instance; | ||
} | ||
|
||
CWallet& GetWallet() |
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.
If you removed the Singleton, did you perhaps not push the latest state of this PR?
CoinsResult wallet_coins; | ||
|
||
LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 50) |
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.
Agree wtih @maflcko, since the seeds are created per target, it would be better to have a separate target for CoinsResult
.
Are you still working on this? |
} | ||
} | ||
|
||
// Occasionally, some random `CCoutPoint` are also selected. |
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.
// Occasionally, some random `CCoutPoint` are also selected. | |
// Occasionally, some random `COutPoint` are also selected. | |
Sorry I got a little occupied with some other things and would want to continue working on this. I've the approach in mind and will force push the update by the end of this month.
|
🐙 This pull request conflicts with the target branch and needs rebase. |
Moved to draft for now. |
Picked up in #30461 |
This PR adds fuzz coverage for
wallet/spend
.Motivation: Issue 27272
This PR adds Fuzz coverage to the whole concept of Creating a New Transaction as well as other sections of the Spend file. Because
CreateTransaction
is one of the most frequently used functions in the wallet codebase, merging this PR will significantly improve the wallet codebase's Fuzz testing!I also used the
Singleton Class
concept for creating Wallet instances because it assures that only one instance of it is created during all Fuzz runs, which significantly boosts the file'sexec/sec
.