aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.test.include3
-rw-r--r--src/Makefile.test_fuzz.include2
-rw-r--r--src/bench/disconnected_transactions.cpp2
-rw-r--r--src/bench/duplicate_inputs.cpp2
-rw-r--r--src/bench/load_external.cpp2
-rw-r--r--src/bench/mempool_stress.cpp2
-rw-r--r--src/bench/pool.cpp3
-rw-r--r--src/bench/streams_findbyte.cpp2
-rw-r--r--src/bitcoin-tx.cpp4
-rw-r--r--src/coins.cpp4
-rw-r--r--src/coins.h5
-rw-r--r--src/common/bloom.cpp4
-rw-r--r--src/index/txindex.cpp2
-rw-r--r--src/kernel/chainparams.cpp4
-rw-r--r--src/kernel/coinstats.cpp4
-rw-r--r--src/net.cpp22
-rw-r--r--src/net.h1
-rw-r--r--src/node/blockstorage.cpp35
-rw-r--r--src/node/blockstorage.h16
-rw-r--r--src/node/transaction.cpp2
-rw-r--r--src/primitives/transaction.cpp2
-rw-r--r--src/primitives/transaction.h9
-rw-r--r--src/qt/coincontroldialog.cpp8
-rw-r--r--src/rest.cpp4
-rw-r--r--src/rpc/blockchain.cpp4
-rw-r--r--src/rpc/mempool.cpp2
-rw-r--r--src/rpc/rawtransaction_util.cpp4
-rw-r--r--src/rpc/txoutproof.cpp2
-rw-r--r--src/script/interpreter.h16
-rw-r--r--src/streams.h32
-rw-r--r--src/support/allocators/pool.h2
-rw-r--r--src/test/blockencodings_tests.cpp4
-rw-r--r--src/test/bloom_tests.cpp16
-rw-r--r--src/test/coins_tests.cpp14
-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
-rw-r--r--src/test/miner_tests.cpp28
-rw-r--r--src/test/miniminer_tests.cpp20
-rw-r--r--src/test/net_peer_connection_tests.cpp10
-rw-r--r--src/test/orphanage_tests.cpp2
-rw-r--r--src/test/pool_tests.cpp24
-rw-r--r--src/test/sighash_tests.cpp2
-rw-r--r--src/test/streams_tests.cpp9
-rw-r--r--src/test/transaction_tests.cpp9
-rw-r--r--src/test/txpackage_tests.cpp6
-rw-r--r--src/test/util/coins.cpp3
-rw-r--r--src/test/util/setup_common.cpp2
-rw-r--r--src/test/validation_chainstatemanager_tests.cpp2
-rw-r--r--src/txmempool.cpp2
-rw-r--r--src/util/check.h1
-rw-r--r--src/util/transaction_identifier.h5
-rw-r--r--src/validation.cpp6
-rw-r--r--src/validation.h2
-rw-r--r--src/wallet/receive.cpp4
-rw-r--r--src/wallet/rpc/coins.cpp2
-rw-r--r--src/wallet/rpc/spend.cpp2
-rw-r--r--src/wallet/spend.cpp4
-rw-r--r--src/wallet/test/feebumper_tests.cpp2
-rw-r--r--src/wallet/test/fuzz/notifications.cpp166
-rw-r--r--src/wallet/test/fuzz/scriptpubkeyman.cpp165
-rw-r--r--src/wallet/test/wallet_tests.cpp6
-rw-r--r--src/wallet/wallet.cpp4
-rw-r--r--src/wallet/walletdb.cpp2
75 files changed, 677 insertions, 359 deletions
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index e9d3bff1de..416a11b0c0 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -205,7 +205,8 @@ FUZZ_WALLET_SRC = \
if USE_SQLITE
FUZZ_WALLET_SRC += \
- wallet/test/fuzz/notifications.cpp
+ wallet/test/fuzz/notifications.cpp \
+ wallet/test/fuzz/scriptpubkeyman.cpp
endif # USE_SQLITE
BITCOIN_TEST_SUITE += \
diff --git a/src/Makefile.test_fuzz.include b/src/Makefile.test_fuzz.include
index aa9c052750..b4337991e4 100644
--- a/src/Makefile.test_fuzz.include
+++ b/src/Makefile.test_fuzz.include
@@ -11,6 +11,7 @@ TEST_FUZZ_H = \
test/fuzz/fuzz.h \
test/fuzz/FuzzedDataProvider.h \
test/fuzz/util.h \
+ test/fuzz/util/descriptor.h \
test/fuzz/util/mempool.h \
test/fuzz/util/net.h
@@ -19,6 +20,7 @@ libtest_fuzz_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libtest_fuzz_a_SOURCES = \
test/fuzz/fuzz.cpp \
test/fuzz/util.cpp \
+ test/fuzz/util/descriptor.cpp \
test/fuzz/util/mempool.cpp \
test/fuzz/util/net.cpp \
$(TEST_FUZZ_H)
diff --git a/src/bench/disconnected_transactions.cpp b/src/bench/disconnected_transactions.cpp
index 91ce904dd9..f48175d472 100644
--- a/src/bench/disconnected_transactions.cpp
+++ b/src/bench/disconnected_transactions.cpp
@@ -28,7 +28,7 @@ struct ReorgTxns {
static BlockTxns CreateRandomTransactions(size_t num_txns)
{
// Ensure every transaction has a different txid by having each one spend the previous one.
- static uint256 prevout_hash{uint256::ZERO};
+ static Txid prevout_hash{};
BlockTxns txns;
txns.reserve(num_txns);
diff --git a/src/bench/duplicate_inputs.cpp b/src/bench/duplicate_inputs.cpp
index a1c8d4d942..b56054ae89 100644
--- a/src/bench/duplicate_inputs.cpp
+++ b/src/bench/duplicate_inputs.cpp
@@ -47,7 +47,7 @@ static void DuplicateInputs(benchmark::Bench& bench)
uint64_t n_inputs = (((MAX_BLOCK_SERIALIZED_SIZE / WITNESS_SCALE_FACTOR) - (CTransaction(coinbaseTx).GetTotalSize() + CTransaction(naughtyTx).GetTotalSize())) / 41) - 100;
for (uint64_t x = 0; x < (n_inputs - 1); ++x) {
- naughtyTx.vin.emplace_back(GetRandHash(), 0, CScript(), 0);
+ naughtyTx.vin.emplace_back(Txid::FromUint256(GetRandHash()), 0, CScript(), 0);
}
naughtyTx.vin.emplace_back(naughtyTx.vin.back());
diff --git a/src/bench/load_external.cpp b/src/bench/load_external.cpp
index 3b100d97b0..fba1233901 100644
--- a/src/bench/load_external.cpp
+++ b/src/bench/load_external.cpp
@@ -55,7 +55,7 @@ static void LoadExternalBlockFile(benchmark::Bench& bench)
bench.run([&] {
// "rb" is "binary, O_RDONLY", positioned to the start of the file.
// The file will be closed by LoadExternalBlockFile().
- CAutoFile file{fsbridge::fopen(blkfile, "rb"), CLIENT_VERSION};
+ AutoFile file{fsbridge::fopen(blkfile, "rb")};
testing_setup->m_node.chainman->LoadExternalBlockFile(file, &pos, &blocks_with_unknown_parent);
});
fs::remove(blkfile);
diff --git a/src/bench/mempool_stress.cpp b/src/bench/mempool_stress.cpp
index 993db66653..fe3e204fb3 100644
--- a/src/bench/mempool_stress.cpp
+++ b/src/bench/mempool_stress.cpp
@@ -56,7 +56,7 @@ static std::vector<CTransactionRef> CreateOrderedCoins(FastRandomContext& det_ra
for (size_t ancestor = 0; ancestor < n_ancestors && !available_coins.empty(); ++ancestor){
size_t idx = det_rand.randrange(available_coins.size());
Available coin = available_coins[idx];
- uint256 hash = coin.ref->GetHash();
+ Txid hash = coin.ref->GetHash();
// biased towards taking min_ancestors parents, but maybe more
size_t n_to_take = det_rand.randrange(2) == 0 ?
min_ancestors :
diff --git a/src/bench/pool.cpp b/src/bench/pool.cpp
index b3e54d85a2..b2a5f8debf 100644
--- a/src/bench/pool.cpp
+++ b/src/bench/pool.cpp
@@ -37,8 +37,7 @@ static void PoolAllocator_StdUnorderedMapWithPoolResource(benchmark::Bench& benc
std::hash<uint64_t>,
std::equal_to<uint64_t>,
PoolAllocator<std::pair<const uint64_t, uint64_t>,
- sizeof(std::pair<const uint64_t, uint64_t>) + 4 * sizeof(void*),
- alignof(void*)>>;
+ sizeof(std::pair<const uint64_t, uint64_t>) + 4 * sizeof(void*)>>;
// make sure the resource supports large enough pools to hold the node. We do this by adding the size of a few pointers to it.
auto pool_resource = Map::allocator_type::ResourceType();
diff --git a/src/bench/streams_findbyte.cpp b/src/bench/streams_findbyte.cpp
index 4aaccb2af8..5098262e9a 100644
--- a/src/bench/streams_findbyte.cpp
+++ b/src/bench/streams_findbyte.cpp
@@ -14,7 +14,7 @@
static void FindByte(benchmark::Bench& bench)
{
// Setup
- CAutoFile file{fsbridge::fopen("streams_tmp", "w+b"), 0};
+ AutoFile file{fsbridge::fopen("streams_tmp", "w+b")};
const size_t file_size = 200;
uint8_t data[file_size] = {0};
data[file_size-1] = 1;
diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp
index 103d8885db..8fe2881f6f 100644
--- a/src/bitcoin-tx.cpp
+++ b/src/bitcoin-tx.cpp
@@ -280,7 +280,7 @@ static void MutateTxAddInput(CMutableTransaction& tx, const std::string& strInpu
}
// append to transaction input list
- CTxIn txin(txid, vout, CScript(), nSequenceIn);
+ CTxIn txin(Txid::FromUint256(txid), vout, CScript(), nSequenceIn);
tx.vin.push_back(txin);
}
@@ -629,7 +629,7 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr)
if (nOut < 0)
throw std::runtime_error("vout cannot be negative");
- COutPoint out(txid, nOut);
+ COutPoint out(Txid::FromUint256(txid), nOut);
std::vector<unsigned char> pkData(ParseHexUV(prevOut["scriptPubKey"], "scriptPubKey"));
CScript scriptPubKey(pkData.begin(), pkData.end());
diff --git a/src/coins.cpp b/src/coins.cpp
index f576fae748..b62653e0de 100644
--- a/src/coins.cpp
+++ b/src/coins.cpp
@@ -116,7 +116,7 @@ void CCoinsViewCache::EmplaceCoinInternalDANGER(COutPoint&& outpoint, Coin&& coi
void AddCoins(CCoinsViewCache& cache, const CTransaction &tx, int nHeight, bool check_for_overwrite) {
bool fCoinbase = tx.IsCoinBase();
- const uint256& txid = tx.GetHash();
+ const Txid& txid = tx.GetHash();
for (size_t i = 0; i < tx.vout.size(); ++i) {
bool overwrite = check_for_overwrite ? cache.HaveCoin(COutPoint(txid, i)) : fCoinbase;
// Coinbase transactions can always be overwritten, in order to correctly
@@ -341,7 +341,7 @@ void CCoinsViewCache::SanityCheck() const
static const size_t MIN_TRANSACTION_OUTPUT_WEIGHT = WITNESS_SCALE_FACTOR * ::GetSerializeSize(CTxOut());
static const size_t MAX_OUTPUTS_PER_BLOCK = MAX_BLOCK_WEIGHT / MIN_TRANSACTION_OUTPUT_WEIGHT;
-const Coin& AccessByTxid(const CCoinsViewCache& view, const uint256& txid)
+const Coin& AccessByTxid(const CCoinsViewCache& view, const Txid& txid)
{
COutPoint iter(txid, 0);
while (iter.n < MAX_OUTPUTS_PER_BLOCK) {
diff --git a/src/coins.h b/src/coins.h
index a6cbb03133..c798cc38ba 100644
--- a/src/coins.h
+++ b/src/coins.h
@@ -145,8 +145,7 @@ using CCoinsMap = std::unordered_map<COutPoint,
SaltedOutpointHasher,
std::equal_to<COutPoint>,
PoolAllocator<std::pair<const COutPoint, CCoinsCacheEntry>,
- sizeof(std::pair<const COutPoint, CCoinsCacheEntry>) + sizeof(void*) * 4,
- alignof(void*)>>;
+ sizeof(std::pair<const COutPoint, CCoinsCacheEntry>) + sizeof(void*) * 4>>;
using CCoinsMapMemoryResource = CCoinsMap::allocator_type::ResourceType;
@@ -364,7 +363,7 @@ void AddCoins(CCoinsViewCache& cache, const CTransaction& tx, int nHeight, bool
//! This function can be quite expensive because in the event of a transaction
//! which is not found in the cache, it can cause up to MAX_OUTPUTS_PER_BLOCK
//! lookups to database, so it should be used with care.
-const Coin& AccessByTxid(const CCoinsViewCache& cache, const uint256& txid);
+const Coin& AccessByTxid(const CCoinsViewCache& cache, const Txid& txid);
/**
* This is a minimally invasive approach to shutdown on LevelDB read errors from the
diff --git a/src/common/bloom.cpp b/src/common/bloom.cpp
index 5c3ad882a1..ca6af90b76 100644
--- a/src/common/bloom.cpp
+++ b/src/common/bloom.cpp
@@ -98,8 +98,8 @@ bool CBloomFilter::IsRelevantAndUpdate(const CTransaction& tx)
// for finding tx when they appear in a block
if (vData.empty()) // zero-size = "match-all" filter
return true;
- const uint256& hash = tx.GetHash();
- if (contains(hash))
+ const Txid& hash = tx.GetHash();
+ if (contains(hash.ToUint256()))
fFound = true;
for (unsigned int i = 0; i < tx.vout.size(); i++)
diff --git a/src/index/txindex.cpp b/src/index/txindex.cpp
index 5d37fd0d8f..4983926e68 100644
--- a/src/index/txindex.cpp
+++ b/src/index/txindex.cpp
@@ -79,7 +79,7 @@ bool TxIndex::FindTx(const uint256& tx_hash, uint256& block_hash, CTransactionRe
return false;
}
- CAutoFile file{m_chainstate->m_blockman.OpenBlockFile(postx, true)};
+ AutoFile file{m_chainstate->m_blockman.OpenBlockFile(postx, true)};
if (file.IsNull()) {
return error("%s: OpenBlockFile failed", __func__);
}
diff --git a/src/kernel/chainparams.cpp b/src/kernel/chainparams.cpp
index 73ba330ff0..56cb3a63a0 100644
--- a/src/kernel/chainparams.cpp
+++ b/src/kernel/chainparams.cpp
@@ -136,7 +136,7 @@ public:
vSeeds.emplace_back("dnsseed.bitcoin.dashjr.org."); // Luke Dashjr
vSeeds.emplace_back("seed.bitcoinstats.com."); // Christian Decker, supports x1 - xf
vSeeds.emplace_back("seed.bitcoin.jonasschnelli.ch."); // Jonas Schnelli, only supports x1, x5, x9, and xd
- vSeeds.emplace_back("seed.btc.petertodd.org."); // Peter Todd, only supports x1, x5, x9, and xd
+ vSeeds.emplace_back("seed.btc.petertodd.net."); // Peter Todd, only supports x1, x5, x9, and xd
vSeeds.emplace_back("seed.bitcoin.sprovoost.nl."); // Sjors Provoost
vSeeds.emplace_back("dnsseed.emzy.de."); // Stephan Oeste
vSeeds.emplace_back("seed.bitcoin.wiz.biz."); // Jason Maurice
@@ -243,7 +243,7 @@ public:
vSeeds.clear();
// nodes with support for servicebits filtering should be at the top
vSeeds.emplace_back("testnet-seed.bitcoin.jonasschnelli.ch.");
- vSeeds.emplace_back("seed.tbtc.petertodd.org.");
+ vSeeds.emplace_back("seed.tbtc.petertodd.net.");
vSeeds.emplace_back("seed.testnet.bitcoin.sprovoost.nl.");
vSeeds.emplace_back("testnet-seed.bluematt.me."); // Just a static list of stable node(s), only supports x9
diff --git a/src/kernel/coinstats.cpp b/src/kernel/coinstats.cpp
index 302638cdbe..ff8a33e804 100644
--- a/src/kernel/coinstats.cpp
+++ b/src/kernel/coinstats.cpp
@@ -89,7 +89,7 @@ static void ApplyCoinHash(std::nullptr_t, const COutPoint& outpoint, const Coin&
//! construction could cause a previously invalid (and potentially malicious)
//! UTXO snapshot to be considered valid.
template <typename T>
-static void ApplyHash(T& hash_obj, const uint256& hash, const std::map<uint32_t, Coin>& outputs)
+static void ApplyHash(T& hash_obj, const Txid& hash, const std::map<uint32_t, Coin>& outputs)
{
for (auto it = outputs.begin(); it != outputs.end(); ++it) {
COutPoint outpoint = COutPoint(hash, it->first);
@@ -118,7 +118,7 @@ static bool ComputeUTXOStats(CCoinsView* view, CCoinsStats& stats, T hash_obj, c
std::unique_ptr<CCoinsViewCursor> pcursor(view->Cursor());
assert(pcursor);
- uint256 prevkey;
+ Txid prevkey;
std::map<uint32_t, Coin> outputs;
while (pcursor->Valid()) {
if (interruption_point) interruption_point();
diff --git a/src/net.cpp b/src/net.cpp
index e1772233b2..dc76fdfb44 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -2714,6 +2714,17 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
continue;
}
+ // Do not make automatic outbound connections to addnode peers, to
+ // not use our limited outbound slots for them and to ensure
+ // addnode connections benefit from their intended protections.
+ if (AddedNodesContain(addr)) {
+ LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "Not making automatic %s%s connection to %s peer selected for manual (addnode) connection%s\n",
+ preferred_net.has_value() ? "network-specific " : "",
+ ConnectionTypeAsString(conn_type), GetNetworkName(addr.GetNetwork()),
+ fLogIPs ? strprintf(": %s", addr.ToStringAddrPort()) : "");
+ continue;
+ }
+
addrConnect = addr;
break;
}
@@ -3453,6 +3464,17 @@ bool CConnman::RemoveAddedNode(const std::string& strNode)
return false;
}
+bool CConnman::AddedNodesContain(const CAddress& addr) const
+{
+ AssertLockNotHeld(m_added_nodes_mutex);
+ const std::string addr_str{addr.ToStringAddr()};
+ const std::string addr_port_str{addr.ToStringAddrPort()};
+ LOCK(m_added_nodes_mutex);
+ return (m_added_node_params.size() < 24 // bound the query to a reasonable limit
+ && std::any_of(m_added_node_params.cbegin(), m_added_node_params.cend(),
+ [&](const auto& p) { return p.m_added_node == addr_str || p.m_added_node == addr_port_str; }));
+}
+
size_t CConnman::GetNodeCount(ConnectionDirection flags) const
{
LOCK(m_nodes_mutex);
diff --git a/src/net.h b/src/net.h
index b673df69b7..4347bf12ca 100644
--- a/src/net.h
+++ b/src/net.h
@@ -1175,6 +1175,7 @@ public:
bool AddNode(const AddedNodeParams& add) EXCLUSIVE_LOCKS_REQUIRED(!m_added_nodes_mutex);
bool RemoveAddedNode(const std::string& node) EXCLUSIVE_LOCKS_REQUIRED(!m_added_nodes_mutex);
+ bool AddedNodesContain(const CAddress& addr) const EXCLUSIVE_LOCKS_REQUIRED(!m_added_nodes_mutex);
std::vector<AddedNodeInfo> GetAddedNodeInfo(bool include_connected) const EXCLUSIVE_LOCKS_REQUIRED(!m_added_nodes_mutex);
/**
diff --git a/src/node/blockstorage.cpp b/src/node/blockstorage.cpp
index c066d1c939..ebc08d7567 100644
--- a/src/node/blockstorage.cpp
+++ b/src/node/blockstorage.cpp
@@ -4,23 +4,32 @@
#include <node/blockstorage.h>
+#include <arith_uint256.h>
#include <chain.h>
-#include <clientversion.h>
+#include <consensus/params.h>
#include <consensus/validation.h>
#include <dbwrapper.h>
#include <flatfile.h>
#include <hash.h>
-#include <kernel/chain.h>
+#include <kernel/blockmanager_opts.h>
#include <kernel/chainparams.h>
#include <kernel/messagestartchars.h>
+#include <kernel/notifications_interface.h>
#include <logging.h>
#include <pow.h>
+#include <primitives/block.h>
+#include <primitives/transaction.h>
#include <reverse_iterator.h>
+#include <serialize.h>
#include <signet.h>
+#include <span.h>
#include <streams.h>
#include <sync.h>
+#include <tinyformat.h>
+#include <uint256.h>
#include <undo.h>
#include <util/batchpriority.h>
+#include <util/check.h>
#include <util/fs.h>
#include <util/signalinterrupt.h>
#include <util/strencodings.h>
@@ -656,7 +665,7 @@ CBlockFileInfo* BlockManager::GetBlockFileInfo(size_t n)
bool BlockManager::UndoWriteToDisk(const CBlockUndo& blockundo, FlatFilePos& pos, const uint256& hashBlock) const
{
// Open history file to append
- CAutoFile fileout{OpenUndoFile(pos)};
+ AutoFile fileout{OpenUndoFile(pos)};
if (fileout.IsNull()) {
return error("%s: OpenUndoFile failed", __func__);
}
@@ -691,7 +700,7 @@ bool BlockManager::UndoReadFromDisk(CBlockUndo& blockundo, const CBlockIndex& in
}
// Open history file to read
- CAutoFile filein{OpenUndoFile(pos, true)};
+ AutoFile filein{OpenUndoFile(pos, true)};
if (filein.IsNull()) {
return error("%s: OpenUndoFile failed", __func__);
}
@@ -810,15 +819,15 @@ FlatFileSeq BlockManager::UndoFileSeq() const
return FlatFileSeq(m_opts.blocks_dir, "rev", UNDOFILE_CHUNK_SIZE);
}
-CAutoFile BlockManager::OpenBlockFile(const FlatFilePos& pos, bool fReadOnly) const
+AutoFile BlockManager::OpenBlockFile(const FlatFilePos& pos, bool fReadOnly) const
{
- return CAutoFile{BlockFileSeq().Open(pos, fReadOnly), CLIENT_VERSION};
+ return AutoFile{BlockFileSeq().Open(pos, fReadOnly)};
}
/** Open an undo file (rev?????.dat) */
-CAutoFile BlockManager::OpenUndoFile(const FlatFilePos& pos, bool fReadOnly) const
+AutoFile BlockManager::OpenUndoFile(const FlatFilePos& pos, bool fReadOnly) const
{
- return CAutoFile{UndoFileSeq().Open(pos, fReadOnly), CLIENT_VERSION};
+ return AutoFile{UndoFileSeq().Open(pos, fReadOnly)};
}
fs::path BlockManager::GetBlockPosFilename(const FlatFilePos& pos) const
@@ -950,7 +959,7 @@ bool BlockManager::FindUndoPos(BlockValidationState& state, int nFile, FlatFileP
bool BlockManager::WriteBlockToDisk(const CBlock& block, FlatFilePos& pos) const
{
// Open history file to append
- CAutoFile fileout{OpenBlockFile(pos)};
+ AutoFile fileout{OpenBlockFile(pos)};
if (fileout.IsNull()) {
return error("WriteBlockToDisk: OpenBlockFile failed");
}
@@ -1016,7 +1025,7 @@ bool BlockManager::ReadBlockFromDisk(CBlock& block, const FlatFilePos& pos) cons
block.SetNull();
// Open history file to read
- CAutoFile filein{OpenBlockFile(pos, true)};
+ AutoFile filein{OpenBlockFile(pos, true)};
if (filein.IsNull()) {
return error("ReadBlockFromDisk: OpenBlockFile failed for %s", pos.ToString());
}
@@ -1059,7 +1068,7 @@ bool BlockManager::ReadRawBlockFromDisk(std::vector<uint8_t>& block, const FlatF
{
FlatFilePos hpos = pos;
hpos.nPos -= 8; // Seek back 8 bytes for meta header
- CAutoFile filein{OpenBlockFile(hpos, true)};
+ AutoFile filein{OpenBlockFile(hpos, true)};
if (filein.IsNull()) {
return error("%s: OpenBlockFile failed for %s", __func__, pos.ToString());
}
@@ -1151,7 +1160,7 @@ void ImportBlocks(ChainstateManager& chainman, std::vector<fs::path> vImportFile
if (!fs::exists(chainman.m_blockman.GetBlockPosFilename(pos))) {
break; // No block files left to reindex
}
- CAutoFile file{chainman.m_blockman.OpenBlockFile(pos, true)};
+ AutoFile file{chainman.m_blockman.OpenBlockFile(pos, true)};
if (file.IsNull()) {
break; // This error is logged in OpenBlockFile
}
@@ -1172,7 +1181,7 @@ void ImportBlocks(ChainstateManager& chainman, std::vector<fs::path> vImportFile
// -loadblock=
for (const fs::path& path : vImportFiles) {
- CAutoFile file{fsbridge::fopen(path, "rb"), CLIENT_VERSION};
+ AutoFile file{fsbridge::fopen(path, "rb")};
if (!file.IsNull()) {
LogPrintf("Importing blocks file %s...\n", fs::PathToString(path));
chainman.LoadExternalBlockFile(file);
diff --git a/src/node/blockstorage.h b/src/node/blockstorage.h
index ba44d31581..d540406ae5 100644
--- a/src/node/blockstorage.h
+++ b/src/node/blockstorage.h
@@ -8,21 +8,26 @@
#include <attributes.h>
#include <chain.h>
#include <dbwrapper.h>
+#include <flatfile.h>
#include <kernel/blockmanager_opts.h>
-#include <kernel/chain.h>
#include <kernel/chainparams.h>
#include <kernel/cs_main.h>
#include <kernel/messagestartchars.h>
+#include <primitives/block.h>
+#include <streams.h>
#include <sync.h>
+#include <uint256.h>
#include <util/fs.h>
#include <util/hasher.h>
+#include <array>
#include <atomic>
#include <cstdint>
#include <functional>
#include <limits>
#include <map>
#include <memory>
+#include <optional>
#include <set>
#include <string>
#include <unordered_map>
@@ -30,14 +35,9 @@
#include <vector>
class BlockValidationState;
-class CAutoFile;
-class CBlock;
class CBlockUndo;
-class CChainParams;
class Chainstate;
class ChainstateManager;
-struct CCheckpointData;
-struct FlatFilePos;
namespace Consensus {
struct Params;
}
@@ -162,7 +162,7 @@ private:
FlatFileSeq BlockFileSeq() const;
FlatFileSeq UndoFileSeq() const;
- CAutoFile OpenUndoFile(const FlatFilePos& pos, bool fReadOnly = false) const;
+ AutoFile OpenUndoFile(const FlatFilePos& pos, bool fReadOnly = false) const;
bool WriteBlockToDisk(const CBlock& block, FlatFilePos& pos) const;
bool UndoWriteToDisk(const CBlockUndo& blockundo, FlatFilePos& pos, const uint256& hashBlock) const;
@@ -350,7 +350,7 @@ public:
void UpdatePruneLock(const std::string& name, const PruneLockInfo& lock_info) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
/** Open a block file (blk?????.dat) */
- CAutoFile OpenBlockFile(const FlatFilePos& pos, bool fReadOnly = false) const;
+ AutoFile OpenBlockFile(const FlatFilePos& pos, bool fReadOnly = false) const;
/** Translation to a filesystem path */
fs::path GetBlockPosFilename(const FlatFilePos& pos) const;
diff --git a/src/node/transaction.cpp b/src/node/transaction.cpp
index 026c8084dd..e8ab2326c1 100644
--- a/src/node/transaction.cpp
+++ b/src/node/transaction.cpp
@@ -40,7 +40,7 @@ TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef t
assert(node.peerman);
std::promise<void> promise;
- uint256 txid = tx->GetHash();
+ Txid txid = tx->GetHash();
uint256 wtxid = tx->GetWitnessHash();
bool callback_set = false;
diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp
index 82fb59d349..002c922c0d 100644
--- a/src/primitives/transaction.cpp
+++ b/src/primitives/transaction.cpp
@@ -29,7 +29,7 @@ CTxIn::CTxIn(COutPoint prevoutIn, CScript scriptSigIn, uint32_t nSequenceIn)
nSequence = nSequenceIn;
}
-CTxIn::CTxIn(uint256 hashPrevTx, uint32_t nOut, CScript scriptSigIn, uint32_t nSequenceIn)
+CTxIn::CTxIn(Txid hashPrevTx, uint32_t nOut, CScript scriptSigIn, uint32_t nSequenceIn)
{
prevout = COutPoint(hashPrevTx, nOut);
scriptSig = scriptSigIn;
diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h
index ad190f7d7f..e0c0c860c6 100644
--- a/src/primitives/transaction.h
+++ b/src/primitives/transaction.h
@@ -28,13 +28,13 @@
class COutPoint
{
public:
- uint256 hash;
+ Txid hash;
uint32_t n;
static constexpr uint32_t NULL_INDEX = std::numeric_limits<uint32_t>::max();
COutPoint(): n(NULL_INDEX) { }
- COutPoint(const uint256& hashIn, uint32_t nIn): hash(hashIn), n(nIn) { }
+ COutPoint(const Txid& hashIn, uint32_t nIn): hash(hashIn), n(nIn) { }
SERIALIZE_METHODS(COutPoint, obj) { READWRITE(obj.hash, obj.n); }
@@ -43,8 +43,7 @@ public:
friend bool operator<(const COutPoint& a, const COutPoint& b)
{
- int cmp = a.hash.Compare(b.hash);
- return cmp < 0 || (cmp == 0 && a.n < b.n);
+ return std::tie(a.hash, a.n) < std::tie(b.hash, b.n);
}
friend bool operator==(const COutPoint& a, const COutPoint& b)
@@ -125,7 +124,7 @@ public:
}
explicit CTxIn(COutPoint prevoutIn, CScript scriptSigIn=CScript(), uint32_t nSequenceIn=SEQUENCE_FINAL);
- CTxIn(uint256 hashPrevTx, uint32_t nOut, CScript scriptSigIn=CScript(), uint32_t nSequenceIn=SEQUENCE_FINAL);
+ CTxIn(Txid hashPrevTx, uint32_t nOut, CScript scriptSigIn=CScript(), uint32_t nSequenceIn=SEQUENCE_FINAL);
SERIALIZE_METHODS(CTxIn, obj) { READWRITE(obj.prevout, obj.scriptSig, obj.nSequence); }
diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp
index 70aa9bc8da..9e49fd87fb 100644
--- a/src/qt/coincontroldialog.cpp
+++ b/src/qt/coincontroldialog.cpp
@@ -181,7 +181,7 @@ void CoinControlDialog::showMenu(const QPoint &point)
if (item->data(COLUMN_ADDRESS, TxHashRole).toString().length() == 64) // transaction hash is 64 characters (this means it is a child node, so it is not a parent node in tree mode)
{
m_copy_transaction_outpoint_action->setEnabled(true);
- if (model->wallet().isLockedCoin(COutPoint(uint256S(item->data(COLUMN_ADDRESS, TxHashRole).toString().toStdString()), item->data(COLUMN_ADDRESS, VOutRole).toUInt())))
+ if (model->wallet().isLockedCoin(COutPoint(TxidFromString(item->data(COLUMN_ADDRESS, TxHashRole).toString().toStdString()), item->data(COLUMN_ADDRESS, VOutRole).toUInt())))
{
lockAction->setEnabled(false);
unlockAction->setEnabled(true);
@@ -244,7 +244,7 @@ void CoinControlDialog::lockCoin()
if (contextMenuItem->checkState(COLUMN_CHECKBOX) == Qt::Checked)
contextMenuItem->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked);
- COutPoint outpt(uint256S(contextMenuItem->data(COLUMN_ADDRESS, TxHashRole).toString().toStdString()), contextMenuItem->data(COLUMN_ADDRESS, VOutRole).toUInt());
+ COutPoint outpt(TxidFromString(contextMenuItem->data(COLUMN_ADDRESS, TxHashRole).toString().toStdString()), contextMenuItem->data(COLUMN_ADDRESS, VOutRole).toUInt());
model->wallet().lockCoin(outpt, /* write_to_db = */ true);
contextMenuItem->setDisabled(true);
contextMenuItem->setIcon(COLUMN_CHECKBOX, platformStyle->SingleColorIcon(":/icons/lock_closed"));
@@ -254,7 +254,7 @@ void CoinControlDialog::lockCoin()
// context menu action: unlock coin
void CoinControlDialog::unlockCoin()
{
- COutPoint outpt(uint256S(contextMenuItem->data(COLUMN_ADDRESS, TxHashRole).toString().toStdString()), contextMenuItem->data(COLUMN_ADDRESS, VOutRole).toUInt());
+ COutPoint outpt(TxidFromString(contextMenuItem->data(COLUMN_ADDRESS, TxHashRole).toString().toStdString()), contextMenuItem->data(COLUMN_ADDRESS, VOutRole).toUInt());
model->wallet().unlockCoin(outpt);
contextMenuItem->setDisabled(false);
contextMenuItem->setIcon(COLUMN_CHECKBOX, QIcon());
@@ -346,7 +346,7 @@ void CoinControlDialog::viewItemChanged(QTreeWidgetItem* item, int column)
{
if (column == COLUMN_CHECKBOX && item->data(COLUMN_ADDRESS, TxHashRole).toString().length() == 64) // transaction hash is 64 characters (this means it is a child node, so it is not a parent node in tree mode)
{
- COutPoint outpt(uint256S(item->data(COLUMN_ADDRESS, TxHashRole).toString().toStdString()), item->data(COLUMN_ADDRESS, VOutRole).toUInt());
+ COutPoint outpt(TxidFromString(item->data(COLUMN_ADDRESS, TxHashRole).toString().toStdString()), item->data(COLUMN_ADDRESS, VOutRole).toUInt());
if (item->checkState(COLUMN_CHECKBOX) == Qt::Unchecked)
m_coin_control.UnSelect(outpt);
diff --git a/src/rest.cpp b/src/rest.cpp
index 3894b5141d..bb54e780b2 100644
--- a/src/rest.cpp
+++ b/src/rest.cpp
@@ -789,7 +789,6 @@ static bool rest_getutxos(const std::any& context, HTTPRequest* req, const std::
for (size_t i = (fCheckMemPool) ? 1 : 0; i < uriParts.size(); i++)
{
- uint256 txid;
int32_t nOutput;
std::string strTxid = uriParts[i].substr(0, uriParts[i].find('-'));
std::string strOutput = uriParts[i].substr(uriParts[i].find('-')+1);
@@ -797,8 +796,7 @@ static bool rest_getutxos(const std::any& context, HTTPRequest* req, const std::
if (!ParseInt32(strOutput, &nOutput) || !IsHex(strTxid))
return RESTERR(req, HTTP_BAD_REQUEST, "Parse error");
- txid.SetHex(strTxid);
- vOutPoints.emplace_back(txid, (uint32_t)nOutput);
+ vOutPoints.emplace_back(TxidFromString(strTxid), (uint32_t)nOutput);
}
if (vOutPoints.size() > 0)
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 6a3aa397d9..be6a8c47fd 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -1057,7 +1057,7 @@ static RPCHelpMan gettxout()
UniValue ret(UniValue::VOBJ);
- uint256 hash(ParseHashV(request.params[0], "txid"));
+ auto hash{Txid::FromUint256(ParseHashV(request.params[0], "txid"))};
COutPoint out{hash, request.params[1].getInt<uint32_t>()};
bool fMempool = true;
if (!request.params[2].isNull())
@@ -2014,7 +2014,7 @@ bool FindScriptPubKey(std::atomic<int>& scan_progress, const std::atomic<bool>&
}
if (count % 256 == 0) {
// update progress reference every 256 item
- uint32_t high = 0x100 * *key.hash.begin() + *(key.hash.begin() + 1);
+ uint32_t high = 0x100 * *UCharCast(key.hash.begin()) + *(UCharCast(key.hash.begin()) + 1);
scan_progress = (int)(high * 100.0 / 65536.0 + 0.5);
}
if (needles.count(coin.out.scriptPubKey)) {
diff --git a/src/rpc/mempool.cpp b/src/rpc/mempool.cpp
index bf60eae433..6cbc96c5ec 100644
--- a/src/rpc/mempool.cpp
+++ b/src/rpc/mempool.cpp
@@ -633,7 +633,7 @@ static RPCHelpMan gettxspendingprevout()
{"vout", UniValueType(UniValue::VNUM)},
}, /*fAllowNull=*/false, /*fStrict=*/true);
- const uint256 txid(ParseHashO(o, "txid"));
+ const Txid txid = Txid::FromUint256(ParseHashO(o, "txid"));
const int nOutput{o.find_value("vout").getInt<int>()};
if (nOutput < 0) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout cannot be negative");
diff --git a/src/rpc/rawtransaction_util.cpp b/src/rpc/rawtransaction_util.cpp
index 3a6fa39e4d..c471986a44 100644
--- a/src/rpc/rawtransaction_util.cpp
+++ b/src/rpc/rawtransaction_util.cpp
@@ -34,7 +34,7 @@ void AddInputs(CMutableTransaction& rawTx, const UniValue& inputs_in, std::optio
const UniValue& input = inputs[idx];
const UniValue& o = input.get_obj();
- uint256 txid = ParseHashO(o, "txid");
+ Txid txid = Txid::FromUint256(ParseHashO(o, "txid"));
const UniValue& vout_v = o.find_value("vout");
if (!vout_v.isNum())
@@ -185,7 +185,7 @@ void ParsePrevouts(const UniValue& prevTxsUnival, FillableSigningProvider* keyst
{"scriptPubKey", UniValueType(UniValue::VSTR)},
});
- uint256 txid = ParseHashO(prevOut, "txid");
+ Txid txid = Txid::FromUint256(ParseHashO(prevOut, "txid"));
int nOut = prevOut.find_value("vout").getInt<int>();
if (nOut < 0) {
diff --git a/src/rpc/txoutproof.cpp b/src/rpc/txoutproof.cpp
index d74959cecc..46a22e9338 100644
--- a/src/rpc/txoutproof.cpp
+++ b/src/rpc/txoutproof.cpp
@@ -69,7 +69,7 @@ static RPCHelpMan gettxoutproof()
// Loop through txids and try to find which block they're in. Exit loop once a block is found.
for (const auto& tx : setTxids) {
- const Coin& coin = AccessByTxid(active_chainstate.CoinsTip(), tx);
+ const Coin& coin = AccessByTxid(active_chainstate.CoinsTip(), Txid::FromUint256(tx));
if (!coin.IsSpent()) {
pblockindex = active_chainstate.m_chain[coin.nHeight];
break;
diff --git a/src/script/interpreter.h b/src/script/interpreter.h
index ac1013302d..836c2e7982 100644
--- a/src/script/interpreter.h
+++ b/src/script/interpreter.h
@@ -6,21 +6,23 @@
#ifndef BITCOIN_SCRIPT_INTERPRETER_H
#define BITCOIN_SCRIPT_INTERPRETER_H
+#include <consensus/amount.h>
#include <hash.h>
-#include <script/script_error.h>
-#include <span.h>
#include <primitives/transaction.h>
+#include <script/script_error.h> // IWYU pragma: export
+#include <span.h>
+#include <uint256.h>
+#include <cstddef>
+#include <cstdint>
#include <optional>
#include <vector>
-#include <stdint.h>
class CPubKey;
-class XOnlyPubKey;
class CScript;
-class CTransaction;
-class CTxOut;
-class uint256;
+class CScriptNum;
+class XOnlyPubKey;
+struct CScriptWitness;
/** Signature hash types/flags */
enum
diff --git a/src/streams.h b/src/streams.h
index 88a5f3da54..5fec289e34 100644
--- a/src/streams.h
+++ b/src/streams.h
@@ -498,31 +498,7 @@ public:
}
};
-class CAutoFile : public AutoFile
-{
-private:
- const int nVersion;
-
-public:
- explicit CAutoFile(std::FILE* file, int version, std::vector<std::byte> data_xor = {}) : AutoFile{file, std::move(data_xor)}, nVersion{version} {}
- int GetVersion() const { return nVersion; }
-
- template<typename T>
- CAutoFile& operator<<(const T& obj)
- {
- ::Serialize(*this, obj);
- return (*this);
- }
-
- template<typename T>
- CAutoFile& operator>>(T&& obj)
- {
- ::Unserialize(*this, obj);
- return (*this);
- }
-};
-
-/** Wrapper around a CAutoFile& that implements a ring buffer to
+/** Wrapper around an AutoFile& that implements a ring buffer to
* deserialize from. It guarantees the ability to rewind a given number of bytes.
*
* Will automatically close the file when it goes out of scope if not null.
@@ -531,7 +507,7 @@ public:
class BufferedFile
{
private:
- CAutoFile& m_src;
+ AutoFile& m_src;
uint64_t nSrcPos{0}; //!< how many bytes have been read from source
uint64_t m_read_pos{0}; //!< how many bytes have been read from this
uint64_t nReadLimit; //!< up to which position we're allowed to read
@@ -578,15 +554,13 @@ private:
}
public:
- BufferedFile(CAutoFile& file, uint64_t nBufSize, uint64_t nRewindIn)
+ BufferedFile(AutoFile& file, uint64_t nBufSize, uint64_t nRewindIn)
: m_src{file}, nReadLimit{std::numeric_limits<uint64_t>::max()}, nRewind{nRewindIn}, vchBuf(nBufSize, std::byte{0})
{
if (nRewindIn >= nBufSize)
throw std::ios_base::failure("Rewind limit must be less than buffer size");
}
- int GetVersion() const { return m_src.GetVersion(); }
-
//! check whether we're at the end of the source file
bool eof() const {
return m_read_pos == nSrcPos && m_src.feof();
diff --git a/src/support/allocators/pool.h b/src/support/allocators/pool.h
index c8e70ebacf..873e260b65 100644
--- a/src/support/allocators/pool.h
+++ b/src/support/allocators/pool.h
@@ -272,7 +272,7 @@ public:
/**
* Forwards all allocations/deallocations to the PoolResource.
*/
-template <class T, std::size_t MAX_BLOCK_SIZE_BYTES, std::size_t ALIGN_BYTES>
+template <class T, std::size_t MAX_BLOCK_SIZE_BYTES, std::size_t ALIGN_BYTES = alignof(T)>
class PoolAllocator
{
PoolResource<MAX_BLOCK_SIZE_BYTES, ALIGN_BYTES>* m_resource;
diff --git a/src/test/blockencodings_tests.cpp b/src/test/blockencodings_tests.cpp
index e4ef019daf..7968966303 100644
--- a/src/test/blockencodings_tests.cpp
+++ b/src/test/blockencodings_tests.cpp
@@ -32,13 +32,13 @@ static CBlock BuildBlockTestCase() {
block.hashPrevBlock = InsecureRand256();
block.nBits = 0x207fffff;
- tx.vin[0].prevout.hash = InsecureRand256();
+ tx.vin[0].prevout.hash = Txid::FromUint256(InsecureRand256());
tx.vin[0].prevout.n = 0;
block.vtx[1] = MakeTransactionRef(tx);
tx.vin.resize(10);
for (size_t i = 0; i < tx.vin.size(); i++) {
- tx.vin[i].prevout.hash = InsecureRand256();
+ tx.vin[i].prevout.hash = Txid::FromUint256(InsecureRand256());
tx.vin[i].prevout.n = 0;
}
block.vtx[2] = MakeTransactionRef(tx);
diff --git a/src/test/bloom_tests.cpp b/src/test/bloom_tests.cpp
index 23cbe921ba..daa5a56a14 100644
--- a/src/test/bloom_tests.cpp
+++ b/src/test/bloom_tests.cpp
@@ -136,11 +136,11 @@ BOOST_AUTO_TEST_CASE(bloom_match)
BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match output address");
filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
- filter.insert(COutPoint(uint256S("0x90c122d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), 0));
+ filter.insert(COutPoint(TxidFromString("0x90c122d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), 0));
BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match COutPoint");
filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
- COutPoint prevOutPoint(uint256S("0x90c122d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), 0);
+ COutPoint prevOutPoint(TxidFromString("0x90c122d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), 0);
{
std::vector<unsigned char> data(32 + sizeof(unsigned int));
memcpy(data.data(), prevOutPoint.hash.begin(), 32);
@@ -158,11 +158,11 @@ BOOST_AUTO_TEST_CASE(bloom_match)
BOOST_CHECK_MESSAGE(!filter.IsRelevantAndUpdate(tx), "Simple Bloom filter matched random address");
filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
- filter.insert(COutPoint(uint256S("0x90c122d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), 1));
+ filter.insert(COutPoint(TxidFromString("0x90c122d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), 1));
BOOST_CHECK_MESSAGE(!filter.IsRelevantAndUpdate(tx), "Simple Bloom filter matched COutPoint for an output we didn't care about");
filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL);
- filter.insert(COutPoint(uint256S("0x000000d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), 0));
+ filter.insert(COutPoint(TxidFromString("0x000000d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), 0));
BOOST_CHECK_MESSAGE(!filter.IsRelevantAndUpdate(tx), "Simple Bloom filter matched COutPoint for an output we didn't care about");
}
@@ -414,9 +414,9 @@ BOOST_AUTO_TEST_CASE(merkle_block_4_test_p2pubkey_only)
BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash());
// We should match the generation outpoint
- BOOST_CHECK(filter.contains(COutPoint(uint256S("0x147caa76786596590baa4e98f5d9f48b86c7765e489f7a6ff3360fe5c674360b"), 0)));
+ BOOST_CHECK(filter.contains(COutPoint(TxidFromString("0x147caa76786596590baa4e98f5d9f48b86c7765e489f7a6ff3360fe5c674360b"), 0)));
// ... but not the 4th transaction's output (its not pay-2-pubkey)
- BOOST_CHECK(!filter.contains(COutPoint(uint256S("0x02981fa052f0481dbc5868f4fc2166035a10f27a03cfd2de67326471df5bc041"), 0)));
+ BOOST_CHECK(!filter.contains(COutPoint(TxidFromString("0x02981fa052f0481dbc5868f4fc2166035a10f27a03cfd2de67326471df5bc041"), 0)));
}
BOOST_AUTO_TEST_CASE(merkle_block_4_test_update_none)
@@ -437,8 +437,8 @@ BOOST_AUTO_TEST_CASE(merkle_block_4_test_update_none)
BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash());
// We shouldn't match any outpoints (UPDATE_NONE)
- BOOST_CHECK(!filter.contains(COutPoint(uint256S("0x147caa76786596590baa4e98f5d9f48b86c7765e489f7a6ff3360fe5c674360b"), 0)));
- BOOST_CHECK(!filter.contains(COutPoint(uint256S("0x02981fa052f0481dbc5868f4fc2166035a10f27a03cfd2de67326471df5bc041"), 0)));
+ BOOST_CHECK(!filter.contains(COutPoint(TxidFromString("0x147caa76786596590baa4e98f5d9f48b86c7765e489f7a6ff3360fe5c674360b"), 0)));
+ BOOST_CHECK(!filter.contains(COutPoint(TxidFromString("0x02981fa052f0481dbc5868f4fc2166035a10f27a03cfd2de67326471df5bc041"), 0)));
}
static std::vector<unsigned char> RandomData()
diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp
index 12dc4d1ccc..b6d3e7d567 100644
--- a/src/test/coins_tests.cpp
+++ b/src/test/coins_tests.cpp
@@ -137,16 +137,16 @@ void SimulationTest(CCoinsView* base, bool fake_best_block)
stack.push_back(std::make_unique<CCoinsViewCacheTest>(base)); // Start with one cache.
// Use a limited set of random transaction ids, so we do test overwriting entries.
- std::vector<uint256> txids;
+ std::vector<Txid> txids;
txids.resize(NUM_SIMULATION_ITERATIONS / 8);
for (unsigned int i = 0; i < txids.size(); i++) {
- txids[i] = InsecureRand256();
+ txids[i] = Txid::FromUint256(InsecureRand256());
}
for (unsigned int i = 0; i < NUM_SIMULATION_ITERATIONS; i++) {
// Do a random modification.
{
- uint256 txid = txids[InsecureRandRange(txids.size())]; // txid we're going to modify in this iteration.
+ auto txid = txids[InsecureRandRange(txids.size())]; // txid we're going to modify in this iteration.
Coin& coin = result[COutPoint(txid, 0)];
// Determine whether to test HaveCoin before or after Access* (or both). As these functions
@@ -290,7 +290,7 @@ UtxoData utxoData;
UtxoData::iterator FindRandomFrom(const std::set<COutPoint> &utxoSet) {
assert(utxoSet.size());
- auto utxoSetIt = utxoSet.lower_bound(COutPoint(InsecureRand256(), 0));
+ auto utxoSetIt = utxoSet.lower_bound(COutPoint(Txid::FromUint256(InsecureRand256()), 0));
if (utxoSetIt == utxoSet.end()) {
utxoSetIt = utxoSet.begin();
}
@@ -926,7 +926,7 @@ void TestFlushBehavior(
}
};
- uint256 txid = InsecureRand256();
+ Txid txid = Txid::FromUint256(InsecureRand256());
COutPoint outp = COutPoint(txid, 0);
Coin coin = MakeCoin();
// Ensure the coins views haven't seen this coin before.
@@ -1017,7 +1017,7 @@ void TestFlushBehavior(
// --- Bonus check: ensure that a coin added to the base view via one cache
// can be spent by another cache which has never seen it.
//
- txid = InsecureRand256();
+ txid = Txid::FromUint256(InsecureRand256());
outp = COutPoint(txid, 0);
coin = MakeCoin();
BOOST_CHECK(!base.HaveCoin(outp));
@@ -1040,7 +1040,7 @@ void TestFlushBehavior(
// --- Bonus check 2: ensure that a FRESH, spent coin is deleted by Sync()
//
- txid = InsecureRand256();
+ txid = Txid::FromUint256(InsecureRand256());
outp = COutPoint(txid, 0);
coin = MakeCoin();
CAmount coin_val = coin.out.nValue;
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
diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp
index 96acbea317..342d2514ed 100644
--- a/src/test/miner_tests.cpp
+++ b/src/test/miner_tests.cpp
@@ -118,19 +118,19 @@ void MinerTestingSetup::TestPackageSelection(const CScript& scriptPubKey, const
tx.vout.resize(1);
tx.vout[0].nValue = 5000000000LL - 1000;
// This tx has a low fee: 1000 satoshis
- uint256 hashParentTx = tx.GetHash(); // save this txid for later use
+ Txid hashParentTx = tx.GetHash(); // save this txid for later use
tx_mempool.addUnchecked(entry.Fee(1000).Time(Now<NodeSeconds>()).SpendsCoinbase(true).FromTx(tx));
// This tx has a medium fee: 10000 satoshis
tx.vin[0].prevout.hash = txFirst[1]->GetHash();
tx.vout[0].nValue = 5000000000LL - 10000;
- uint256 hashMediumFeeTx = tx.GetHash();
+ Txid hashMediumFeeTx = tx.GetHash();
tx_mempool.addUnchecked(entry.Fee(10000).Time(Now<NodeSeconds>()).SpendsCoinbase(true).FromTx(tx));
// This tx has a high fee, but depends on the first transaction
tx.vin[0].prevout.hash = hashParentTx;
tx.vout[0].nValue = 5000000000LL - 1000 - 50000; // 50k satoshi fee
- uint256 hashHighFeeTx = tx.GetHash();
+ Txid hashHighFeeTx = tx.GetHash();
tx_mempool.addUnchecked(entry.Fee(50000).Time(Now<NodeSeconds>()).SpendsCoinbase(false).FromTx(tx));
std::unique_ptr<CBlockTemplate> pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey);
@@ -142,7 +142,7 @@ void MinerTestingSetup::TestPackageSelection(const CScript& scriptPubKey, const
// Test that a package below the block min tx fee doesn't get included
tx.vin[0].prevout.hash = hashHighFeeTx;
tx.vout[0].nValue = 5000000000LL - 1000 - 50000; // 0 fee
- uint256 hashFreeTx = tx.GetHash();
+ Txid hashFreeTx = tx.GetHash();
tx_mempool.addUnchecked(entry.Fee(0).FromTx(tx));
size_t freeTxSize = ::GetSerializeSize(TX_WITH_WITNESS(tx));
@@ -152,7 +152,7 @@ void MinerTestingSetup::TestPackageSelection(const CScript& scriptPubKey, const
tx.vin[0].prevout.hash = hashFreeTx;
tx.vout[0].nValue = 5000000000LL - 1000 - 50000 - feeToUse;
- uint256 hashLowFeeTx = tx.GetHash();
+ Txid hashLowFeeTx = tx.GetHash();
tx_mempool.addUnchecked(entry.Fee(feeToUse).FromTx(tx));
pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey);
// Verify that the free tx and the low fee tx didn't get selected
@@ -180,7 +180,7 @@ void MinerTestingSetup::TestPackageSelection(const CScript& scriptPubKey, const
tx.vout.resize(2);
tx.vout[0].nValue = 5000000000LL - 100000000;
tx.vout[1].nValue = 100000000; // 1BTC output
- uint256 hashFreeTx2 = tx.GetHash();
+ Txid hashFreeTx2 = tx.GetHash();
tx_mempool.addUnchecked(entry.Fee(0).SpendsCoinbase(true).FromTx(tx));
// This tx can't be mined by itself
@@ -188,7 +188,7 @@ void MinerTestingSetup::TestPackageSelection(const CScript& scriptPubKey, const
tx.vout.resize(1);
feeToUse = blockMinFeeRate.GetFee(freeTxSize);
tx.vout[0].nValue = 5000000000LL - 100000000 - feeToUse;
- uint256 hashLowFeeTx2 = tx.GetHash();
+ Txid hashLowFeeTx2 = tx.GetHash();
tx_mempool.addUnchecked(entry.Fee(feeToUse).SpendsCoinbase(false).FromTx(tx));
pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey);
@@ -210,7 +210,7 @@ void MinerTestingSetup::TestPackageSelection(const CScript& scriptPubKey, const
void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst, int baseheight)
{
- uint256 hash;
+ Txid hash;
CMutableTransaction tx;
TestMemPoolEntryHelper entry;
entry.nFee = 11;
@@ -545,20 +545,20 @@ void MinerTestingSetup::TestPrioritisedMining(const CScript& scriptPubKey, const
tx.vin[0].prevout.n = 0;
tx.vout[0].nValue = 5000000000LL - 1000;
// This tx has a low fee: 1000 satoshis
- uint256 hashParentTx = tx.GetHash(); // save this txid for later use
+ Txid hashParentTx = tx.GetHash(); // save this txid for later use
tx_mempool.addUnchecked(entry.Fee(1000).Time(Now<NodeSeconds>()).SpendsCoinbase(true).FromTx(tx));
// This tx has a medium fee: 10000 satoshis
tx.vin[0].prevout.hash = txFirst[2]->GetHash();
tx.vout[0].nValue = 5000000000LL - 10000;
- uint256 hashMediumFeeTx = tx.GetHash();
+ Txid hashMediumFeeTx = tx.GetHash();
tx_mempool.addUnchecked(entry.Fee(10000).Time(Now<NodeSeconds>()).SpendsCoinbase(true).FromTx(tx));
tx_mempool.PrioritiseTransaction(hashMediumFeeTx, -5 * COIN);
// This tx also has a low fee, but is prioritised
tx.vin[0].prevout.hash = hashParentTx;
tx.vout[0].nValue = 5000000000LL - 1000 - 1000; // 1000 satoshi fee
- uint256 hashPrioritsedChild = tx.GetHash();
+ Txid hashPrioritsedChild = tx.GetHash();
tx_mempool.addUnchecked(entry.Fee(1000).Time(Now<NodeSeconds>()).SpendsCoinbase(false).FromTx(tx));
tx_mempool.PrioritiseTransaction(hashPrioritsedChild, 2 * COIN);
@@ -570,19 +570,19 @@ void MinerTestingSetup::TestPrioritisedMining(const CScript& scriptPubKey, const
// When FreeChild is included, FreeChild's prioritisation should also not be included.
tx.vin[0].prevout.hash = txFirst[3]->GetHash();
tx.vout[0].nValue = 5000000000LL; // 0 fee
- uint256 hashFreeParent = tx.GetHash();
+ Txid hashFreeParent = tx.GetHash();
tx_mempool.addUnchecked(entry.Fee(0).SpendsCoinbase(true).FromTx(tx));
tx_mempool.PrioritiseTransaction(hashFreeParent, 10 * COIN);
tx.vin[0].prevout.hash = hashFreeParent;
tx.vout[0].nValue = 5000000000LL; // 0 fee
- uint256 hashFreeChild = tx.GetHash();
+ Txid hashFreeChild = tx.GetHash();
tx_mempool.addUnchecked(entry.Fee(0).SpendsCoinbase(false).FromTx(tx));
tx_mempool.PrioritiseTransaction(hashFreeChild, 1 * COIN);
tx.vin[0].prevout.hash = hashFreeChild;
tx.vout[0].nValue = 5000000000LL; // 0 fee
- uint256 hashFreeGrandchild = tx.GetHash();
+ Txid hashFreeGrandchild = tx.GetHash();
tx_mempool.addUnchecked(entry.Fee(0).SpendsCoinbase(false).FromTx(tx));
auto pblocktemplate = AssemblerForTest(tx_mempool).CreateNewBlock(scriptPubKey);
diff --git a/src/test/miniminer_tests.cpp b/src/test/miniminer_tests.cpp
index 311e402e3e..5b007997b9 100644
--- a/src/test/miniminer_tests.cpp
+++ b/src/test/miniminer_tests.cpp
@@ -190,7 +190,7 @@ BOOST_FIXTURE_TEST_CASE(miniminer_1p1c, TestChain100Setup)
CFeeRate(23330), CFeeRate(50000), CFeeRate(5*CENT)});
// All nonexistent entries have a bumpfee of zero, regardless of feerate
- std::vector<COutPoint> nonexistent_outpoints({ COutPoint{GetRandHash(), 0}, COutPoint{GetRandHash(), 3} });
+ std::vector<COutPoint> nonexistent_outpoints({ COutPoint{Txid::FromUint256(GetRandHash()), 0}, COutPoint{Txid::FromUint256(GetRandHash()), 3} });
for (const auto& outpoint : nonexistent_outpoints) BOOST_CHECK(!pool.isSpent(outpoint));
for (const auto& feerate : various_normal_feerates) {
node::MiniMiner mini_miner(pool, nonexistent_outpoints);
@@ -590,9 +590,17 @@ BOOST_FIXTURE_TEST_CASE(calculate_cluster, TestChain100Setup)
CTxMemPool& pool = *Assert(m_node.mempool);
LOCK2(cs_main, pool.cs);
+ // TODO this can be removed once the mempool interface uses Txid, Wtxid
+ auto convert_to_uint256_vec = [](const std::vector<Txid>& vec) -> std::vector<uint256> {
+ std::vector<uint256> out;
+ std::transform(vec.begin(), vec.end(), std::back_inserter(out),
+ [](const Txid& txid) { return txid.ToUint256(); });
+ return out;
+ };
+
// Add chain of size 500
TestMemPoolEntryHelper entry;
- std::vector<uint256> chain_txids;
+ std::vector<Txid> chain_txids;
auto& lasttx = m_coinbase_txns[0];
for (auto i{0}; i < 500; ++i) {
const auto tx = make_tx({COutPoint{lasttx->GetHash(), 0}}, /*num_outputs=*/1);
@@ -603,7 +611,7 @@ BOOST_FIXTURE_TEST_CASE(calculate_cluster, TestChain100Setup)
const auto cluster_500tx = pool.GatherClusters({lasttx->GetHash()});
CTxMemPool::setEntries cluster_500tx_set{cluster_500tx.begin(), cluster_500tx.end()};
BOOST_CHECK_EQUAL(cluster_500tx.size(), cluster_500tx_set.size());
- const auto vec_iters_500 = pool.GetIterVec(chain_txids);
+ const auto vec_iters_500 = pool.GetIterVec(convert_to_uint256_vec(chain_txids));
for (const auto& iter : vec_iters_500) BOOST_CHECK(cluster_500tx_set.count(iter));
// GatherClusters stops at 500 transactions.
@@ -618,9 +626,9 @@ BOOST_FIXTURE_TEST_CASE(calculate_cluster, TestChain100Setup)
* txc0 txc1 txc2 ... txc48
* Note that each transaction's ancestor size is 1 or 3, and each descendant size is 1, 2 or 3.
* However, all of these transactions are in the same cluster. */
- std::vector<uint256> zigzag_txids;
+ std::vector<Txid> zigzag_txids;
for (auto p{0}; p < 50; ++p) {
- const auto txp = make_tx({COutPoint{GetRandHash(), 0}}, /*num_outputs=*/2);
+ const auto txp = make_tx({COutPoint{Txid::FromUint256(GetRandHash()), 0}}, /*num_outputs=*/2);
pool.addUnchecked(entry.Fee(CENT).FromTx(txp));
zigzag_txids.push_back(txp->GetHash());
}
@@ -629,7 +637,7 @@ BOOST_FIXTURE_TEST_CASE(calculate_cluster, TestChain100Setup)
pool.addUnchecked(entry.Fee(CENT).FromTx(txc));
zigzag_txids.push_back(txc->GetHash());
}
- const auto vec_iters_zigzag = pool.GetIterVec(zigzag_txids);
+ const auto vec_iters_zigzag = pool.GetIterVec(convert_to_uint256_vec(zigzag_txids));
// It doesn't matter which tx we calculate cluster for, everybody is in it.
const std::vector<size_t> indices{0, 22, 72, zigzag_txids.size() - 1};
for (const auto index : indices) {
diff --git a/src/test/net_peer_connection_tests.cpp b/src/test/net_peer_connection_tests.cpp
index 3d3f296d82..0300c17e40 100644
--- a/src/test/net_peer_connection_tests.cpp
+++ b/src/test/net_peer_connection_tests.cpp
@@ -116,12 +116,22 @@ BOOST_AUTO_TEST_CASE(test_addnode_getaddednodeinfo_and_connection_detection)
BOOST_TEST_MESSAGE("\nCall AddNode() with 2 addrs resolving to existing localhost addnode entry; neither should be added");
BOOST_CHECK(!connman->AddNode({/*m_added_node=*/"127.0.0.1", /*m_use_v2transport=*/true}));
+ // OpenBSD doesn't support the IPv4 shorthand notation with omitted zero-bytes.
+#if !defined(__OpenBSD__)
BOOST_CHECK(!connman->AddNode({/*m_added_node=*/"127.1", /*m_use_v2transport=*/true}));
+#endif
BOOST_TEST_MESSAGE("\nExpect GetAddedNodeInfo to return expected number of peers with `include_connected` true/false");
BOOST_CHECK_EQUAL(connman->GetAddedNodeInfo(/*include_connected=*/true).size(), nodes.size());
BOOST_CHECK(connman->GetAddedNodeInfo(/*include_connected=*/false).empty());
+ // Test AddedNodesContain()
+ for (auto node : connman->TestNodes()) {
+ BOOST_CHECK(connman->AddedNodesContain(node->addr));
+ }
+ AddPeer(id, nodes, *peerman, *connman, ConnectionType::OUTBOUND_FULL_RELAY);
+ BOOST_CHECK(!connman->AddedNodesContain(nodes.back()->addr));
+
BOOST_TEST_MESSAGE("\nPrint GetAddedNodeInfo contents:");
for (const auto& info : connman->GetAddedNodeInfo(/*include_connected=*/true)) {
BOOST_TEST_MESSAGE(strprintf("\nadded node: %s", info.m_params.m_added_node));
diff --git a/src/test/orphanage_tests.cpp b/src/test/orphanage_tests.cpp
index b51de30cb2..bf465c0c64 100644
--- a/src/test/orphanage_tests.cpp
+++ b/src/test/orphanage_tests.cpp
@@ -68,7 +68,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
CMutableTransaction tx;
tx.vin.resize(1);
tx.vin[0].prevout.n = 0;
- tx.vin[0].prevout.hash = InsecureRand256();
+ tx.vin[0].prevout.hash = Txid::FromUint256(InsecureRand256());
tx.vin[0].scriptSig << OP_1;
tx.vout.resize(1);
tx.vout[0].nValue = 1*CENT;
diff --git a/src/test/pool_tests.cpp b/src/test/pool_tests.cpp
index 8a07e09a44..5ad4afa3a1 100644
--- a/src/test/pool_tests.cpp
+++ b/src/test/pool_tests.cpp
@@ -156,21 +156,20 @@ BOOST_AUTO_TEST_CASE(random_allocations)
BOOST_AUTO_TEST_CASE(memusage_test)
{
- auto std_map = std::unordered_map<int, int>{};
-
- using Map = std::unordered_map<int,
- int,
- std::hash<int>,
- std::equal_to<int>,
- PoolAllocator<std::pair<const int, int>,
- sizeof(std::pair<const int, int>) + sizeof(void*) * 4,
- alignof(void*)>>;
+ auto std_map = std::unordered_map<int64_t, int64_t>{};
+
+ using Map = std::unordered_map<int64_t,
+ int64_t,
+ std::hash<int64_t>,
+ std::equal_to<int64_t>,
+ PoolAllocator<std::pair<const int64_t, int64_t>,
+ sizeof(std::pair<const int64_t, int64_t>) + sizeof(void*) * 4>>;
auto resource = Map::allocator_type::ResourceType(1024);
PoolResourceTester::CheckAllDataAccountedFor(resource);
{
- auto resource_map = Map{0, std::hash<int>{}, std::equal_to<int>{}, &resource};
+ auto resource_map = Map{0, std::hash<int64_t>{}, std::equal_to<int64_t>{}, &resource};
// can't have the same resource usage
BOOST_TEST(memusage::DynamicUsage(std_map) != memusage::DynamicUsage(resource_map));
@@ -182,6 +181,11 @@ BOOST_AUTO_TEST_CASE(memusage_test)
// Eventually the resource_map should have a much lower memory usage because it has less malloc overhead
BOOST_TEST(memusage::DynamicUsage(resource_map) <= memusage::DynamicUsage(std_map) * 90 / 100);
+
+ // Make sure the pool is actually used by the nodes
+ auto max_nodes_per_chunk = resource.ChunkSizeBytes() / sizeof(Map::value_type);
+ auto min_num_allocated_chunks = resource_map.size() / max_nodes_per_chunk + 1;
+ BOOST_TEST(resource.NumAllocatedChunks() >= min_num_allocated_chunks);
}
PoolResourceTester::CheckAllDataAccountedFor(resource);
diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp
index bc2e3ca45e..0da9283fa8 100644
--- a/src/test/sighash_tests.cpp
+++ b/src/test/sighash_tests.cpp
@@ -102,7 +102,7 @@ void static RandomTransaction(CMutableTransaction& tx, bool fSingle)
for (int in = 0; in < ins; in++) {
tx.vin.emplace_back();
CTxIn &txin = tx.vin.back();
- txin.prevout.hash = InsecureRand256();
+ txin.prevout.hash = Txid::FromUint256(InsecureRand256());
txin.prevout.n = InsecureRandBits(2);
RandomScript(txin.scriptSig);
txin.nSequence = (InsecureRandBool()) ? InsecureRand32() : std::numeric_limits<uint32_t>::max();
diff --git a/src/test/streams_tests.cpp b/src/test/streams_tests.cpp
index 208993a76d..693247b8d4 100644
--- a/src/test/streams_tests.cpp
+++ b/src/test/streams_tests.cpp
@@ -249,7 +249,7 @@ BOOST_AUTO_TEST_CASE(streams_serializedata_xor)
BOOST_AUTO_TEST_CASE(streams_buffered_file)
{
fs::path streams_test_filename = m_args.GetDataDirBase() / "streams_test_tmp";
- CAutoFile file{fsbridge::fopen(streams_test_filename, "w+b"), 333};
+ AutoFile file{fsbridge::fopen(streams_test_filename, "w+b")};
// The value at each offset is the offset.
for (uint8_t j = 0; j < 40; ++j) {
@@ -271,9 +271,6 @@ BOOST_AUTO_TEST_CASE(streams_buffered_file)
BufferedFile bf{file, 25, 10};
BOOST_CHECK(!bf.eof());
- // This member has no functional effect.
- BOOST_CHECK_EQUAL(bf.GetVersion(), 333);
-
uint8_t i;
bf >> i;
BOOST_CHECK_EQUAL(i, 0);
@@ -383,7 +380,7 @@ BOOST_AUTO_TEST_CASE(streams_buffered_file)
BOOST_AUTO_TEST_CASE(streams_buffered_file_skip)
{
fs::path streams_test_filename = m_args.GetDataDirBase() / "streams_test_tmp";
- CAutoFile file{fsbridge::fopen(streams_test_filename, "w+b"), 333};
+ AutoFile file{fsbridge::fopen(streams_test_filename, "w+b")};
// The value at each offset is the byte offset (e.g. byte 1 in the file has the value 0x01).
for (uint8_t j = 0; j < 40; ++j) {
file << j;
@@ -436,7 +433,7 @@ BOOST_AUTO_TEST_CASE(streams_buffered_file_rand)
fs::path streams_test_filename = m_args.GetDataDirBase() / "streams_test_tmp";
for (int rep = 0; rep < 50; ++rep) {
- CAutoFile file{fsbridge::fopen(streams_test_filename, "w+b"), 333};
+ AutoFile file{fsbridge::fopen(streams_test_filename, "w+b")};
size_t fileSize = InsecureRandRange(256);
for (uint8_t i = 0; i < fileSize; ++i) {
file << i;
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index 220b61f7e7..0a7ef3f780 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -27,6 +27,7 @@
#include <test/util/transaction_utils.h>
#include <util/strencodings.h>
#include <util/string.h>
+#include <util/transaction_identifier.h>
#include <validation.h>
#include <functional>
@@ -219,7 +220,7 @@ BOOST_AUTO_TEST_CASE(tx_valid)
fValid = false;
break;
}
- COutPoint outpoint{uint256S(vinput[0].get_str()), uint32_t(vinput[1].getInt<int>())};
+ COutPoint outpoint{TxidFromString(vinput[0].get_str()), uint32_t(vinput[1].getInt<int>())};
mapprevOutScriptPubKeys[outpoint] = ParseScript(vinput[2].get_str());
if (vinput.size() >= 4)
{
@@ -307,7 +308,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
fValid = false;
break;
}
- COutPoint outpoint{uint256S(vinput[0].get_str()), uint32_t(vinput[1].getInt<int>())};
+ COutPoint outpoint{TxidFromString(vinput[0].get_str()), uint32_t(vinput[1].getInt<int>())};
mapprevOutScriptPubKeys[outpoint] = ParseScript(vinput[2].get_str());
if (vinput.size() >= 4)
{
@@ -504,9 +505,7 @@ BOOST_AUTO_TEST_CASE(test_big_witness_transaction)
// create a big transaction of 4500 inputs signed by the same key
for(uint32_t ij = 0; ij < 4500; ij++) {
uint32_t i = mtx.vin.size();
- uint256 prevId;
- prevId.SetHex("0000000000000000000000000000000000000000000000000000000000000100");
- COutPoint outpoint(prevId, i);
+ COutPoint outpoint(TxidFromString("0000000000000000000000000000000000000000000000000000000000000100"), i);
mtx.vin.resize(mtx.vin.size() + 1);
mtx.vin[i].prevout = outpoint;
diff --git a/src/test/txpackage_tests.cpp b/src/test/txpackage_tests.cpp
index 84c9ecc3d1..637f92bd0f 100644
--- a/src/test/txpackage_tests.cpp
+++ b/src/test/txpackage_tests.cpp
@@ -29,7 +29,7 @@ inline CTransactionRef create_placeholder_tx(size_t num_inputs, size_t num_outpu
mtx.vout.resize(num_outputs);
auto random_script = CScript() << ToByteVector(InsecureRand256()) << ToByteVector(InsecureRand256());
for (size_t i{0}; i < num_inputs; ++i) {
- mtx.vin[i].prevout.hash = InsecureRand256();
+ mtx.vin[i].prevout.hash = Txid::FromUint256(InsecureRand256());
mtx.vin[i].prevout.n = 0;
mtx.vin[i].scriptSig = random_script;
}
@@ -83,7 +83,7 @@ BOOST_FIXTURE_TEST_CASE(package_sanitization_tests, TestChain100Setup)
// Packages can't have transactions spending the same prevout
CMutableTransaction tx_zero_1;
CMutableTransaction tx_zero_2;
- COutPoint same_prevout{InsecureRand256(), 0};
+ COutPoint same_prevout{Txid::FromUint256(InsecureRand256()), 0};
tx_zero_1.vin.emplace_back(same_prevout);
tx_zero_2.vin.emplace_back(same_prevout);
// Different vouts (not the same tx)
@@ -101,7 +101,7 @@ BOOST_FIXTURE_TEST_CASE(package_sanitization_tests, TestChain100Setup)
// IsConsistentPackage only cares about conflicts between transactions, not about a transaction
// conflicting with itself (i.e. duplicate prevouts in vin).
CMutableTransaction dup_tx;
- const COutPoint rand_prevout{InsecureRand256(), 0};
+ const COutPoint rand_prevout{Txid::FromUint256(InsecureRand256()), 0};
dup_tx.vin.emplace_back(rand_prevout);
dup_tx.vin.emplace_back(rand_prevout);
Package package_with_dup_tx{MakeTransactionRef(dup_tx)};
diff --git a/src/test/util/coins.cpp b/src/test/util/coins.cpp
index 9b6c5535c5..742dbc04d1 100644
--- a/src/test/util/coins.cpp
+++ b/src/test/util/coins.cpp
@@ -16,8 +16,7 @@
COutPoint AddTestCoin(CCoinsViewCache& coins_view)
{
Coin new_coin;
- const uint256 txid{InsecureRand256()};
- COutPoint outpoint{txid, /*nIn=*/0};
+ COutPoint outpoint{Txid::FromUint256(InsecureRand256()), /*nIn=*/0};
new_coin.nHeight = 1;
new_coin.out.nValue = InsecureRandMoneyAmount();
new_coin.out.scriptPubKey.assign(uint32_t{56}, 1);
diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp
index 9979b75444..22fdf132c7 100644
--- a/src/test/util/setup_common.cpp
+++ b/src/test/util/setup_common.cpp
@@ -501,7 +501,7 @@ void TestChain100Setup::MockMempoolMinFee(const CFeeRate& target_feerate)
// Manually create an invalid transaction. Manually set the fee in the CTxMemPoolEntry to
// achieve the exact target feerate.
CMutableTransaction mtx = CMutableTransaction();
- mtx.vin.emplace_back(COutPoint{g_insecure_rand_ctx.rand256(), 0});
+ mtx.vin.emplace_back(COutPoint{Txid::FromUint256(g_insecure_rand_ctx.rand256()), 0});
mtx.vout.emplace_back(1 * COIN, GetScriptForDestination(WitnessV0ScriptHash(CScript() << OP_TRUE)));
const auto tx{MakeTransactionRef(mtx)};
LockPoints lp;
diff --git a/src/test/validation_chainstatemanager_tests.cpp b/src/test/validation_chainstatemanager_tests.cpp
index e2541a74fd..6969822ad7 100644
--- a/src/test/validation_chainstatemanager_tests.cpp
+++ b/src/test/validation_chainstatemanager_tests.cpp
@@ -724,7 +724,7 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_snapshot_completion_hash_mismatch, Sna
badcoin.out.nValue = InsecureRand32();
badcoin.nHeight = 1;
badcoin.out.scriptPubKey.assign(InsecureRandBits(6), 0);
- uint256 txid = InsecureRand256();
+ Txid txid = Txid::FromUint256(InsecureRand256());
ibd_coins.AddCoin(COutPoint(txid, 0), std::move(badcoin), false);
fs::path snapshot_chainstate_dir = gArgs.GetDataDirNet() / "chainstate_snapshot";
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index e057d7ece1..b6be395d74 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -124,7 +124,7 @@ void CTxMemPool::UpdateTransactionsFromBlock(const std::vector<uint256>& vHashes
if (it == mapTx.end()) {
continue;
}
- auto iter = mapNextTx.lower_bound(COutPoint(hash, 0));
+ auto iter = mapNextTx.lower_bound(COutPoint(Txid::FromUint256(hash), 0));
// First calculate the children, and update CTxMemPoolEntry::m_children to
// include them, and update their CTxMemPoolEntry::m_parents to include this tx.
// we cache the in-mempool children to avoid duplicate updates
diff --git a/src/util/check.h b/src/util/check.h
index 00951dec89..a02a1de8dc 100644
--- a/src/util/check.h
+++ b/src/util/check.h
@@ -7,6 +7,7 @@
#include <attributes.h>
+#include <cassert> // IWYU pragma: export
#include <stdexcept>
#include <string>
#include <string_view>
diff --git a/src/util/transaction_identifier.h b/src/util/transaction_identifier.h
index 4fb9b49966..89e10dee01 100644
--- a/src/util/transaction_identifier.h
+++ b/src/util/transaction_identifier.h
@@ -65,4 +65,9 @@ using Txid = transaction_identifier<false>;
/** Wtxid commits to all transaction fields including the witness. */
using Wtxid = transaction_identifier<true>;
+inline Txid TxidFromString(std::string_view str)
+{
+ return Txid::FromUint256(uint256S(str.data()));
+}
+
#endif // BITCOIN_UTIL_TRANSACTION_IDENTIFIER_H
diff --git a/src/validation.cpp b/src/validation.cpp
index ed72a7c97a..dbb00d4e4a 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -696,7 +696,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
AssertLockHeld(m_pool.cs);
const CTransactionRef& ptx = ws.m_ptx;
const CTransaction& tx = *ws.m_ptx;
- const uint256& hash = ws.m_hash;
+ const Txid& hash = ws.m_hash;
// Copy/alias what we need out of args
const int64_t nAcceptTime = args.m_accept_time;
@@ -2036,7 +2036,7 @@ DisconnectResult Chainstate::DisconnectBlock(const CBlock& block, const CBlockIn
// undo transactions in reverse order
for (int i = block.vtx.size() - 1; i >= 0; i--) {
const CTransaction &tx = *(block.vtx[i]);
- uint256 hash = tx.GetHash();
+ Txid hash = tx.GetHash();
bool is_coinbase = tx.IsCoinBase();
bool is_bip30_exception = (is_coinbase && !fEnforceBIP30);
@@ -4649,7 +4649,7 @@ bool Chainstate::LoadGenesisBlock()
}
void ChainstateManager::LoadExternalBlockFile(
- CAutoFile& file_in,
+ AutoFile& file_in,
FlatFilePos* dbp,
std::multimap<uint256, FlatFilePos>* blocks_with_unknown_parent)
{
diff --git a/src/validation.h b/src/validation.h
index e669ec46d5..7473bcbc3b 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -1137,7 +1137,7 @@ public:
* (only used for reindex)
* */
void LoadExternalBlockFile(
- CAutoFile& file_in,
+ AutoFile& file_in,
FlatFilePos* dbp = nullptr,
std::multimap<uint256, FlatFilePos>* blocks_with_unknown_parent = nullptr);
diff --git a/src/wallet/receive.cpp b/src/wallet/receive.cpp
index 0a75bb6d92..b9d8d9abc9 100644
--- a/src/wallet/receive.cpp
+++ b/src/wallet/receive.cpp
@@ -173,7 +173,7 @@ CAmount CachedTxGetAvailableCredit(const CWallet& wallet, const CWalletTx& wtx,
bool allow_used_addresses = (filter & ISMINE_USED) || !wallet.IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE);
CAmount nCredit = 0;
- uint256 hashTx = wtx.GetHash();
+ Txid hashTx = wtx.GetHash();
for (unsigned int i = 0; i < wtx.tx->vout.size(); i++) {
const CTxOut& txout = wtx.tx->vout[i];
if (!wallet.IsSpent(COutPoint(hashTx, i)) && (allow_used_addresses || !wallet.IsSpentKey(txout.scriptPubKey))) {
@@ -348,7 +348,7 @@ std::map<CTxDestination, CAmount> GetAddressBalances(const CWallet& wallet)
if(!ExtractDestination(output.scriptPubKey, addr))
continue;
- CAmount n = wallet.IsSpent(COutPoint(walletEntry.first, i)) ? 0 : output.nValue;
+ CAmount n = wallet.IsSpent(COutPoint(Txid::FromUint256(walletEntry.first), i)) ? 0 : output.nValue;
balances[addr] += n;
}
}
diff --git a/src/wallet/rpc/coins.cpp b/src/wallet/rpc/coins.cpp
index fdc6ee055d..0cb0891141 100644
--- a/src/wallet/rpc/coins.cpp
+++ b/src/wallet/rpc/coins.cpp
@@ -320,7 +320,7 @@ RPCHelpMan lockunspent()
{"vout", UniValueType(UniValue::VNUM)},
});
- const uint256 txid(ParseHashO(o, "txid"));
+ const Txid txid = Txid::FromUint256(ParseHashO(o, "txid"));
const int nOutput = o.find_value("vout").getInt<int>();
if (nOutput < 0) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout cannot be negative");
diff --git a/src/wallet/rpc/spend.cpp b/src/wallet/rpc/spend.cpp
index 6519504618..84e617c140 100644
--- a/src/wallet/rpc/spend.cpp
+++ b/src/wallet/rpc/spend.cpp
@@ -672,7 +672,7 @@ void FundTransaction(CWallet& wallet, CMutableTransaction& tx, CAmount& fee_out,
if (options.exists("input_weights")) {
for (const UniValue& input : options["input_weights"].get_array().getValues()) {
- uint256 txid = ParseHashO(input, "txid");
+ Txid txid = Txid::FromUint256(ParseHashO(input, "txid"));
const UniValue& vout_v = input.find_value("vout");
if (!vout_v.isNum()) {
diff --git a/src/wallet/spend.cpp b/src/wallet/spend.cpp
index d586f6d4aa..35583642a5 100644
--- a/src/wallet/spend.cpp
+++ b/src/wallet/spend.cpp
@@ -321,7 +321,7 @@ CoinsResult AvailableCoins(const CWallet& wallet,
std::set<uint256> trusted_parents;
for (const auto& entry : wallet.mapWallet)
{
- const uint256& wtxid = entry.first;
+ const uint256& txid = entry.first;
const CWalletTx& wtx = entry.second;
if (wallet.IsTxImmatureCoinBase(wtx) && !params.include_immature_coinbase)
@@ -381,7 +381,7 @@ CoinsResult AvailableCoins(const CWallet& wallet,
for (unsigned int i = 0; i < wtx.tx->vout.size(); i++) {
const CTxOut& output = wtx.tx->vout[i];
- const COutPoint outpoint(wtxid, i);
+ const COutPoint outpoint(Txid::FromUint256(txid), i);
if (output.nValue < params.min_amount || output.nValue > params.max_amount)
continue;
diff --git a/src/wallet/test/feebumper_tests.cpp b/src/wallet/test/feebumper_tests.cpp
index 2480a9b4e1..80fd778419 100644
--- a/src/wallet/test/feebumper_tests.cpp
+++ b/src/wallet/test/feebumper_tests.cpp
@@ -21,7 +21,7 @@ static void CheckMaxWeightComputation(const std::string& script_str, const std::
{
std::vector script_data(ParseHex(script_str));
CScript script(script_data.begin(), script_data.end());
- CTxIn input(uint256(), 0, script);
+ CTxIn input(Txid{}, 0, script);
for (const auto& s : witness_str_stack) {
input.scriptWitness.stack.push_back(ParseHex(s));
diff --git a/src/wallet/test/fuzz/notifications.cpp b/src/wallet/test/fuzz/notifications.cpp
index abd788f96f..08dee08cc4 100644
--- a/src/wallet/test/fuzz/notifications.cpp
+++ b/src/wallet/test/fuzz/notifications.cpp
@@ -2,21 +2,46 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <addresstype.h>
+#include <common/args.h>
+#include <consensus/amount.h>
+#include <interfaces/chain.h>
#include <kernel/chain.h>
+#include <outputtype.h>
+#include <policy/feerate.h>
+#include <policy/policy.h>
+#include <primitives/block.h>
+#include <primitives/transaction.h>
+#include <script/descriptor.h>
+#include <script/script.h>
+#include <script/signingprovider.h>
+#include <sync.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
#include <test/util/setup_common.h>
+#include <tinyformat.h>
+#include <uint256.h>
+#include <util/check.h>
+#include <util/result.h>
#include <util/translation.h>
+#include <wallet/coincontrol.h>
#include <wallet/context.h>
+#include <wallet/fees.h>
#include <wallet/receive.h>
+#include <wallet/spend.h>
+#include <wallet/test/util.h>
#include <wallet/wallet.h>
-#include <wallet/walletdb.h>
#include <wallet/walletutil.h>
-#include <cassert>
+#include <cstddef>
#include <cstdint>
+#include <limits>
+#include <numeric>
+#include <set>
#include <string>
+#include <tuple>
+#include <utility>
#include <vector>
namespace wallet {
@@ -29,45 +54,59 @@ void initialize_setup()
g_setup = testing_setup.get();
}
+void ImportDescriptors(CWallet& wallet, const std::string& seed_insecure)
+{
+ const std::vector<std::string> DESCS{
+ "pkh(%s/%s/*)",
+ "sh(wpkh(%s/%s/*))",
+ "tr(%s/%s/*)",
+ "wpkh(%s/%s/*)",
+ };
+
+ for (const std::string& desc_fmt : DESCS) {
+ for (bool internal : {true, false}) {
+ const auto descriptor{(strprintf)(desc_fmt, "[5aa9973a/66h/4h/2h]" + seed_insecure, int{internal})};
+
+ FlatSigningProvider keys;
+ std::string error;
+ auto parsed_desc = Parse(descriptor, keys, error, /*require_checksum=*/false);
+ assert(parsed_desc);
+ assert(error.empty());
+ assert(parsed_desc->IsRange());
+ assert(parsed_desc->IsSingleType());
+ assert(!keys.keys.empty());
+ WalletDescriptor w_desc{std::move(parsed_desc), /*creation_time=*/0, /*range_start=*/0, /*range_end=*/1, /*next_index=*/0};
+ assert(!wallet.GetDescriptorScriptPubKeyMan(w_desc));
+ LOCK(wallet.cs_wallet);
+ auto spk_manager{wallet.AddWalletDescriptor(w_desc, keys, /*label=*/"", internal)};
+ assert(spk_manager);
+ wallet.AddActiveScriptPubKeyMan(spk_manager->GetID(), *Assert(w_desc.descriptor->GetOutputType()), internal);
+ }
+ }
+}
+
/**
- * Wraps a descriptor wallet for fuzzing. The constructor writes the sqlite db
- * to disk, the destructor deletes it.
+ * Wraps a descriptor wallet for fuzzing.
*/
struct FuzzedWallet {
ArgsManager args;
WalletContext context;
std::shared_ptr<CWallet> wallet;
- FuzzedWallet(const std::string& name)
+ FuzzedWallet(const std::string& name, const std::string& seed_insecure)
{
- context.args = &args;
- context.chain = g_setup->m_node.chain.get();
-
- DatabaseOptions options;
- options.require_create = true;
- options.create_flags = WALLET_FLAG_DESCRIPTORS;
- const std::optional<bool> load_on_start;
- gArgs.ForceSetArg("-keypool", "0"); // Avoid timeout in TopUp()
-
- DatabaseStatus status;
- bilingual_str error;
- std::vector<bilingual_str> warnings;
- wallet = CreateWallet(context, name, load_on_start, options, status, error, warnings);
- assert(wallet);
- assert(error.empty());
- assert(warnings.empty());
+ auto& chain{*Assert(g_setup->m_node.chain)};
+ wallet = std::make_shared<CWallet>(&chain, name, 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);
}
- ~FuzzedWallet()
- {
- const auto name{wallet->GetName()};
- std::vector<bilingual_str> warnings;
- std::optional<bool> load_on_start;
- assert(RemoveWallet(context, wallet, load_on_start, warnings));
- assert(warnings.empty());
- UnloadWallet(std::move(wallet));
- fs::remove_all(GetWalletDir() / fs::PathFromString(name));
- }
- CScript GetScriptPubKey(FuzzedDataProvider& fuzzed_data_provider)
+ CTxDestination GetDestination(FuzzedDataProvider& fuzzed_data_provider)
{
auto type{fuzzed_data_provider.PickValueInArray(OUTPUT_TYPES)};
util::Result<CTxDestination> op_dest{util::Error{}};
@@ -76,7 +115,51 @@ struct FuzzedWallet {
} else {
op_dest = wallet->GetNewChangeDestination(type);
}
- return GetScriptForDestination(*Assert(op_dest));
+ return *Assert(op_dest);
+ }
+ CScript GetScriptPubKey(FuzzedDataProvider& fuzzed_data_provider) { return GetScriptForDestination(GetDestination(fuzzed_data_provider)); }
+ void FundTx(FuzzedDataProvider& fuzzed_data_provider, CMutableTransaction tx)
+ {
+ // The fee of "tx" is 0, so this is the total input and output amount
+ const CAmount total_amt{
+ std::accumulate(tx.vout.begin(), tx.vout.end(), CAmount{}, [](CAmount t, const CTxOut& out) { return t + out.nValue; })};
+ const uint32_t tx_size(GetVirtualTransactionSize(CTransaction{tx}));
+ std::set<int> subtract_fee_from_outputs;
+ if (fuzzed_data_provider.ConsumeBool()) {
+ for (size_t i{}; i < tx.vout.size(); ++i) {
+ if (fuzzed_data_provider.ConsumeBool()) {
+ subtract_fee_from_outputs.insert(i);
+ }
+ }
+ }
+ CCoinControl coin_control;
+ coin_control.m_allow_other_inputs = fuzzed_data_provider.ConsumeBool();
+ CallOneOf(
+ fuzzed_data_provider, [&] { coin_control.destChange = GetDestination(fuzzed_data_provider); },
+ [&] { coin_control.m_change_type.emplace(fuzzed_data_provider.PickValueInArray(OUTPUT_TYPES)); },
+ [&] { /* no op (leave uninitialized) */ });
+ coin_control.fAllowWatchOnly = fuzzed_data_provider.ConsumeBool();
+ coin_control.m_include_unsafe_inputs = fuzzed_data_provider.ConsumeBool();
+ {
+ auto& r{coin_control.m_signal_bip125_rbf};
+ CallOneOf(
+ fuzzed_data_provider, [&] { r = true; }, [&] { r = false; }, [&] { r = std::nullopt; });
+ }
+ coin_control.m_feerate = CFeeRate{
+ // A fee of this range should cover all cases
+ fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(0, 2 * total_amt),
+ tx_size,
+ };
+ if (fuzzed_data_provider.ConsumeBool()) {
+ *coin_control.m_feerate += GetMinimumFeeRate(*wallet, coin_control, nullptr);
+ }
+ coin_control.fOverrideFeeRate = fuzzed_data_provider.ConsumeBool();
+ // Add solving data (m_external_provider and SelectExternal)?
+
+ CAmount fee_out;
+ int change_position{fuzzed_data_provider.ConsumeIntegralInRange<int>(-1, tx.vout.size() - 1)};
+ bilingual_str error;
+ (void)FundTransaction(*wallet, tx, fee_out, change_position, error, /*lockUnspents=*/false, subtract_fee_from_outputs, coin_control);
}
};
@@ -87,8 +170,14 @@ FUZZ_TARGET(wallet_notifications, .init = initialize_setup)
// without fee. Thus, the balance of the wallets should always equal the
// total amount.
const auto total_amount{ConsumeMoney(fuzzed_data_provider)};
- FuzzedWallet a{"fuzzed_wallet_a"};
- FuzzedWallet b{"fuzzed_wallet_b"};
+ FuzzedWallet a{
+ "fuzzed_wallet_a",
+ "tprv8ZgxMBicQKsPd1QwsGgzfu2pcPYbBosZhJknqreRHgsWx32nNEhMjGQX2cgFL8n6wz9xdDYwLcs78N4nsCo32cxEX8RBtwGsEGgybLiQJfk",
+ };
+ FuzzedWallet b{
+ "fuzzed_wallet_b",
+ "tprv8ZgxMBicQKsPfCunYTF18sEmEyjz8TfhGnZ3BoVAhkqLv7PLkQgmoG2Ecsp4JuqciWnkopuEwShit7st743fdmB9cMD4tznUkcs33vK51K9",
+ };
// Keep track of all coins in this test.
// Each tuple in the chain represents the coins and the block created with
@@ -100,7 +189,7 @@ FUZZ_TARGET(wallet_notifications, .init = initialize_setup)
// Add the initial entry
chain.emplace_back();
auto& [coins, block]{chain.back()};
- coins.emplace(total_amount, COutPoint{uint256::ONE, 1});
+ coins.emplace(total_amount, COutPoint{Txid::FromUint256(uint256::ONE), 1});
}
LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 200)
{
@@ -123,7 +212,7 @@ FUZZ_TARGET(wallet_notifications, .init = initialize_setup)
coins.erase(coins.begin());
}
// Create some outputs spending all inputs, without fee
- LIMITED_WHILE(in > 0 && fuzzed_data_provider.ConsumeBool(), 100)
+ LIMITED_WHILE(in > 0 && fuzzed_data_provider.ConsumeBool(), 10)
{
const auto out_value{ConsumeMoney(fuzzed_data_provider, in)};
in -= out_value;
@@ -135,6 +224,9 @@ FUZZ_TARGET(wallet_notifications, .init = initialize_setup)
tx.vout.emplace_back(in, wallet.GetScriptPubKey(fuzzed_data_provider));
// Add tx to block
block.vtx.emplace_back(MakeTransactionRef(tx));
+ // Check that funding the tx doesn't crash the wallet
+ a.FundTx(fuzzed_data_provider, tx);
+ b.FundTx(fuzzed_data_provider, tx);
}
// Mine block
const uint256& hash = block.GetHash();
diff --git a/src/wallet/test/fuzz/scriptpubkeyman.cpp b/src/wallet/test/fuzz/scriptpubkeyman.cpp
new file mode 100644
index 0000000000..a8a9c7ce36
--- /dev/null
+++ b/src/wallet/test/fuzz/scriptpubkeyman.cpp
@@ -0,0 +1,165 @@
+// 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 <chainparams.h>
+#include <validation.h>
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+#include <test/fuzz/util/descriptor.h>
+#include <test/util/setup_common.h>
+#include <wallet/scriptpubkeyman.h>
+#include <wallet/wallet.h>
+#include <wallet/test/util.h>
+
+namespace wallet {
+namespace {
+const TestingSetup* g_setup;
+
+//! The converter of mocked descriptors, needs to be initialized when the target is.
+MockedDescriptorConverter MOCKED_DESC_CONVERTER;
+
+void initialize_spkm()
+{
+ static const auto testing_setup{MakeNoLogFileContext<const TestingSetup>()};
+ g_setup = testing_setup.get();
+ SelectParams(ChainType::MAIN);
+ MOCKED_DESC_CONVERTER.Init();
+}
+
+static std::optional<std::pair<WalletDescriptor, FlatSigningProvider>> CreateWalletDescriptor(FuzzedDataProvider& fuzzed_data_provider)
+{
+ const std::string mocked_descriptor{fuzzed_data_provider.ConsumeRandomLengthString()};
+ const auto desc_str{MOCKED_DESC_CONVERTER.GetDescriptor(mocked_descriptor)};
+ if (!desc_str.has_value()) return std::nullopt;
+
+ FlatSigningProvider keys;
+ std::string error;
+ std::unique_ptr<Descriptor> parsed_desc{Parse(desc_str.value(), keys, error, false)};
+ if (!parsed_desc) return std::nullopt;
+
+ WalletDescriptor w_desc{std::move(parsed_desc), /*creation_time=*/0, /*range_start=*/0, /*range_end=*/1, /*next_index=*/1};
+ return std::make_pair(w_desc, keys);
+}
+
+static DescriptorScriptPubKeyMan* CreateDescriptor(WalletDescriptor& wallet_desc, FlatSigningProvider& keys, CWallet& keystore)
+{
+ LOCK(keystore.cs_wallet);
+ keystore.AddWalletDescriptor(wallet_desc, keys, /*label=*/"", /*internal=*/false);
+ return keystore.GetDescriptorScriptPubKeyMan(wallet_desc);
+};
+
+FUZZ_TARGET(scriptpubkeyman, .init = initialize_spkm)
+{
+ FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
+ const auto& node{g_setup->m_node};
+ Chainstate& chainstate{node.chainman->ActiveChainstate()};
+ std::unique_ptr<CWallet> wallet_ptr{std::make_unique<CWallet>(node.chain.get(), "", CreateMockableWalletDatabase())};
+ CWallet& wallet{*wallet_ptr};
+ {
+ LOCK(wallet.cs_wallet);
+ wallet.SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
+ wallet.SetLastBlockProcessed(chainstate.m_chain.Height(), chainstate.m_chain.Tip()->GetBlockHash());
+ }
+
+ auto wallet_desc{CreateWalletDescriptor(fuzzed_data_provider)};
+ if (!wallet_desc.has_value()) return;
+ auto spk_manager{CreateDescriptor(wallet_desc->first, wallet_desc->second, wallet)};
+ if (spk_manager == nullptr) return;
+
+ bool good_data{true};
+ LIMITED_WHILE(good_data && fuzzed_data_provider.ConsumeBool(), 300) {
+ CallOneOf(
+ fuzzed_data_provider,
+ [&] {
+ auto wallet_desc{CreateWalletDescriptor(fuzzed_data_provider)};
+ if (!wallet_desc.has_value()) {
+ good_data = false;
+ return;
+ }
+ std::string error;
+ if (spk_manager->CanUpdateToWalletDescriptor(wallet_desc->first, error)) {
+ auto new_spk_manager{CreateDescriptor(wallet_desc->first, wallet_desc->second, wallet)};
+ if (new_spk_manager != nullptr) spk_manager = new_spk_manager;
+ }
+ },
+ [&] {
+ const CScript script{ConsumeScript(fuzzed_data_provider)};
+ auto is_mine{spk_manager->IsMine(script)};
+ if (is_mine == isminetype::ISMINE_SPENDABLE) {
+ assert(spk_manager->GetScriptPubKeys().count(script));
+ }
+ },
+ [&] {
+ auto spks{spk_manager->GetScriptPubKeys()};
+ for (const CScript& spk : spks) {
+ assert(spk_manager->IsMine(spk) == ISMINE_SPENDABLE);
+ CTxDestination dest;
+ bool extract_dest{ExtractDestination(spk, dest)};
+ if (extract_dest) {
+ const std::string msg{fuzzed_data_provider.ConsumeRandomLengthString()};
+ PKHash pk_hash{fuzzed_data_provider.ConsumeBool() ? PKHash{ConsumeUInt160(fuzzed_data_provider)} : *std::get_if<PKHash>(&dest)};
+ std::string str_sig;
+ (void)spk_manager->SignMessage(msg, pk_hash, str_sig);
+ }
+ }
+ },
+ [&] {
+ CKey key{ConsumePrivateKey(fuzzed_data_provider, /*compressed=*/fuzzed_data_provider.ConsumeBool())};
+ if (!key.IsValid()) {
+ good_data = false;
+ return;
+ }
+ spk_manager->AddDescriptorKey(key, key.GetPubKey());
+ spk_manager->TopUp();
+ },
+ [&] {
+ std::string descriptor;
+ (void)spk_manager->GetDescriptorString(descriptor, /*priv=*/fuzzed_data_provider.ConsumeBool());
+ },
+ [&] {
+ LOCK(spk_manager->cs_desc_man);
+ auto wallet_desc{spk_manager->GetWalletDescriptor()};
+ if (wallet_desc.descriptor->IsSingleType()) {
+ auto output_type{wallet_desc.descriptor->GetOutputType()};
+ if (output_type.has_value()) {
+ auto dest{spk_manager->GetNewDestination(*output_type)};
+ if (dest) {
+ assert(IsValidDestination(*dest));
+ assert(spk_manager->IsHDEnabled());
+ }
+ }
+ }
+ },
+ [&] {
+ CMutableTransaction tx_to;
+ const std::optional<CMutableTransaction> opt_tx_to{ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider, TX_WITH_WITNESS)};
+ if (!opt_tx_to) {
+ good_data = false;
+ return;
+ }
+ tx_to = *opt_tx_to;
+
+ std::map<COutPoint, Coin> coins{ConsumeCoins(fuzzed_data_provider)};
+ const int sighash{fuzzed_data_provider.ConsumeIntegral<int>()};
+ std::map<int, bilingual_str> input_errors;
+ (void)spk_manager->SignTransaction(tx_to, coins, sighash, input_errors);
+ },
+ [&] {
+ std::optional<PartiallySignedTransaction> opt_psbt{ConsumeDeserializable<PartiallySignedTransaction>(fuzzed_data_provider)};
+ if (!opt_psbt) {
+ good_data = false;
+ return;
+ }
+ auto psbt{*opt_psbt};
+ const PrecomputedTransactionData txdata{PrecomputePSBTData(psbt)};
+ const int sighash_type{fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 150)};
+ (void)spk_manager->FillPSBT(psbt, txdata, sighash_type, fuzzed_data_provider.ConsumeBool(), fuzzed_data_provider.ConsumeBool(), nullptr, fuzzed_data_provider.ConsumeBool());
+ }
+ );
+ }
+}
+
+} // namespace
+} // namespace wallet
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index c5452c3b0d..6d7b9100b5 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -946,7 +946,7 @@ BOOST_FIXTURE_TEST_CASE(wallet_sync_tx_invalid_state_test, TestingSetup)
CMutableTransaction mtx;
mtx.vout.emplace_back(COIN, GetScriptForDestination(op_dest));
- mtx.vin.emplace_back(g_insecure_rand_ctx.rand256(), 0);
+ mtx.vin.emplace_back(Txid::FromUint256(g_insecure_rand_ctx.rand256()), 0);
const auto& tx_id_to_spend = wallet.AddToWallet(MakeTransactionRef(mtx), TxStateInMempool{})->GetHash();
{
@@ -963,12 +963,12 @@ BOOST_FIXTURE_TEST_CASE(wallet_sync_tx_invalid_state_test, TestingSetup)
mtx.vin.clear();
mtx.vin.emplace_back(tx_id_to_spend, 0);
wallet.transactionAddedToMempool(MakeTransactionRef(mtx));
- const auto good_tx_id{mtx.GetHash().ToUint256()};
+ const auto good_tx_id{mtx.GetHash()};
{
// Verify balance update for the new tx and the old one
LOCK(wallet.cs_wallet);
- const CWalletTx* new_wtx = wallet.GetWalletTx(good_tx_id);
+ const CWalletTx* new_wtx = wallet.GetWalletTx(good_tx_id.ToUint256());
BOOST_CHECK_EQUAL(CachedTxGetAvailableCredit(wallet, *new_wtx), 1 * COIN);
// Now the old wtx
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index ecf18fbe78..c34bf96b5e 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -681,7 +681,7 @@ std::set<uint256> CWallet::GetConflicts(const uint256& txid) const
bool CWallet::HasWalletSpend(const CTransactionRef& tx) const
{
AssertLockHeld(cs_wallet);
- const uint256& txid = tx->GetHash();
+ const Txid& txid = tx->GetHash();
for (unsigned int i = 0; i < tx->vout.size(); ++i) {
if (IsSpent(COutPoint(txid, i))) {
return true;
@@ -1373,7 +1373,7 @@ void CWallet::RecursiveUpdateTxState(const uint256& tx_hash, const TryUpdatingSt
batch.WriteTx(wtx);
// Iterate over all its outputs, and update those tx states as well (if applicable)
for (unsigned int i = 0; i < wtx.tx->vout.size(); ++i) {
- std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(COutPoint(now, i));
+ std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(COutPoint(Txid::FromUint256(now), i));
for (TxSpends::const_iterator iter = range.first; iter != range.second; ++iter) {
if (!done.count(iter->second)) {
todo.insert(iter->second);
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index 92eca46f05..66da5c1dc4 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -1073,7 +1073,7 @@ static DBErrors LoadTxRecords(CWallet* pwallet, DatabaseBatch& batch, std::vecto
// Load locked utxo record
LoadResult locked_utxo_res = LoadRecords(pwallet, batch, DBKeys::LOCKED_UTXO,
[] (CWallet* pwallet, DataStream& key, CDataStream& value, std::string& err) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet) {
- uint256 hash;
+ Txid hash;
uint32_t n;
key >> hash;
key >> n;