6#include <chainparams.h>
26#include <validation.h>
55void initialize_spkm_migration()
61static std::optional<std::pair<WalletDescriptor, FlatSigningProvider>> CreateWalletDescriptor(FuzzedDataProvider& fuzzed_data_provider)
65 if (!desc_str.has_value())
return std::nullopt;
68 FlatSigningProvider
keys;
70 std::vector<std::unique_ptr<Descriptor>> parsed_descs =
Parse(desc_str.value(),
keys, error,
false);
71 if (parsed_descs.empty())
return std::nullopt;
75 FlatSigningProvider out_keys;
76 std::vector<CScript> scripts_temp;
77 DescriptorCache temp_cache;
78 if (!parsed_descs.at(0)->Expand(0,
keys, scripts_temp, out_keys, &temp_cache))
return std::nullopt;
81 return std::make_pair(w_desc,
keys);
88 if (!spk_manager_res)
return nullptr;
89 return &spk_manager_res.value().get();
92FUZZ_TARGET(scriptpubkeyman, .init = initialize_spkm)
95 FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
96 FakeNodeClock clock{
ConsumeTime(fuzzed_data_provider)};
98 Chainstate& chainstate{node.chainman->ActiveChainstate()};
108 auto wallet_desc{CreateWalletDescriptor(fuzzed_data_provider)};
109 if (!wallet_desc.has_value())
return;
110 auto spk_manager{
CreateDescriptor(wallet_desc->first, wallet_desc->second, wallet)};
111 if (spk_manager ==
nullptr)
return;
114 auto wallet_desc{CreateWalletDescriptor(fuzzed_data_provider)};
115 if (!wallet_desc.has_value()) {
119 if (spk_manager->CanUpdateToWalletDescriptor(wallet_desc->first, error)) {
120 auto new_spk_manager{
CreateDescriptor(wallet_desc->first, wallet_desc->second, wallet)};
121 if (new_spk_manager !=
nullptr) spk_manager = new_spk_manager;
125 bool good_data{
true};
128 fuzzed_data_provider,
131 if (spk_manager->IsMine(script)) {
132 assert(spk_manager->GetScriptPubKeys().contains(script));
136 auto spks{spk_manager->GetScriptPubKeys()};
137 for (
const CScript& spk : spks) {
138 assert(spk_manager->IsMine(spk));
143 PKHash pk_hash{std::get_if<PKHash>(&dest) && fuzzed_data_provider.
ConsumeBool() ?
144 *std::get_if<PKHash>(&dest) :
147 (void)spk_manager->SignMessage(msg, pk_hash, str_sig);
148 (void)spk_manager->GetMetadata(dest);
153 auto spks{spk_manager->GetScriptPubKeys()};
155 auto& spk{
PickValue(fuzzed_data_provider, spks)};
156 (void)spk_manager->MarkUnusedAddresses(spk);
160 LOCK(spk_manager->cs_desc_man);
161 auto wallet_desc{spk_manager->GetWalletDescriptor()};
163 auto output_type{wallet_desc.
descriptor->GetOutputType()};
164 if (output_type.has_value()) {
165 auto dest{spk_manager->GetNewDestination(*output_type)};
168 assert(spk_manager->IsHDEnabled());
174 CMutableTransaction tx_to;
182 std::map<COutPoint, Coin> coins{
ConsumeCoins(fuzzed_data_provider)};
184 std::map<int, bilingual_str> input_errors;
185 (void)spk_manager->SignTransaction(tx_to, coins, sighash, input_errors);
193 auto psbt{*opt_psbt};
198 const PrecomputedTransactionData& txdata = *txdata_res;
199 common::PSBTFillOptions options{
206 (void)spk_manager->FillPSBT(psbt, txdata, options);
211 std::string descriptor;
212 (void)spk_manager->GetDescriptorString(descriptor, fuzzed_data_provider.
ConsumeBool());
213 (
void)spk_manager->GetEndRange();
214 (
void)spk_manager->GetKeyPoolSize();
217FUZZ_TARGET(spkm_migration, .init = initialize_spkm_migration)
220 FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
221 FakeNodeClock clock{
ConsumeTime(fuzzed_data_provider)};
223 Chainstate& chainstate{node.chainman->ActiveChainstate()};
236 std::vector<CKey>
keys;
239 if (!key.IsValid())
return;
240 auto pub_key{key.GetPubKey()};
241 if (!pub_key.IsFullyValid())
return;
242 if (legacy_data.LoadKey(key, pub_key) && std::find(
keys.begin(),
keys.end(), key) ==
keys.end())
keys.push_back(key);
245 size_t added_chains = 0;
246 bool add_hd_chain{fuzzed_data_provider.
ConsumeBool() && !
keys.empty()};
252 hd_chain.nVersion = version;
254 legacy_data.LoadHDChain(hd_chain);
258 bool add_inactive_hd_chain{fuzzed_data_provider.
ConsumeBool() && !
keys.empty()};
259 if (add_inactive_hd_chain) {
260 CKey inactive_hd_key =
PickValue(fuzzed_data_provider,
keys);
262 bool dup_chain = hd_key.
IsValid() && std::equal(hd_key.
begin(), hd_key.
end(), inactive_hd_key.
begin());
264 legacy_data.AddInactiveHDChain(hd_chain);
265 if (!dup_chain) added_chains++;
268 bool watch_only =
false;
270 if (!pub_key || !pub_key->IsFullyValid())
return;
275 if (legacy_data.LoadWatchOnly(script_dest)) watch_only =
true;
277 size_t added_script{0};
278 bool good_data{
true};
281 fuzzed_data_provider,
293 fuzzed_data_provider,
306 script = script_opt.value();
310 if (!legacy_data.HaveCScript(CScriptID(script)) && legacy_data.AddCScript(script)) added_script++;
321 std::vector<CPubKey> pubkeys;
323 for (
size_t i = 1; i < num_keys; i++) {
332 if (pubkeys.size() < num_keys)
return;
334 if (!legacy_data.HaveCScript(CScriptID(multisig_script)) && legacy_data.AddCScript(multisig_script)) {
341 auto result{legacy_data.MigrateToDescriptor()};
346 size_t added_size{
keys.size() + added_chains};
347 if (added_script > 0) {
348 assert(result->desc_spkms.size() >= added_size);
350 assert(result->desc_spkms.size() == added_size);
352 if (watch_only)
assert(!result->watch_descs.empty());
353 if (!result->solvable_descs.empty())
assert(added_script > 0);
bool ExtractDestination(const CScript &scriptPubKey, CTxDestination &addressRet)
Parse a scriptPubKey for the destination.
bool IsValidDestination(const CTxDestination &dest)
Check whether a CTxDestination corresponds to one with an address.
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a Bitcoin scriptPubKey for the given CTxDestination.
std::variant< CNoDestination, PubKeyDestination, PKHash, ScriptHash, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessV1Taproot, PayToAnchor, WitnessUnknown > CTxDestination
A txout script categorized into standard templates.
const TestingSetup * g_setup
uint256 GetBlockHash() const
CBlockIndex * Tip() const
Returns the index entry for the tip of this chain, or nullptr if none.
int Height() const
Return the maximal height in the chain.
bool IsValid() const
Check whether this private key is valid.
const std::byte * begin() const
CPubKey GetPubKey() const
Compute the public key from a private key.
const std::byte * end() const
CKeyID GetID() const
Get the KeyID of this public key (hash of its serialization).
LegacyDataSPKM * GetOrCreateLegacyDataSPKM()
int64_t m_keypool_size
Number of pre-generated keys/scripts by each spkm (part of the look-ahead process,...
RecursiveMutex cs_wallet
Main wallet lock.
util::Result< std::reference_wrapper< DescriptorScriptPubKeyMan > > AddWalletDescriptor(WalletDescriptor &desc, const FlatSigningProvider &signing_provider, const std::string &label, bool internal) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Add a descriptor to the wallet, return a ScriptPubKeyMan & associated output type.
std::string ConsumeRandomLengthString(size_t max_length)
T ConsumeIntegralInRange(T min, T max)
void Init()
When initializing the target, populate the list of keys.
std::optional< std::string > GetDescriptor(std::string_view mocked_desc) const
Get an actual descriptor string from a descriptor string whose keys were mocked.
const std::shared_ptr< const Descriptor > descriptor
static constexpr int VERSION_HD_CHAIN_SPLIT
static constexpr int VERSION_HD_BASE
A CWallet maintains a set of transactions and balances, and provides the ability to create new transa...
Descriptor with some wallet metadata.
MockedDescriptorConverter MOCKED_DESC_CONVERTER
The converter of mocked descriptors, needs to be initialized when the target is.
#define LIMITED_WHILE(condition, limit)
Can be used to limit a theoretically unbounded loop.
void BlockUntilSyncedToCurrentChain() const LOCKS_EXCLUDED(void SetWalletFlag(uint64_t flags)
Blocks until the wallet state is up-to-date to /at least/ the current chain at the time this function...
void UnsetWalletFlag(uint64_t flag)
Unsets a single wallet flag.
void SetLastBlockProcessed(int block_height, uint256 block_hash) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Set last block processed height, and write to database.
wallet::DescriptorScriptPubKeyMan * CreateDescriptor(CWallet &keystore, const std::string &desc_str, const bool success)
std::unique_ptr< WalletDatabase > CreateMockableWalletDatabase()
FUZZ_TARGET(coin_grinder)
@ WALLET_FLAG_DESCRIPTORS
Indicate that this wallet supports DescriptorScriptPubKeyMan.
constexpr TransactionSerParams TX_WITH_WITNESS
std::optional< PrecomputedTransactionData > PrecomputePSBTData(const PartiallySignedTransaction &psbt)
Compute a PrecomputedTransactionData object from a psbt.
std::vector< std::unique_ptr< Descriptor > > Parse(std::string_view descriptor, FlatSigningProvider &out, std::string &error, bool require_checksum)
Parse a descriptor string.
constexpr int MAX_PUBKEYS_PER_MULTISIG
std::unique_ptr< T > MakeNoLogFileContext(const ChainType chain_type=ChainType::REGTEST, TestOpts opts={})
Make a test setup that has disk access to the debug.log file disabled.
CScript GetScriptForMultisig(int nRequired, const std::vector< CPubKey > &keys)
Generate a multisig script.
constexpr auto MakeUCharSpan(const V &v) -> decltype(UCharSpanCast(std::span{v}))
Like the std::span constructor, but for (const) unsigned char member types only.
std::optional< int > sighash_type
The sighash type to use when signing (if PSBT does not specify).
std::vector< uint16_t > keys
SeedRandomStateForTest(SeedRand::ZEROS)
bool IsTooExpensive(std::span< const uint8_t > buffer)
Deriving "expensive" descriptors will consume useful fuzz compute. The compute is better spent on a s...
NodeSeconds ConsumeTime(FuzzedDataProvider &fuzzed_data_provider, const std::optional< int64_t > &min, const std::optional< int64_t > &max) noexcept
CScript ConsumeScript(FuzzedDataProvider &fuzzed_data_provider, const bool maybe_p2wsh) noexcept
CKey ConsumePrivateKey(FuzzedDataProvider &fuzzed_data_provider, std::optional< bool > compressed) noexcept
std::map< COutPoint, Coin > ConsumeCoins(FuzzedDataProvider &fuzzed_data_provider) noexcept
auto & PickValue(FuzzedDataProvider &fuzzed_data_provider, Collection &col)
std::optional< T > ConsumeDeserializableConstructor(FuzzedDataProvider &fuzzed_data_provider, const std::optional< size_t > &max_length=std::nullopt) noexcept
size_t CallOneOf(FuzzedDataProvider &fuzzed_data_provider, Callables... callables)
std::optional< T > ConsumeDeserializable(FuzzedDataProvider &fuzzed_data_provider, const P ¶ms, const std::optional< size_t > &max_length=std::nullopt) noexcept
uint160 ConsumeUInt160(FuzzedDataProvider &fuzzed_data_provider) noexcept
@ ZEROS
Seed with a compile time constant of zeros.