diff options
Diffstat (limited to 'src')
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); @@ -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; |