aboutsummaryrefslogtreecommitdiff
path: root/src/test/fuzz
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/fuzz')
-rw-r--r--src/test/fuzz/buffered_file.cpp4
-rw-r--r--src/test/fuzz/coinscache_sim.cpp4
-rw-r--r--src/test/fuzz/descriptor_parse.cpp96
-rw-r--r--src/test/fuzz/load_external_block_file.cpp2
-rw-r--r--src/test/fuzz/mini_miner.cpp2
-rw-r--r--src/test/fuzz/package_eval.cpp4
-rw-r--r--src/test/fuzz/script_flags.cpp21
-rw-r--r--src/test/fuzz/script_sign.cpp13
-rw-r--r--src/test/fuzz/tx_pool.cpp12
-rw-r--r--src/test/fuzz/txorphan.cpp2
-rw-r--r--src/test/fuzz/util.cpp22
-rw-r--r--src/test/fuzz/util.h4
-rw-r--r--src/test/fuzz/util/descriptor.cpp72
-rw-r--r--src/test/fuzz/util/descriptor.h48
14 files changed, 169 insertions, 137 deletions
diff --git a/src/test/fuzz/buffered_file.cpp b/src/test/fuzz/buffered_file.cpp
index 813af63738..e30c19b265 100644
--- a/src/test/fuzz/buffered_file.cpp
+++ b/src/test/fuzz/buffered_file.cpp
@@ -20,9 +20,8 @@ FUZZ_TARGET(buffered_file)
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
FuzzedFileProvider fuzzed_file_provider{fuzzed_data_provider};
std::optional<BufferedFile> opt_buffered_file;
- CAutoFile fuzzed_file{
+ AutoFile fuzzed_file{
fuzzed_file_provider.open(),
- 0,
ConsumeRandomLengthByteVector<std::byte>(fuzzed_data_provider),
};
try {
@@ -65,6 +64,5 @@ FUZZ_TARGET(buffered_file)
});
}
opt_buffered_file->GetPos();
- opt_buffered_file->GetVersion();
}
}
diff --git a/src/test/fuzz/coinscache_sim.cpp b/src/test/fuzz/coinscache_sim.cpp
index f350c9d032..648e96b4a0 100644
--- a/src/test/fuzz/coinscache_sim.cpp
+++ b/src/test/fuzz/coinscache_sim.cpp
@@ -43,7 +43,9 @@ struct PrecomputedData
for (uint32_t i = 0; i < NUM_OUTPOINTS; ++i) {
uint32_t idx = (i * 1200U) >> 12; /* Map 3 or 4 entries to same txid. */
const uint8_t ser[4] = {uint8_t(idx), uint8_t(idx >> 8), uint8_t(idx >> 16), uint8_t(idx >> 24)};
- CSHA256().Write(PREFIX_O, 1).Write(ser, sizeof(ser)).Finalize(outpoints[i].hash.begin());
+ uint256 txid;
+ CSHA256().Write(PREFIX_O, 1).Write(ser, sizeof(ser)).Finalize(txid.begin());
+ outpoints[i].hash = Txid::FromUint256(txid);
outpoints[i].n = i;
}
diff --git a/src/test/fuzz/descriptor_parse.cpp b/src/test/fuzz/descriptor_parse.cpp
index 57129a60b8..5474b38204 100644
--- a/src/test/fuzz/descriptor_parse.cpp
+++ b/src/test/fuzz/descriptor_parse.cpp
@@ -7,104 +7,10 @@
#include <pubkey.h>
#include <script/descriptor.h>
#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util/descriptor.h>
#include <util/chaintype.h>
#include <util/strencodings.h>
-//! Types are raw (un)compressed pubkeys, raw xonly pubkeys, raw privkeys (WIF), xpubs, xprvs.
-static constexpr uint8_t KEY_TYPES_COUNT{6};
-//! How many keys we'll generate in total.
-static constexpr size_t TOTAL_KEYS_GENERATED{std::numeric_limits<uint8_t>::max() + 1};
-
-/**
- * Converts a mocked descriptor string to a valid one. Every key in a mocked descriptor key is
- * represented by 2 hex characters preceded by the '%' character. We parse the two hex characters
- * as an index in a list of pre-generated keys. This list contains keys of the various types
- * accepted in descriptor keys expressions.
- */
-class MockedDescriptorConverter {
- //! 256 keys of various types.
- std::array<std::string, TOTAL_KEYS_GENERATED> keys_str;
-
-public:
- // We derive the type of key to generate from the 1-byte id parsed from hex.
- bool IdIsCompPubKey(uint8_t idx) const { return idx % KEY_TYPES_COUNT == 0; }
- bool IdIsUnCompPubKey(uint8_t idx) const { return idx % KEY_TYPES_COUNT == 1; }
- bool IdIsXOnlyPubKey(uint8_t idx) const { return idx % KEY_TYPES_COUNT == 2; }
- bool IdIsConstPrivKey(uint8_t idx) const { return idx % KEY_TYPES_COUNT == 3; }
- bool IdIsXpub(uint8_t idx) const { return idx % KEY_TYPES_COUNT == 4; }
- bool IdIsXprv(uint8_t idx) const { return idx % KEY_TYPES_COUNT == 5; }
-
- //! When initializing the target, populate the list of keys.
- void Init() {
- // The data to use as a private key or a seed for an xprv.
- std::array<std::byte, 32> key_data{std::byte{1}};
- // Generate keys of all kinds and store them in the keys array.
- for (size_t i{0}; i < TOTAL_KEYS_GENERATED; i++) {
- key_data[31] = std::byte(i);
-
- // If this is a "raw" key, generate a normal privkey. Otherwise generate
- // an extended one.
- if (IdIsCompPubKey(i) || IdIsUnCompPubKey(i) || IdIsXOnlyPubKey(i) || IdIsConstPrivKey(i)) {
- CKey privkey;
- privkey.Set(UCharCast(key_data.begin()), UCharCast(key_data.end()), !IdIsUnCompPubKey(i));
- if (IdIsCompPubKey(i) || IdIsUnCompPubKey(i)) {
- CPubKey pubkey{privkey.GetPubKey()};
- keys_str[i] = HexStr(pubkey);
- } else if (IdIsXOnlyPubKey(i)) {
- const XOnlyPubKey pubkey{privkey.GetPubKey()};
- keys_str[i] = HexStr(pubkey);
- } else {
- keys_str[i] = EncodeSecret(privkey);
- }
- } else {
- CExtKey ext_privkey;
- ext_privkey.SetSeed(key_data);
- if (IdIsXprv(i)) {
- keys_str[i] = EncodeExtKey(ext_privkey);
- } else {
- const CExtPubKey ext_pubkey{ext_privkey.Neuter()};
- keys_str[i] = EncodeExtPubKey(ext_pubkey);
- }
- }
- }
- }
-
- //! Parse an id in the keys vectors from a 2-characters hex string.
- std::optional<uint8_t> IdxFromHex(std::string_view hex_characters) const {
- if (hex_characters.size() != 2) return {};
- auto idx = ParseHex(hex_characters);
- if (idx.size() != 1) return {};
- return idx[0];
- }
-
- //! Get an actual descriptor string from a descriptor string whose keys were mocked.
- std::optional<std::string> GetDescriptor(std::string_view mocked_desc) const {
- // The smallest fragment would be "pk(%00)"
- if (mocked_desc.size() < 7) return {};
-
- // The actual descriptor string to be returned.
- std::string desc;
- desc.reserve(mocked_desc.size());
-
- // Replace all occurrences of '%' followed by two hex characters with the corresponding key.
- for (size_t i = 0; i < mocked_desc.size();) {
- if (mocked_desc[i] == '%') {
- if (i + 3 >= mocked_desc.size()) return {};
- if (const auto idx = IdxFromHex(mocked_desc.substr(i + 1, 2))) {
- desc += keys_str[*idx];
- i += 3;
- } else {
- return {};
- }
- } else {
- desc += mocked_desc[i++];
- }
- }
-
- return desc;
- }
-};
-
//! The converter of mocked descriptors, needs to be initialized when the target is.
MockedDescriptorConverter MOCKED_DESC_CONVERTER;
diff --git a/src/test/fuzz/load_external_block_file.cpp b/src/test/fuzz/load_external_block_file.cpp
index ae4f5d089b..6460261f0f 100644
--- a/src/test/fuzz/load_external_block_file.cpp
+++ b/src/test/fuzz/load_external_block_file.cpp
@@ -28,7 +28,7 @@ FUZZ_TARGET(load_external_block_file, .init = initialize_load_external_block_fil
{
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
FuzzedFileProvider fuzzed_file_provider{fuzzed_data_provider};
- CAutoFile fuzzed_block_file{fuzzed_file_provider.open(), CLIENT_VERSION};
+ AutoFile fuzzed_block_file{fuzzed_file_provider.open()};
if (fuzzed_block_file.IsNull()) {
return;
}
diff --git a/src/test/fuzz/mini_miner.cpp b/src/test/fuzz/mini_miner.cpp
index 2f53943c31..84f9bb4ad0 100644
--- a/src/test/fuzz/mini_miner.cpp
+++ b/src/test/fuzz/mini_miner.cpp
@@ -25,7 +25,7 @@ void initialize_miner()
static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>();
g_setup = testing_setup.get();
for (uint32_t i = 0; i < uint32_t{100}; ++i) {
- g_available_coins.emplace_back(uint256::ZERO, i);
+ g_available_coins.emplace_back(Txid::FromUint256(uint256::ZERO), i);
}
}
diff --git a/src/test/fuzz/package_eval.cpp b/src/test/fuzz/package_eval.cpp
index 8658c0b45a..064930c5aa 100644
--- a/src/test/fuzz/package_eval.cpp
+++ b/src/test/fuzz/package_eval.cpp
@@ -252,10 +252,10 @@ FUZZ_TARGET(tx_package_eval, .init = initialize_tx_pool)
}
if (fuzzed_data_provider.ConsumeBool()) {
const auto& txid = fuzzed_data_provider.ConsumeBool() ?
- txs.back()->GetHash().ToUint256() :
+ txs.back()->GetHash() :
PickValue(fuzzed_data_provider, mempool_outpoints).hash;
const auto delta = fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(-50 * COIN, +50 * COIN);
- tx_pool.PrioritiseTransaction(txid, delta);
+ tx_pool.PrioritiseTransaction(txid.ToUint256(), delta);
}
// Remember all added transactions
diff --git a/src/test/fuzz/script_flags.cpp b/src/test/fuzz/script_flags.cpp
index 3b8f5c068d..accb32f1cc 100644
--- a/src/test/fuzz/script_flags.cpp
+++ b/src/test/fuzz/script_flags.cpp
@@ -3,25 +3,22 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <consensus/amount.h>
-#include <pubkey.h>
+#include <primitives/transaction.h>
#include <script/interpreter.h>
+#include <serialize.h>
#include <streams.h>
+#include <test/fuzz/fuzz.h>
#include <test/util/script.h>
-#include <version.h>
-#include <test/fuzz/fuzz.h>
+#include <cassert>
+#include <ios>
+#include <utility>
+#include <vector>
FUZZ_TARGET(script_flags)
{
- CDataStream ds(buffer, SER_NETWORK, INIT_PROTO_VERSION);
- try {
- int nVersion;
- ds >> nVersion;
- ds.SetVersion(nVersion);
- } catch (const std::ios_base::failure&) {
- return;
- }
-
+ if (buffer.size() > 100'000) return;
+ DataStream ds{buffer};
try {
const CTransaction tx(deserialize, TX_WITH_WITNESS, ds);
diff --git a/src/test/fuzz/script_sign.cpp b/src/test/fuzz/script_sign.cpp
index 0944c91c4a..9c2966e0cb 100644
--- a/src/test/fuzz/script_sign.cpp
+++ b/src/test/fuzz/script_sign.cpp
@@ -125,18 +125,7 @@ FUZZ_TARGET(script_sign, .init = initialize_script_sign)
}
(void)signature_creator.CreateSig(provider, vch_sig, address, ConsumeScript(fuzzed_data_provider), fuzzed_data_provider.PickValueInArray({SigVersion::BASE, SigVersion::WITNESS_V0}));
}
- std::map<COutPoint, Coin> coins;
- LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10000) {
- const std::optional<COutPoint> outpoint = ConsumeDeserializable<COutPoint>(fuzzed_data_provider);
- if (!outpoint) {
- break;
- }
- const std::optional<Coin> coin = ConsumeDeserializable<Coin>(fuzzed_data_provider);
- if (!coin) {
- break;
- }
- coins[*outpoint] = *coin;
- }
+ std::map<COutPoint, Coin> coins{ConsumeCoins(fuzzed_data_provider)};
std::map<int, bilingual_str> input_errors;
(void)SignTransaction(sign_transaction_tx_to, &provider, coins, fuzzed_data_provider.ConsumeIntegral<int>(), input_errors);
}
diff --git a/src/test/fuzz/tx_pool.cpp b/src/test/fuzz/tx_pool.cpp
index 96095539ec..ffa0c1216e 100644
--- a/src/test/fuzz/tx_pool.cpp
+++ b/src/test/fuzz/tx_pool.cpp
@@ -277,10 +277,10 @@ FUZZ_TARGET(tx_pool_standard, .init = initialize_tx_pool)
}
if (fuzzed_data_provider.ConsumeBool()) {
const auto& txid = fuzzed_data_provider.ConsumeBool() ?
- tx->GetHash().ToUint256() :
+ tx->GetHash() :
PickValue(fuzzed_data_provider, outpoints_rbf).hash;
const auto delta = fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(-50 * COIN, +50 * COIN);
- tx_pool.PrioritiseTransaction(txid, delta);
+ tx_pool.PrioritiseTransaction(txid.ToUint256(), delta);
}
// Remember all removed and added transactions
@@ -367,7 +367,7 @@ FUZZ_TARGET(tx_pool, .init = initialize_tx_pool)
MockTime(fuzzed_data_provider, chainstate);
- std::vector<uint256> txids;
+ std::vector<Txid> txids;
txids.reserve(g_outpoints_coinbase_init_mature.size());
for (const auto& outpoint : g_outpoints_coinbase_init_mature) {
txids.push_back(outpoint.hash);
@@ -375,7 +375,7 @@ FUZZ_TARGET(tx_pool, .init = initialize_tx_pool)
for (int i{0}; i <= 3; ++i) {
// Add some immature and non-existent outpoints
txids.push_back(g_outpoints_coinbase_init_immature.at(i).hash);
- txids.push_back(ConsumeUInt256(fuzzed_data_provider));
+ txids.push_back(Txid::FromUint256(ConsumeUInt256(fuzzed_data_provider)));
}
SetMempoolConstraints(*node.args, fuzzed_data_provider);
@@ -396,10 +396,10 @@ FUZZ_TARGET(tx_pool, .init = initialize_tx_pool)
}
if (fuzzed_data_provider.ConsumeBool()) {
const auto txid = fuzzed_data_provider.ConsumeBool() ?
- mut_tx.GetHash().ToUint256() :
+ mut_tx.GetHash() :
PickValue(fuzzed_data_provider, txids);
const auto delta = fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(-50 * COIN, +50 * COIN);
- tx_pool.PrioritiseTransaction(txid, delta);
+ tx_pool.PrioritiseTransaction(txid.ToUint256(), delta);
}
const auto tx = MakeTransactionRef(mut_tx);
diff --git a/src/test/fuzz/txorphan.cpp b/src/test/fuzz/txorphan.cpp
index a84dc951fc..e9ceb299fe 100644
--- a/src/test/fuzz/txorphan.cpp
+++ b/src/test/fuzz/txorphan.cpp
@@ -39,7 +39,7 @@ FUZZ_TARGET(txorphan, .init = initialize_orphanage)
std::vector<COutPoint> outpoints;
// initial outpoints used to construct transactions later
for (uint8_t i = 0; i < 4; i++) {
- outpoints.emplace_back(uint256{i}, 0);
+ outpoints.emplace_back(Txid::FromUint256(uint256{i}), 0);
}
// if true, allow duplicate input when constructing tx
const bool duplicate_input = fuzzed_data_provider.ConsumeBool();
diff --git a/src/test/fuzz/util.cpp b/src/test/fuzz/util.cpp
index 87ca2f6aed..90ef58d437 100644
--- a/src/test/fuzz/util.cpp
+++ b/src/test/fuzz/util.cpp
@@ -40,7 +40,7 @@ int64_t ConsumeTime(FuzzedDataProvider& fuzzed_data_provider, const std::optiona
return fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(min.value_or(time_min), max.value_or(time_max));
}
-CMutableTransaction ConsumeTransaction(FuzzedDataProvider& fuzzed_data_provider, const std::optional<std::vector<uint256>>& prevout_txids, const int max_num_in, const int max_num_out) noexcept
+CMutableTransaction ConsumeTransaction(FuzzedDataProvider& fuzzed_data_provider, const std::optional<std::vector<Txid>>& prevout_txids, const int max_num_in, const int max_num_out) noexcept
{
CMutableTransaction tx_mut;
const auto p2wsh_op_true = fuzzed_data_provider.ConsumeBool();
@@ -53,7 +53,7 @@ CMutableTransaction ConsumeTransaction(FuzzedDataProvider& fuzzed_data_provider,
for (int i = 0; i < num_in; ++i) {
const auto& txid_prev = prevout_txids ?
PickValue(fuzzed_data_provider, *prevout_txids) :
- ConsumeUInt256(fuzzed_data_provider);
+ Txid::FromUint256(ConsumeUInt256(fuzzed_data_provider));
const auto index_out = fuzzed_data_provider.ConsumeIntegralInRange<uint32_t>(0, max_num_out);
const auto sequence = ConsumeSequence(fuzzed_data_provider);
const auto script_sig = p2wsh_op_true ? CScript{} : ConsumeScript(fuzzed_data_provider);
@@ -164,6 +164,24 @@ uint32_t ConsumeSequence(FuzzedDataProvider& fuzzed_data_provider) noexcept
fuzzed_data_provider.ConsumeIntegral<uint32_t>();
}
+std::map<COutPoint, Coin> ConsumeCoins(FuzzedDataProvider& fuzzed_data_provider) noexcept
+{
+ std::map<COutPoint, Coin> coins;
+ LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10000) {
+ const std::optional<COutPoint> outpoint{ConsumeDeserializable<COutPoint>(fuzzed_data_provider)};
+ if (!outpoint) {
+ break;
+ }
+ const std::optional<Coin> coin{ConsumeDeserializable<Coin>(fuzzed_data_provider)};
+ if (!coin) {
+ break;
+ }
+ coins[*outpoint] = *coin;
+ }
+
+ return coins;
+}
+
CTxDestination ConsumeTxDestination(FuzzedDataProvider& fuzzed_data_provider) noexcept
{
CTxDestination tx_destination;
diff --git a/src/test/fuzz/util.h b/src/test/fuzz/util.h
index 0ad2ed6128..045476ab86 100644
--- a/src/test/fuzz/util.h
+++ b/src/test/fuzz/util.h
@@ -145,7 +145,7 @@ template <typename WeakEnumType, size_t size>
[[nodiscard]] int64_t ConsumeTime(FuzzedDataProvider& fuzzed_data_provider, const std::optional<int64_t>& min = std::nullopt, const std::optional<int64_t>& max = std::nullopt) noexcept;
-[[nodiscard]] CMutableTransaction ConsumeTransaction(FuzzedDataProvider& fuzzed_data_provider, const std::optional<std::vector<uint256>>& prevout_txids, const int max_num_in = 10, const int max_num_out = 10) noexcept;
+[[nodiscard]] CMutableTransaction ConsumeTransaction(FuzzedDataProvider& fuzzed_data_provider, const std::optional<std::vector<Txid>>& prevout_txids, const int max_num_in = 10, const int max_num_out = 10) noexcept;
[[nodiscard]] CScriptWitness ConsumeScriptWitness(FuzzedDataProvider& fuzzed_data_provider, const size_t max_stack_elem_size = 32) noexcept;
@@ -181,6 +181,8 @@ template <typename WeakEnumType, size_t size>
return UintToArith256(ConsumeUInt256(fuzzed_data_provider));
}
+[[nodiscard]] std::map<COutPoint, Coin> ConsumeCoins(FuzzedDataProvider& fuzzed_data_provider) noexcept;
+
[[nodiscard]] CTxDestination ConsumeTxDestination(FuzzedDataProvider& fuzzed_data_provider) noexcept;
[[nodiscard]] CKey ConsumePrivateKey(FuzzedDataProvider& fuzzed_data_provider, std::optional<bool> compressed = std::nullopt) noexcept;
diff --git a/src/test/fuzz/util/descriptor.cpp b/src/test/fuzz/util/descriptor.cpp
new file mode 100644
index 0000000000..5bfd2721ce
--- /dev/null
+++ b/src/test/fuzz/util/descriptor.cpp
@@ -0,0 +1,72 @@
+// Copyright (c) 2023-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/util/descriptor.h>
+
+void MockedDescriptorConverter::Init() {
+ // The data to use as a private key or a seed for an xprv.
+ std::array<std::byte, 32> key_data{std::byte{1}};
+ // Generate keys of all kinds and store them in the keys array.
+ for (size_t i{0}; i < TOTAL_KEYS_GENERATED; i++) {
+ key_data[31] = std::byte(i);
+
+ // If this is a "raw" key, generate a normal privkey. Otherwise generate
+ // an extended one.
+ if (IdIsCompPubKey(i) || IdIsUnCompPubKey(i) || IdIsXOnlyPubKey(i) || IdIsConstPrivKey(i)) {
+ CKey privkey;
+ privkey.Set(UCharCast(key_data.begin()), UCharCast(key_data.end()), !IdIsUnCompPubKey(i));
+ if (IdIsCompPubKey(i) || IdIsUnCompPubKey(i)) {
+ CPubKey pubkey{privkey.GetPubKey()};
+ keys_str[i] = HexStr(pubkey);
+ } else if (IdIsXOnlyPubKey(i)) {
+ const XOnlyPubKey pubkey{privkey.GetPubKey()};
+ keys_str[i] = HexStr(pubkey);
+ } else {
+ keys_str[i] = EncodeSecret(privkey);
+ }
+ } else {
+ CExtKey ext_privkey;
+ ext_privkey.SetSeed(key_data);
+ if (IdIsXprv(i)) {
+ keys_str[i] = EncodeExtKey(ext_privkey);
+ } else {
+ const CExtPubKey ext_pubkey{ext_privkey.Neuter()};
+ keys_str[i] = EncodeExtPubKey(ext_pubkey);
+ }
+ }
+ }
+}
+
+std::optional<uint8_t> MockedDescriptorConverter::IdxFromHex(std::string_view hex_characters) const {
+ if (hex_characters.size() != 2) return {};
+ auto idx = ParseHex(hex_characters);
+ if (idx.size() != 1) return {};
+ return idx[0];
+}
+
+std::optional<std::string> MockedDescriptorConverter::GetDescriptor(std::string_view mocked_desc) const {
+ // The smallest fragment would be "pk(%00)"
+ if (mocked_desc.size() < 7) return {};
+
+ // The actual descriptor string to be returned.
+ std::string desc;
+ desc.reserve(mocked_desc.size());
+
+ // Replace all occurrences of '%' followed by two hex characters with the corresponding key.
+ for (size_t i = 0; i < mocked_desc.size();) {
+ if (mocked_desc[i] == '%') {
+ if (i + 3 >= mocked_desc.size()) return {};
+ if (const auto idx = IdxFromHex(mocked_desc.substr(i + 1, 2))) {
+ desc += keys_str[*idx];
+ i += 3;
+ } else {
+ return {};
+ }
+ } else {
+ desc += mocked_desc[i++];
+ }
+ }
+
+ return desc;
+}
diff --git a/src/test/fuzz/util/descriptor.h b/src/test/fuzz/util/descriptor.h
new file mode 100644
index 0000000000..6289b91b07
--- /dev/null
+++ b/src/test/fuzz/util/descriptor.h
@@ -0,0 +1,48 @@
+// Copyright (c) 2023-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.
+
+#ifndef BITCOIN_TEST_FUZZ_UTIL_DESCRIPTOR_H
+#define BITCOIN_TEST_FUZZ_UTIL_DESCRIPTOR_H
+
+#include <key_io.h>
+#include <util/strencodings.h>
+#include <script/descriptor.h>
+
+#include <functional>
+
+/**
+ * Converts a mocked descriptor string to a valid one. Every key in a mocked descriptor key is
+ * represented by 2 hex characters preceded by the '%' character. We parse the two hex characters
+ * as an index in a list of pre-generated keys. This list contains keys of the various types
+ * accepted in descriptor keys expressions.
+ */
+class MockedDescriptorConverter {
+private:
+ //! Types are raw (un)compressed pubkeys, raw xonly pubkeys, raw privkeys (WIF), xpubs, xprvs.
+ static constexpr uint8_t KEY_TYPES_COUNT{6};
+ //! How many keys we'll generate in total.
+ static constexpr size_t TOTAL_KEYS_GENERATED{std::numeric_limits<uint8_t>::max() + 1};
+ //! 256 keys of various types.
+ std::array<std::string, TOTAL_KEYS_GENERATED> keys_str;
+
+public:
+ // We derive the type of key to generate from the 1-byte id parsed from hex.
+ bool IdIsCompPubKey(uint8_t idx) const { return idx % KEY_TYPES_COUNT == 0; }
+ bool IdIsUnCompPubKey(uint8_t idx) const { return idx % KEY_TYPES_COUNT == 1; }
+ bool IdIsXOnlyPubKey(uint8_t idx) const { return idx % KEY_TYPES_COUNT == 2; }
+ bool IdIsConstPrivKey(uint8_t idx) const { return idx % KEY_TYPES_COUNT == 3; }
+ bool IdIsXpub(uint8_t idx) const { return idx % KEY_TYPES_COUNT == 4; }
+ bool IdIsXprv(uint8_t idx) const { return idx % KEY_TYPES_COUNT == 5; }
+
+ //! When initializing the target, populate the list of keys.
+ void Init();
+
+ //! Parse an id in the keys vectors from a 2-characters hex string.
+ std::optional<uint8_t> IdxFromHex(std::string_view hex_characters) const;
+
+ //! Get an actual descriptor string from a descriptor string whose keys were mocked.
+ std::optional<std::string> GetDescriptor(std::string_view mocked_desc) const;
+};
+
+#endif // BITCOIN_TEST_FUZZ_UTIL_DESCRIPTOR_H