Skip to content

Commit

Permalink
fuzz: wallet: add target for CreateTransaction
Browse files Browse the repository at this point in the history
  • Loading branch information
brunoerg committed Apr 22, 2024
1 parent 1849c06 commit cbda244
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 1 deletion.
3 changes: 2 additions & 1 deletion src/Makefile.test.include
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,8 @@ FUZZ_WALLET_SRC = \
if USE_SQLITE
FUZZ_WALLET_SRC += \
wallet/test/fuzz/notifications.cpp \
wallet/test/fuzz/scriptpubkeyman.cpp
wallet/test/fuzz/scriptpubkeyman.cpp \
wallet/test/fuzz/spend.cpp
endif # USE_SQLITE

BITCOIN_TEST_SUITE += \
Expand Down
106 changes: 106 additions & 0 deletions src/wallet/test/fuzz/spend.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// Copyright (c) 2024-present The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
#include <test/util/setup_common.h>
#include <wallet/coincontrol.h>
#include <wallet/context.h>
#include <wallet/spend.h>
#include <wallet/test/util.h>
#include <wallet/wallet.h>

namespace wallet {
namespace {
const TestingSetup* g_setup;

void initialize_setup()
{
static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>();
g_setup = testing_setup.get();
}

/**
* Wraps a descriptor wallet for fuzzing.
*/
struct FuzzedWallet {
std::shared_ptr<CWallet> wallet;
FuzzedWallet()
{
auto& chain{*Assert(g_setup->m_node.chain)};
const auto seed_insecure{"tprv8ZgxMBicQKsPd1QwsGgzfu2pcPYbBosZhJknqreRHgsWx32nNEhMjGQX2cgFL8n6wz9xdDYwLcs78N4nsCo32cxEX8RBtwGsEGgybLiQJfk"};
wallet = std::make_shared<CWallet>(&chain, "", CreateMockableWalletDatabase());
{
LOCK(wallet->cs_wallet);
wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
auto height{*Assert(chain.getHeight())};
wallet->SetLastBlockProcessed(height, chain.getBlockHash(height));
}
wallet->m_keypool_size = 1; // Avoid timeout in TopUp()
assert(wallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS));
ImportDescriptors(*wallet, seed_insecure);
}
CTxDestination GetDestination(FuzzedDataProvider& fuzzed_data_provider)
{
auto type{fuzzed_data_provider.PickValueInArray(OUTPUT_TYPES)};
util::Result<CTxDestination> op_dest{util::Error{}};
if (fuzzed_data_provider.ConsumeBool()) {
op_dest = wallet->GetNewDestination(type, "");
} else {
op_dest = wallet->GetNewChangeDestination(type);
}
return *Assert(op_dest);
}
};

FUZZ_TARGET(wallet_create_transaction, .init = initialize_setup)
{
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};

const auto& node = g_setup->m_node;
ArgsManager& args = *node.args;
args.ForceSetArg("-dustrelayfee", ToString(fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(0, MAX_MONEY)));
FuzzedWallet fuzzed_wallet;

CCoinControl coin_control;
if (fuzzed_data_provider.ConsumeBool()) coin_control.m_version = fuzzed_data_provider.ConsumeIntegral<unsigned int>();
coin_control.m_avoid_partial_spends = fuzzed_data_provider.ConsumeBool();
coin_control.m_include_unsafe_inputs = fuzzed_data_provider.ConsumeBool();
if (fuzzed_data_provider.ConsumeBool()) coin_control.m_confirm_target = fuzzed_data_provider.ConsumeIntegral<unsigned int>();
coin_control.destChange = fuzzed_data_provider.ConsumeBool() ? fuzzed_wallet.GetDestination(fuzzed_data_provider) : ConsumeTxDestination(fuzzed_data_provider);
if (fuzzed_data_provider.ConsumeBool()) coin_control.m_change_type = fuzzed_data_provider.PickValueInArray(OUTPUT_TYPES);
if (fuzzed_data_provider.ConsumeBool()) coin_control.m_feerate = CFeeRate(ConsumeMoney(fuzzed_data_provider, /*max=*/COIN));
coin_control.m_allow_other_inputs = fuzzed_data_provider.ConsumeBool();
coin_control.m_locktime = fuzzed_data_provider.ConsumeIntegral<unsigned int>();
coin_control.fOverrideFeeRate = fuzzed_data_provider.ConsumeBool();

std::vector<CRecipient> recipients;
LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 100) {
CTxDestination destination;
CallOneOf(
fuzzed_data_provider,
[&] {
destination = fuzzed_wallet.GetDestination(fuzzed_data_provider);
},
[&] {
CScript script;
script << OP_RETURN;
destination = CNoDestination{script};
},
[&] {
destination = ConsumeTxDestination(fuzzed_data_provider);
}
);
recipients.push_back({destination,
/*nAmount=*/ConsumeMoney(fuzzed_data_provider),
/*fSubtractFeeFromAmount=*/fuzzed_data_provider.ConsumeBool()});
}

std::optional<unsigned int> change_pos;
if (fuzzed_data_provider.ConsumeBool()) change_pos = fuzzed_data_provider.ConsumeIntegral<unsigned int>();
(void)CreateTransaction(*fuzzed_wallet.wallet, recipients, change_pos, coin_control);
}
} // namespace
} // namespace wallet

0 comments on commit cbda244

Please sign in to comment.