diff --git a/src/bench/ccoins_caching.cpp b/src/bench/ccoins_caching.cpp --- a/src/bench/ccoins_caching.cpp +++ b/src/bench/ccoins_caching.cpp @@ -65,14 +65,14 @@ CMutableTransaction t1; t1.vin.resize(3); - t1.vin[0].prevout.hash = dummyTransactions[0].GetId(); + t1.vin[0].prevout.unspentid = dummyTransactions[0].GetUnspentid(); t1.vin[0].prevout.n = 1; t1.vin[0].scriptSig << std::vector(65, 0); - t1.vin[1].prevout.hash = dummyTransactions[1].GetId(); + t1.vin[1].prevout.unspentid = dummyTransactions[1].GetUnspentid(); t1.vin[1].prevout.n = 0; t1.vin[1].scriptSig << std::vector(65, 0) << std::vector(33, 4); - t1.vin[2].prevout.hash = dummyTransactions[1].GetId(); + t1.vin[2].prevout.unspentid = dummyTransactions[1].GetUnspentid(); t1.vin[2].prevout.n = 1; t1.vin[2].scriptSig << std::vector(65, 0) << std::vector(33, 4); diff --git a/src/bench/mempool_eviction.cpp b/src/bench/mempool_eviction.cpp --- a/src/bench/mempool_eviction.cpp +++ b/src/bench/mempool_eviction.cpp @@ -17,7 +17,7 @@ bool spendsCoinbase = false; unsigned int sigOpCost = 4; LockPoints lp; - pool.addUnchecked(tx.GetId(), + pool.addUnchecked(tx.GetHash(), CTxMemPoolEntry(MakeTransactionRef(tx), nFee, nTime, dPriority, nHeight, tx.GetValueOut().GetSatoshis(), @@ -44,7 +44,7 @@ CMutableTransaction tx3 = CMutableTransaction(); tx3.vin.resize(1); - tx3.vin[0].prevout = COutPoint(tx2.GetId(), 0); + tx3.vin[0].prevout = COutPoint(tx2.GetUnspentid(), 0); tx3.vin[0].scriptSig = CScript() << OP_2; tx3.vout.resize(1); tx3.vout[0].scriptPubKey = CScript() << OP_3 << OP_EQUAL; @@ -64,7 +64,7 @@ CMutableTransaction tx5 = CMutableTransaction(); tx5.vin.resize(2); - tx5.vin[0].prevout = COutPoint(tx4.GetId(), 0); + tx5.vin[0].prevout = COutPoint(tx4.GetUnspentid(), 0); tx5.vin[0].scriptSig = CScript() << OP_4; tx5.vin[1].prevout.SetNull(); tx5.vin[1].scriptSig = CScript() << OP_5; @@ -76,7 +76,7 @@ CMutableTransaction tx6 = CMutableTransaction(); tx6.vin.resize(2); - tx6.vin[0].prevout = COutPoint(tx4.GetId(), 1); + tx6.vin[0].prevout = COutPoint(tx4.GetUnspentid(), 1); tx6.vin[0].scriptSig = CScript() << OP_4; tx6.vin[1].prevout.SetNull(); tx6.vin[1].scriptSig = CScript() << OP_6; @@ -88,9 +88,9 @@ CMutableTransaction tx7 = CMutableTransaction(); tx7.vin.resize(2); - tx7.vin[0].prevout = COutPoint(tx5.GetId(), 0); + tx7.vin[0].prevout = COutPoint(tx5.GetUnspentid(), 0); tx7.vin[0].scriptSig = CScript() << OP_5; - tx7.vin[1].prevout = COutPoint(tx6.GetId(), 0); + tx7.vin[1].prevout = COutPoint(tx6.GetUnspentid(), 0); tx7.vin[1].scriptSig = CScript() << OP_6; tx7.vout.resize(2); tx7.vout[0].scriptPubKey = CScript() << OP_7 << OP_EQUAL; diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -67,8 +67,8 @@ strUsage += HelpMessageOpt("-create", _("Create new, empty TX.")); strUsage += HelpMessageOpt("-json", _("Select JSON output")); strUsage += - HelpMessageOpt("-txid", _("Output only the hex-encoded transaction " - "id of the resultant transaction.")); + HelpMessageOpt("-txhash", _("Output only the hex-encoded hash " + "of the resultant transaction.")); AppendParamsHelpMessages(strUsage); fprintf(stdout, "%s", strUsage.c_str()); @@ -76,7 +76,7 @@ strUsage = HelpMessageGroup(_("Commands:")); strUsage += HelpMessageOpt("delin=N", _("Delete input N from TX")); strUsage += HelpMessageOpt("delout=N", _("Delete output N from TX")); - strUsage += HelpMessageOpt("in=TXID:VOUT(:SEQUENCE_NUMBER)", + strUsage += HelpMessageOpt("in=unspentid:VOUT(:SEQUENCE_NUMBER)", _("Add input to TX")); strUsage += HelpMessageOpt("locktime=N", _("Set TX lock time to N")); strUsage += HelpMessageOpt("nversion=N", _("Set TX version to N")); @@ -228,18 +228,18 @@ std::vector vStrInputParts; boost::split(vStrInputParts, strInput, boost::is_any_of(":")); - // separate TXID:VOUT in string + // separate unspentid:VOUT in string if (vStrInputParts.size() < 2) { throw std::runtime_error("TX input missing separator"); } - // extract and validate TXID - std::string strTxid = vStrInputParts[0]; - if ((strTxid.size() != 64) || !IsHex(strTxid)) { - throw std::runtime_error("invalid TX input txid"); + // extract and validate unspentid + std::string strunspentid = vStrInputParts[0]; + if ((strunspentid.size() != 64) || !IsHex(strunspentid)) { + throw std::runtime_error("invalid TX input unspentid"); } - uint256 txid(uint256S(strTxid)); + unspentid_t unspentid(uint256S(strunspentid)); static const unsigned int minTxOutSz = 9; static const unsigned int maxVout = MAX_TX_SIZE / minTxOutSz; @@ -258,7 +258,7 @@ } // append to transaction input list - CTxIn txin(txid, vout, CScript(), nSequenceIn); + CTxIn txin(unspentid, vout, CScript(), nSequenceIn); tx.vin.push_back(txin); } @@ -603,21 +603,22 @@ } std::map types = { - {"txid", UniValue::VSTR}, + {"unspentid", UniValue::VSTR}, {"vout", UniValue::VNUM}, {"scriptPubKey", UniValue::VSTR}}; if (!prevOut.checkObject(types)) { throw std::runtime_error("prevtxs internal object typecheck fail"); } - uint256 txid = ParseHashUV(prevOut["txid"], "txid"); + unspentid_t unspentid = + unspentid_t(ParseHashUV(prevOut["unspentid"], "unspentid")); int nOut = atoi(prevOut["vout"].getValStr()); if (nOut < 0) { throw std::runtime_error("vout must be positive"); } - COutPoint out(txid, nOut); + COutPoint out(unspentid, nOut); std::vector pkData( ParseHexUV(prevOut["scriptPubKey"], "scriptPubKey")); CScript scriptPubKey(pkData.begin(), pkData.end()); @@ -763,7 +764,7 @@ static void OutputTxHash(const CTransaction &tx) { // the hex-encoded transaction id. - std::string strHexHash = tx.GetId().GetHex(); + std::string strHexHash = tx.GetHash().GetHex(); fprintf(stdout, "%s\n", strHexHash.c_str()); } @@ -777,7 +778,7 @@ static void OutputTx(const CTransaction &tx) { if (GetBoolArg("-json", false)) { OutputTxJSON(tx); - } else if (GetBoolArg("-txid", false)) { + } else if (GetBoolArg("-txhash", false)) { OutputTxHash(tx); } else { OutputTxHex(tx); diff --git a/src/blockencodings.h b/src/blockencodings.h --- a/src/blockencodings.h +++ b/src/blockencodings.h @@ -106,10 +106,11 @@ } }; -// Dumb serialization/storage-helper for CBlockHeaderAndShortTxIDs and +// Dumb serialization/storage-helper for CBlockHeaderAndShortTxHashes and // PartiallyDownloadedBlock struct PrefilledTransaction { - // Used as an offset since last prefilled tx in CBlockHeaderAndShortTxIDs, + // Used as an offset since last prefilled tx in + // CBlockHeaderAndShortTxHashes, // as a proper transaction-in-block-index in PartiallyDownloadedBlock uint16_t index; CTransactionRef tx; @@ -138,33 +139,33 @@ READ_STATUS_CHECKBLOCK_FAILED, } ReadStatus; -class CBlockHeaderAndShortTxIDs { +class CBlockHeaderAndShortTxHashes { private: - mutable uint64_t shorttxidk0, shorttxidk1; + mutable uint64_t shorttxhashk0, shorttxhashk1; uint64_t nonce; - void FillShortTxIDSelector() const; + void FillShortTxHashSelector() const; friend class PartiallyDownloadedBlock; - static const int SHORTTXIDS_LENGTH = 6; + static const int SHORTTXHASHES_LENGTH = 6; protected: - std::vector shorttxids; + std::vector shortTxHashes; std::vector prefilledtxn; public: CBlockHeader header; // Dummy for deserialization - CBlockHeaderAndShortTxIDs() {} + CBlockHeaderAndShortTxHashes() {} - CBlockHeaderAndShortTxIDs(const CBlock &block); + CBlockHeaderAndShortTxHashes(const CBlock &block); uint64_t GetShortID(const uint256 &txhash) const; size_t BlockTxCount() const { - return shorttxids.size() + prefilledtxn.size(); + return shortTxHashes.size() + prefilledtxn.size(); } ADD_SERIALIZE_METHODS; @@ -174,28 +175,29 @@ READWRITE(header); READWRITE(nonce); - uint64_t shorttxids_size = (uint64_t)shorttxids.size(); - READWRITE(COMPACTSIZE(shorttxids_size)); + uint64_t shortTxHashes_size = (uint64_t)shortTxHashes.size(); + READWRITE(COMPACTSIZE(shortTxHashes_size)); if (ser_action.ForRead()) { size_t i = 0; - while (shorttxids.size() < shorttxids_size) { - shorttxids.resize(std::min((uint64_t)(1000 + shorttxids.size()), - shorttxids_size)); - for (; i < shorttxids.size(); i++) { + while (shortTxHashes.size() < shortTxHashes_size) { + shortTxHashes.resize( + std::min((uint64_t)(1000 + shortTxHashes.size()), + shortTxHashes_size)); + for (; i < shortTxHashes.size(); i++) { uint32_t lsb = 0; uint16_t msb = 0; READWRITE(lsb); READWRITE(msb); - shorttxids[i] = (uint64_t(msb) << 32) | uint64_t(lsb); - static_assert( - SHORTTXIDS_LENGTH == 6, - "shorttxids serialization assumes 6-byte shorttxids"); + shortTxHashes[i] = (uint64_t(msb) << 32) | uint64_t(lsb); + static_assert(SHORTTXHASHES_LENGTH == 6, + "shortTxHashes serialization assumes 6-byte " + "shortTxHashes"); } } } else { - for (size_t i = 0; i < shorttxids.size(); i++) { - uint32_t lsb = shorttxids[i] & 0xffffffff; - uint16_t msb = (shorttxids[i] >> 32) & 0xffff; + for (size_t i = 0; i < shortTxHashes.size(); i++) { + uint32_t lsb = shortTxHashes[i] & 0xffffffff; + uint16_t msb = (shortTxHashes[i] >> 32) & 0xffff; READWRITE(lsb); READWRITE(msb); } @@ -203,7 +205,7 @@ READWRITE(prefilledtxn); - if (ser_action.ForRead()) FillShortTxIDSelector(); + if (ser_action.ForRead()) FillShortTxHashSelector(); } }; @@ -222,7 +224,7 @@ // extra_txn is a list of extra transactions to look at, in form. ReadStatus - InitData(const CBlockHeaderAndShortTxIDs &cmpctblock, + InitData(const CBlockHeaderAndShortTxHashes &cmpctblock, const std::vector> &extra_txn); bool IsTxAvailable(size_t index) const; ReadStatus FillBlock(CBlock &block, diff --git a/src/blockencodings.cpp b/src/blockencodings.cpp --- a/src/blockencodings.cpp +++ b/src/blockencodings.cpp @@ -16,43 +16,44 @@ #include -CBlockHeaderAndShortTxIDs::CBlockHeaderAndShortTxIDs(const CBlock &block) +CBlockHeaderAndShortTxHashes::CBlockHeaderAndShortTxHashes(const CBlock &block) : nonce(GetRand(std::numeric_limits::max())), - shorttxids(block.vtx.size() - 1), prefilledtxn(1), header(block) { - FillShortTxIDSelector(); + shortTxHashes(block.vtx.size() - 1), prefilledtxn(1), header(block) { + FillShortTxHashSelector(); // TODO: Use our mempool prior to block acceptance to predictively fill more // than just the coinbase. prefilledtxn[0] = {0, block.vtx[0]}; for (size_t i = 1; i < block.vtx.size(); i++) { const CTransaction &tx = *block.vtx[i]; - shorttxids[i - 1] = GetShortID(tx.GetHash()); + shortTxHashes[i - 1] = GetShortID(tx.GetHash()); } } -void CBlockHeaderAndShortTxIDs::FillShortTxIDSelector() const { +void CBlockHeaderAndShortTxHashes::FillShortTxHashSelector() const { CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); stream << header << nonce; CSHA256 hasher; hasher.Write((uint8_t *)&(*stream.begin()), stream.end() - stream.begin()); - uint256 shorttxidhash; - hasher.Finalize(shorttxidhash.begin()); - shorttxidk0 = shorttxidhash.GetUint64(0); - shorttxidk1 = shorttxidhash.GetUint64(1); + uint256 shorttxhash; + hasher.Finalize(shorttxhash.begin()); + shorttxhashk0 = shorttxhash.GetUint64(0); + shorttxhashk1 = shorttxhash.GetUint64(1); } -uint64_t CBlockHeaderAndShortTxIDs::GetShortID(const uint256 &txhash) const { - static_assert(SHORTTXIDS_LENGTH == 6, - "shorttxids calculation assumes 6-byte shorttxids"); - return SipHashUint256(shorttxidk0, shorttxidk1, txhash) & 0xffffffffffffL; +uint64_t CBlockHeaderAndShortTxHashes::GetShortID(const uint256 &txhash) const { + static_assert(SHORTTXHASHES_LENGTH == 6, + "shorttxhashes calculation assumes 6-byte shorttxhashes"); + return SipHashUint256(shorttxhashk0, shorttxhashk1, txhash) & + 0xffffffffffffL; } ReadStatus PartiallyDownloadedBlock::InitData( - const CBlockHeaderAndShortTxIDs &cmpctblock, + const CBlockHeaderAndShortTxHashes &cmpctblock, const std::vector> &extra_txn) { if (cmpctblock.header.IsNull() || - (cmpctblock.shorttxids.empty() && cmpctblock.prefilledtxn.empty())) + (cmpctblock.shortTxHashes.empty() && cmpctblock.prefilledtxn.empty())) return READ_STATUS_INVALID; - if (cmpctblock.shorttxids.size() + cmpctblock.prefilledtxn.size() > + if (cmpctblock.shortTxHashes.size() + cmpctblock.prefilledtxn.size() > config->GetMaxBlockSize() / MIN_TRANSACTION_SIZE) return READ_STATUS_INVALID; @@ -68,31 +69,34 @@ lastprefilledindex += cmpctblock.prefilledtxn[i].index + 1; if (lastprefilledindex > std::numeric_limits::max()) return READ_STATUS_INVALID; - if ((uint32_t)lastprefilledindex > cmpctblock.shorttxids.size() + i) { + if ((uint32_t)lastprefilledindex > + cmpctblock.shortTxHashes.size() + i) { // If we are inserting a tx at an index greater than our full list - // of shorttxids plus the number of prefilled txn we've inserted, + // of shortTxHashes plus the number of prefilled txn we've inserted, // then we have txn for which we have neither a prefilled txn or a - // shorttxid! + // shorttxhash! return READ_STATUS_INVALID; } txn_available[lastprefilledindex] = cmpctblock.prefilledtxn[i].tx; } prefilled_count = cmpctblock.prefilledtxn.size(); - // Calculate map of txids -> positions and check mempool to see what we have + // Calculate map of txhashes -> positions and check mempool to see what we + // have // (or don't). Because well-formed cmpctblock messages will have a // (relatively) uniform distribution of short IDs, any highly-uneven // distribution of elements can be safely treated as a READ_STATUS_FAILED. - std::unordered_map shorttxids( - cmpctblock.shorttxids.size()); + std::unordered_map shorttxhashes( + cmpctblock.shortTxHashes.size()); uint16_t index_offset = 0; - for (size_t i = 0; i < cmpctblock.shorttxids.size(); i++) { + for (size_t i = 0; i < cmpctblock.shortTxHashes.size(); i++) { while (txn_available[i + index_offset]) index_offset++; - shorttxids[cmpctblock.shorttxids[i]] = i + index_offset; + shorttxhashes[cmpctblock.shortTxHashes[i]] = i + index_offset; // To determine the chance that the number of entries in a bucket // exceeds N, we use the fact that the number of elements in a single - // bucket is binomially distributed (with n = the number of shorttxids + // bucket is binomially distributed (with n = the number of + // shorttxhashes // S, and p = 1 / the number of buckets), that in the worst case the // number of buckets is equal to S (due to std::unordered_map having a // default load factor of 1.0), and that the chance for any bucket to @@ -101,14 +105,14 @@ // S * (1 - cdf(binomial(n=S,p=1/S), N)). If we assume blocks of up to // 16000, allowing 12 elements per bucket should only fail once per ~1 // million block transfers (per peer and connection). - if (shorttxids.bucket_size( - shorttxids.bucket(cmpctblock.shorttxids[i])) > 12) + if (shorttxhashes.bucket_size( + shorttxhashes.bucket(cmpctblock.shortTxHashes[i])) > 12) return READ_STATUS_FAILED; } // TODO: in the shortid-collision case, we should instead request both // transactions which collided. Falling back to full-block-request here is // overkill. - if (shorttxids.size() != cmpctblock.shorttxids.size()) { + if (shorttxhashes.size() != cmpctblock.shortTxHashes.size()) { // Short ID collision return READ_STATUS_FAILED; } @@ -116,13 +120,13 @@ std::vector have_txn(txn_available.size()); { LOCK(pool->cs); - const std::vector> &vTxHashes = + const std::vector> &vTxHashes = pool->vTxHashes; for (size_t i = 0; i < vTxHashes.size(); i++) { uint64_t shortid = cmpctblock.GetShortID(vTxHashes[i].first); std::unordered_map::iterator idit = - shorttxids.find(shortid); - if (idit != shorttxids.end()) { + shorttxhashes.find(shortid); + if (idit != shorttxhashes.end()) { if (!have_txn[idit->second]) { txn_available[idit->second] = vTxHashes[i].second->GetSharedTx(); @@ -142,15 +146,15 @@ // Though ideally we'd continue scanning for the // two-txn-match-shortid case, the performance win of an early exit // here is too good to pass up and worth the extra risk. - if (mempool_count == shorttxids.size()) break; + if (mempool_count == shorttxhashes.size()) break; } } for (size_t i = 0; i < extra_txn.size(); i++) { uint64_t shortid = cmpctblock.GetShortID(extra_txn[i].first); std::unordered_map::iterator idit = - shorttxids.find(shortid); - if (idit != shorttxids.end()) { + shorttxhashes.find(shortid); + if (idit != shorttxhashes.end()) { if (!have_txn[idit->second]) { txn_available[idit->second] = extra_txn[i].second; have_txn[idit->second] = true; @@ -176,7 +180,7 @@ // Though ideally we'd continue scanning for the two-txn-match-shortid // case, the performance win of an early exit here is too good to pass // up and worth the extra risk. - if (mempool_count == shorttxids.size()) break; + if (mempool_count == shorttxhashes.size()) break; } LogPrint("cmpctblock", "Initialized PartiallyDownloadedBlock for block %s " @@ -237,7 +241,7 @@ if (vtx_missing.size() < 5) { for (const auto &tx : vtx_missing) LogPrint("cmpctblock", "Reconstructed block %s required tx %s\n", - hash.ToString(), tx->GetId().ToString()); + hash.ToString(), tx->GetHash().ToString()); } return READ_STATUS_OK; diff --git a/src/bloom.cpp b/src/bloom.cpp --- a/src/bloom.cpp +++ b/src/bloom.cpp @@ -124,8 +124,8 @@ // appear in a block if (isFull) return true; if (isEmpty) return false; - const uint256 &txid = tx.GetId(); - if (contains(txid)) fFound = true; + const uint256 &txhash = tx.GetHash(); + if (contains(txhash)) fFound = true; for (unsigned int i = 0; i < tx.vout.size(); i++) { const CTxOut &txout = tx.vout[i]; @@ -143,14 +143,14 @@ if (data.size() != 0 && contains(data)) { fFound = true; if ((nFlags & BLOOM_UPDATE_MASK) == BLOOM_UPDATE_ALL) - insert(COutPoint(txid, i)); + insert(COutPoint((unspentid_t)txhash, i)); else if ((nFlags & BLOOM_UPDATE_MASK) == BLOOM_UPDATE_P2PUBKEY_ONLY) { txnouttype type; std::vector> vSolutions; if (Solver(txout.scriptPubKey, type, vSolutions) && (type == TX_PUBKEY || type == TX_MULTISIG)) - insert(COutPoint(txid, i)); + insert(COutPoint((unspentid_t)txhash, i)); } break; } diff --git a/src/chain.h b/src/chain.h --- a/src/chain.h +++ b/src/chain.h @@ -128,7 +128,7 @@ /** * Only first tx is coinbase, 2 <= coinbase input script length <= 100, - * transactions valid, no duplicate txids, sigops, size, merkle root. + * transactions valid, no duplicate txhashes, sigops, size, merkle root. * Implies all parents are at least TREE but not necessarily TRANSACTIONS. * When all parent blocks also have TRANSACTIONS, CBlockIndex::nChainTx will * be set. diff --git a/src/coins.h b/src/coins.h --- a/src/coins.h +++ b/src/coins.h @@ -87,7 +87,7 @@ * implementation. */ size_t operator()(const COutPoint &outpoint) const { - return SipHashUint256Extra(k0, k1, outpoint.hash, outpoint.n); + return SipHashUint256Extra(k0, k1, outpoint.unspentid, outpoint.n); } }; @@ -292,7 +292,4 @@ // (pre-BIP34) cases. void AddCoins(CCoinsViewCache &cache, const CTransaction &tx, int nHeight); -//! Utility function to find any unspent output with a given txid. -const Coin &AccessByTxid(const CCoinsViewCache &cache, const uint256 &txid); - #endif // BITCOIN_COINS_H diff --git a/src/coins.cpp b/src/coins.cpp --- a/src/coins.cpp +++ b/src/coins.cpp @@ -124,13 +124,13 @@ void AddCoins(CCoinsViewCache &cache, const CTransaction &tx, int nHeight) { bool fCoinbase = tx.IsCoinBase(); - const uint256 &txid = tx.GetHash(); + const unspentid_t &unspentid = tx.GetUnspentid(); for (size_t i = 0; i < tx.vout.size(); ++i) { // Pass fCoinbase as the possible_overwrite flag to AddCoin, in order to // correctly deal with the pre-BIP30 occurrances of duplicate coinbase // transactions. - cache.AddCoin(COutPoint(txid, i), Coin(tx.vout[i], nHeight, fCoinbase), - fCoinbase); + cache.AddCoin(COutPoint(unspentid, i), + Coin(tx.vout[i], nHeight, fCoinbase), fCoinbase); } } @@ -318,20 +318,3 @@ } return tx.ComputePriority(dResult); } - -// TODO: merge with similar definition in undo.h. -static const size_t MAX_OUTPUTS_PER_TX = - MAX_TX_SIZE / ::GetSerializeSize(CTxOut(), SER_NETWORK, PROTOCOL_VERSION); - -const Coin &AccessByTxid(const CCoinsViewCache &view, const uint256 &txid) { - COutPoint iter(txid, 0); - while (iter.n < MAX_OUTPUTS_PER_TX) { - const Coin &alternate = view.AccessCoin(iter); - if (!alternate.IsSpent()) { - return alternate; - } - ++iter.n; - } - - return coinEmpty; -} diff --git a/src/consensus/merkle.cpp b/src/consensus/merkle.cpp --- a/src/consensus/merkle.cpp +++ b/src/consensus/merkle.cpp @@ -9,7 +9,7 @@ /* WARNING! If you're reading this because you're learning about crypto and/or designing a new system that will use merkle trees, keep in mind that the following merkle tree algorithm has a serious flaw related to - duplicate txids, resulting in a vulnerability (CVE-2012-2459). + duplicate txhashes, resulting in a vulnerability (CVE-2012-2459). The reason is that if the number of hashes in the list at a given time is odd, the last one is duplicated before computing the next level (which @@ -176,7 +176,7 @@ std::vector leaves; leaves.resize(block.vtx.size()); for (size_t s = 0; s < block.vtx.size(); s++) { - leaves[s] = block.vtx[s]->GetId(); + leaves[s] = block.vtx[s]->GetHash(); } return ComputeMerkleRoot(leaves, mutated); } @@ -185,7 +185,7 @@ std::vector leaves; leaves.resize(block.vtx.size()); for (size_t s = 0; s < block.vtx.size(); s++) { - leaves[s] = block.vtx[s]->GetId(); + leaves[s] = block.vtx[s]->GetHash(); } return ComputeMerkleBranch(leaves, position); } diff --git a/src/core_write.cpp b/src/core_write.cpp --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -183,7 +183,7 @@ void TxToUniv(const CTransaction &tx, const uint256 &hashBlock, UniValue &entry) { - entry.pushKV("txid", tx.GetId().GetHex()); + entry.pushKV("unspentid", tx.Getunspentid().GetHex()); entry.pushKV("hash", tx.GetHash().GetHex()); entry.pushKV("version", tx.nVersion); entry.pushKV("locktime", (int64_t)tx.nLockTime); @@ -196,7 +196,7 @@ in.pushKV("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())); } else { - in.pushKV("txid", txin.prevout.hash.GetHex()); + in.pushKV("unspentid", txin.prevout.unspentid.GetHex()); in.pushKV("vout", (int64_t)txin.prevout.n); UniValue o(UniValue::VOBJ); o.pushKV("asm", ScriptToAsmStr(txin.scriptSig, true)); diff --git a/src/merkleblock.h b/src/merkleblock.h --- a/src/merkleblock.h +++ b/src/merkleblock.h @@ -16,13 +16,13 @@ /** * Data structure that represents a partial merkle tree. * - * It represents a subset of the txid's of a known block, in a way that - * allows recovery of the list of txid's and the merkle root, in an + * It represents a subset of the txhashes of a known block, in a way that + * allows recovery of the list of txhashes and the merkle root, in an * authenticated way. * * The encoding works as follows: we traverse the tree in depth-first order, * storing a bit for each traversed node, signifying whether the node is the - * parent of at least one matched leaf txid (or a matched txid itself). In + * parent of at least one matched leaf txhash (or a matched txhash itself). In * case we are at the leaf level, or this bit is 0, its merkle node hash is * stored, and its children are not explorer further. Otherwise, no hash is * stored, but we recurse into both (or the only) child branch. During @@ -54,10 +54,10 @@ /** the total number of transactions in the block */ unsigned int nTransactions; - /** node-is-parent-of-matched-txid bits */ + /** node-is-parent-of-matched-txhash bits */ std::vector vBits; - /** txids and internal hashes */ + /** txhashes and internal hashes */ std::vector vHash; /** flag set when encountering invalid data */ @@ -70,14 +70,14 @@ } /** Calculate the hash of a node in the merkle tree (at leaf level: the - * txid's themselves) */ + * txhashes themselves) */ uint256 CalcHash(int height, unsigned int pos, - const std::vector &vTxid); + const std::vector &vTxhash); /** Recursive function that traverses tree nodes, storing the data as bits * and hashes. */ void TraverseAndBuild(int height, unsigned int pos, - const std::vector &vTxid, + const std::vector &vTxhash, const std::vector &vMatch); /** @@ -116,13 +116,13 @@ /** Construct a partial merkle tree from a list of transaction ids, and a * mask that selects a subset of them. */ - CPartialMerkleTree(const std::vector &vTxid, + CPartialMerkleTree(const std::vector &vTxhash, const std::vector &vMatch); CPartialMerkleTree(); /** - * Extract the matching txid's represented by this partial merkle tree and + * Extract the matching txhashes represented by this partial merkle tree and * their respective indices within the partial tree. Returns the merkle * root, or 0 in case of failure */ @@ -151,8 +151,8 @@ */ CMerkleBlock(const CBlock &block, CBloomFilter &filter); - // Create from a CBlock, matching the txids in the set. - CMerkleBlock(const CBlock &block, const std::set &txids); + // Create from a CBlock, matching the txhashes in the set. + CMerkleBlock(const CBlock &block, const std::set &txhashes); CMerkleBlock() {} diff --git a/src/merkleblock.cpp b/src/merkleblock.cpp --- a/src/merkleblock.cpp +++ b/src/merkleblock.cpp @@ -19,20 +19,20 @@ vHashes.reserve(block.vtx.size()); for (unsigned int i = 0; i < block.vtx.size(); i++) { - const uint256 &txid = block.vtx[i]->GetId(); + const uint256 &txhash = block.vtx[i]->GetHash(); if (filter.IsRelevantAndUpdate(*block.vtx[i])) { vMatch.push_back(true); - vMatchedTxn.push_back(std::make_pair(i, txid)); + vMatchedTxn.push_back(std::make_pair(i, txhash)); } else vMatch.push_back(false); - vHashes.push_back(txid); + vHashes.push_back(txhash); } txn = CPartialMerkleTree(vHashes, vMatch); } CMerkleBlock::CMerkleBlock(const CBlock &block, - const std::set &txids) { + const std::set &txhashes) { header = block.GetBlockHeader(); std::vector vMatch; @@ -42,29 +42,29 @@ vHashes.reserve(block.vtx.size()); for (unsigned int i = 0; i < block.vtx.size(); i++) { - const uint256 &txid = block.vtx[i]->GetId(); - if (txids.count(txid)) + const txhash_t &txhash = block.vtx[i]->GetHash(); + if (txhashes.count(txhash)) vMatch.push_back(true); else vMatch.push_back(false); - vHashes.push_back(txid); + vHashes.push_back(txhash); } txn = CPartialMerkleTree(vHashes, vMatch); } uint256 CPartialMerkleTree::CalcHash(int height, unsigned int pos, - const std::vector &vTxid) { + const std::vector &vTxhash) { if (height == 0) { - // hash at height 0 is the txids themself. - return vTxid[pos]; + // hash at height 0 is the txhashes themself. + return vTxhash[pos]; } else { // Calculate left hash. - uint256 left = CalcHash(height - 1, pos * 2, vTxid), right; + uint256 left = CalcHash(height - 1, pos * 2, vTxhash), right; // Calculate right hash if not beyond the end of the array - copy left // hash otherwise1. if (pos * 2 + 1 < CalcTreeWidth(height - 1)) { - right = CalcHash(height - 1, pos * 2 + 1, vTxid); + right = CalcHash(height - 1, pos * 2 + 1, vTxhash); } else { right = left; } @@ -74,9 +74,9 @@ } void CPartialMerkleTree::TraverseAndBuild(int height, unsigned int pos, - const std::vector &vTxid, + const std::vector &vTxhash, const std::vector &vMatch) { - // Determine whether this node is the parent of at least one matched txid. + // Determine whether this node is the parent of at least one matched txhash. bool fParentOfMatch = false; for (unsigned int p = pos << height; p < (pos + 1) << height && p < nTransactions; p++) @@ -85,12 +85,12 @@ vBits.push_back(fParentOfMatch); if (height == 0 || !fParentOfMatch) { // If at height 0, or nothing interesting below, store hash and stop. - vHash.push_back(CalcHash(height, pos, vTxid)); + vHash.push_back(CalcHash(height, pos, vTxhash)); } else { // Otherwise, don't store any hash, but descend into the subtrees. - TraverseAndBuild(height - 1, pos * 2, vTxid, vMatch); + TraverseAndBuild(height - 1, pos * 2, vTxhash, vMatch); if (pos * 2 + 1 < CalcTreeWidth(height - 1)) - TraverseAndBuild(height - 1, pos * 2 + 1, vTxid, vMatch); + TraverseAndBuild(height - 1, pos * 2 + 1, vTxhash, vMatch); } } @@ -113,14 +113,14 @@ return uint256(); } const uint256 &hash = vHash[nHashUsed++]; - // In case of height 0, we have a matched txid. + // In case of height 0, we have a matched txhash. if (height == 0 && fParentOfMatch) { vMatch.push_back(hash); vnIndex.push_back(pos); } return hash; } else { - // Otherwise, descend into the subtrees to extract matched txids and + // Otherwise, descend into the subtrees to extract matched txhashes and // hashes. uint256 left = TraverseAndExtract(height - 1, pos * 2, nBitsUsed, nHashUsed, vMatch, vnIndex), @@ -141,9 +141,9 @@ } } -CPartialMerkleTree::CPartialMerkleTree(const std::vector &vTxid, +CPartialMerkleTree::CPartialMerkleTree(const std::vector &vTxhashes, const std::vector &vMatch) - : nTransactions(vTxid.size()), fBad(false) { + : nTransactions(vTxhashes.size()), fBad(false) { // reset state vBits.clear(); vHash.clear(); @@ -154,7 +154,7 @@ nHeight++; // traverse the partial tree - TraverseAndBuild(nHeight, 0, vTxid, vMatch); + TraverseAndBuild(nHeight, 0, vTxhashes, vMatch); } CPartialMerkleTree::CPartialMerkleTree() : nTransactions(0), fBad(true) {} @@ -167,7 +167,7 @@ // Check for excessively high numbers of transactions. // FIXME: Track the maximum block size we've seen and use it here. - // There can never be more hashes provided than one for every txid. + // There can never be more hashes provided than one for every txhash. if (vHash.size() > nTransactions) return uint256(); // There must be at least one bit per node in the partial tree, and at least // one node per hash. diff --git a/src/miner.cpp b/src/miner.cpp --- a/src/miner.cpp +++ b/src/miner.cpp @@ -349,11 +349,11 @@ if (fPrintPriority) { double dPriority = iter->GetPriority(nHeight); Amount dummy; - mempool.ApplyDeltas(iter->GetTx().GetId(), dPriority, dummy); + mempool.ApplyDeltas(iter->GetTx().GetHash(), dPriority, dummy); LogPrintf( - "priority %.1f fee %s txid %s\n", dPriority, + "priority %.1f fee %s txhash %s\n", dPriority, CFeeRate(iter->GetModifiedFee(), iter->GetTxSize()).ToString(), - iter->GetTx().GetId().ToString()); + iter->GetTx().GetHash().ToString()); } } @@ -582,7 +582,7 @@ mi != mempool.mapTx.end(); ++mi) { double dPriority = mi->GetPriority(nHeight); Amount dummy; - mempool.ApplyDeltas(mi->GetTx().GetId(), dPriority, dummy); + mempool.ApplyDeltas(mi->GetTx().GetHash(), dPriority, dummy); vecPriority.push_back(TxCoinAgePriority(dPriority, mi)); } std::make_heap(vecPriority.begin(), vecPriority.end(), pricomparer); diff --git a/src/net.h b/src/net.h --- a/src/net.h +++ b/src/net.h @@ -16,6 +16,7 @@ #include "hash.h" #include "limitedmap.h" #include "netaddress.h" +#include "primitives/transaction.h" #include "protocol.h" #include "random.h" #include "streams.h" @@ -668,7 +669,7 @@ CRollingBloomFilter filterInventoryKnown; // Set of transaction ids we still have to announce. They are sorted by the // mempool before relay, so the order is not important. - std::set setInventoryTxToSend; + std::set setInventoryTxToSend; // List of block ids we still have announce. There is no final sorting // before sending, as they are always sent immediately and in the order // requested. @@ -795,8 +796,9 @@ void PushInventory(const CInv &inv) { LOCK(cs_inventory); if (inv.type == MSG_TX) { - if (!filterInventoryKnown.contains(inv.hash)) { - setInventoryTxToSend.insert(inv.hash); + const txhash_t txhash(inv.hash); + if (!filterInventoryKnown.contains(txhash)) { + setInventoryTxToSend.insert(txhash); } } else if (inv.type == MSG_BLOCK) { vInventoryBlockToSend.push_back(inv.hash); diff --git a/src/net_processing.cpp b/src/net_processing.cpp --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -726,8 +726,8 @@ bool AddOrphanTx(const CTransactionRef &tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { - const uint256 &txid = tx->GetId(); - if (mapOrphanTransactions.count(txid)) { + const uint256 &txhash = tx->GetHash(); + if (mapOrphanTransactions.count(txhash)) { return false; } @@ -740,12 +740,12 @@ unsigned int sz = GetTransactionSize(*tx); if (sz >= MAX_STANDARD_TX_SIZE) { LogPrint("mempool", "ignoring large orphan tx (size: %u, hash: %s)\n", - sz, txid.ToString()); + sz, txhash.ToString()); return false; } auto ret = mapOrphanTransactions.emplace( - txid, COrphanTx{tx, peer, GetTime() + ORPHAN_TX_EXPIRE_TIME}); + txhash, COrphanTx{tx, peer, GetTime() + ORPHAN_TX_EXPIRE_TIME}); assert(ret.second); for (const CTxIn &txin : tx->vin) { mapOrphanTransactionsByPrev[txin.prevout].insert(ret.first); @@ -754,7 +754,7 @@ AddToCompactExtraTransactions(tx); LogPrint("mempool", "stored orphan tx %s (mapsz %u outsz %u)\n", - txid.ToString(), mapOrphanTransactions.size(), + txhash.ToString(), mapOrphanTransactions.size(), mapOrphanTransactionsByPrev.size()); return true; } @@ -786,7 +786,7 @@ // Increment to avoid iterator becoming invalid. std::map::iterator maybeErase = iter++; if (maybeErase->second.fromPeer == peer) { - nErased += EraseOrphanTx(maybeErase->second.tx->GetId()); + nErased += EraseOrphanTx(maybeErase->second.tx->GetHash()); } } if (nErased > 0) { @@ -810,7 +810,7 @@ while (iter != mapOrphanTransactions.end()) { std::map::iterator maybeErase = iter++; if (maybeErase->second.nTimeExpire <= nNow) { - nErased += EraseOrphanTx(maybeErase->second.tx->GetId()); + nErased += EraseOrphanTx(maybeErase->second.tx->GetHash()); } else { nMinExpTime = std::min(maybeErase->second.nTimeExpire, nMinExpTime); @@ -900,7 +900,7 @@ for (auto mi = itByPrev->second.begin(); mi != itByPrev->second.end(); ++mi) { const CTransaction &orphanTx = *(*mi)->second.tx; - const uint256 &orphanId = orphanTx.GetId(); + const uint256 &orphanId = orphanTx.GetHash(); vOrphanErase.push_back(orphanId); } } @@ -919,14 +919,14 @@ static CCriticalSection cs_most_recent_block; static std::shared_ptr most_recent_block; -static std::shared_ptr +static std::shared_ptr most_recent_compact_block; static uint256 most_recent_block_hash; void PeerLogicValidation::NewPoWValidBlock( const CBlockIndex *pindex, const std::shared_ptr &pblock) { - std::shared_ptr pcmpctblock = - std::make_shared(*pblock); + std::shared_ptr pcmpctblock = + std::make_shared(*pblock); const CNetMsgMaker msgMaker(PROTOCOL_VERSION); LOCK(cs_main); @@ -1055,6 +1055,9 @@ static bool AlreadyHave(const CInv &inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { switch (inv.type) { case MSG_TX: { + + const txhash_t txhash(inv.hash); + assert(recentRejects); if (chainActive.Tip()->GetBlockHash() != hashRecentRejectsChainTip) { @@ -1078,7 +1081,7 @@ } static void RelayTransaction(const CTransaction &tx, CConnman &connman) { - CInv inv(MSG_TX, tx.GetId()); + CInv inv(MSG_TX, tx.GetHash()); connman.ForEachNode([&inv](CNode *pnode) { pnode->PushInventory(inv); }); } @@ -1275,7 +1278,7 @@ if (CanDirectFetch(consensusParams) && mi->second->nHeight >= chainActive.Height() - MAX_CMPCTBLOCK_DEPTH) { - CBlockHeaderAndShortTxIDs cmpctblock(block); + CBlockHeaderAndShortTxHashes cmpctblock(block); connman.PushMessage( pfrom, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, @@ -1302,6 +1305,8 @@ } } } else if (inv.type == MSG_TX) { + + const txhash_t txhash(inv.hash); // Send stream from relay memory bool push = false; auto mi = mapRelay.find(inv.hash); @@ -1312,7 +1317,7 @@ msgMaker.Make(nSendFlags, NetMsgType::TX, *mi->second)); push = true; } else if (pfrom->timeLastMempoolReq) { - auto txinfo = mempool.info(inv.hash); + auto txinfo = mempool.info(txhash); // To protect privacy, do not answer getdata using the // mempool when that TX couldn't have been INVed in reply to // a MEMPOOL request. @@ -2062,9 +2067,11 @@ vRecv >> ptx; const CTransaction &tx = *ptx; - CInv inv(MSG_TX, tx.GetId()); + CInv inv(MSG_TX, tx.GetHash()); pfrom->AddInventoryKnown(inv); + const unspentid_t &unspentid = tx.Getunspentid(); + LOCK(cs_main); bool fMissingInputs = false; @@ -2081,14 +2088,14 @@ mempool.check(pcoinsTip); RelayTransaction(tx, connman); for (size_t i = 0; i < tx.vout.size(); i++) { - vWorkQueue.emplace_back(inv.hash, i); + vWorkQueue.emplace_back(unspentid, i); } pfrom->nLastTXTime = GetTime(); LogPrint("mempool", "AcceptToMemoryPool: peer=%d: accepted %s " "(poolsz %u txn, %u kB)\n", - pfrom->id, tx.GetId().ToString(), mempool.size(), + pfrom->id, tx.GetHash().ToString(), mempool.size(), mempool.DynamicMemoryUsage() / 1000); // Recursively process any orphan transactions that depended on this @@ -2105,7 +2112,10 @@ mi != itByPrev->second.end(); ++mi) { const CTransactionRef &porphanTx = (*mi)->second.tx; const CTransaction &orphanTx = *porphanTx; - const uint256 &orphanId = orphanTx.GetId(); + const uint256 &orphanId = orphanTx.GetHash(); + const unspentid_t &orphanunspentid = + orphanTx.Getunspentid(); + NodeId fromPeer = (*mi)->second.fromPeer; bool fMissingInputs2 = false; // Use a dummy CValidationState so someone can't setup nodes @@ -2121,10 +2131,10 @@ porphanTx, true, &fMissingInputs2, &lRemovedTxn)) { LogPrint("mempool", " accepted orphan tx %s\n", - orphanId.ToString()); + orphanunspentid.ToString()); RelayTransaction(orphanTx, connman); for (size_t i = 0; i < orphanTx.vout.size(); i++) { - vWorkQueue.emplace_back(orphanId, i); + vWorkQueue.emplace_back(orphanunspentid, i); } vEraseQueue.push_back(orphanId); } else if (!fMissingInputs2) { @@ -2163,7 +2173,7 @@ // rejected. bool fRejectedParents = false; for (const CTxIn &txin : tx.vin) { - if (recentRejects->contains(txin.prevout.hash)) { + if (recentRejects->contains(txin.prevout.unspentid)) { fRejectedParents = true; break; } @@ -2172,7 +2182,7 @@ uint32_t nFetchFlags = GetFetchFlags( pfrom, chainActive.Tip(), chainparams.GetConsensus()); for (const CTxIn &txin : tx.vin) { - CInv _inv(MSG_TX | nFetchFlags, txin.prevout.hash); + CInv _inv(MSG_TX | nFetchFlags, txin.prevout.unspentid); pfrom->AddInventoryKnown(_inv); if (!AlreadyHave(_inv)) { pfrom->AskFor(_inv); @@ -2193,10 +2203,10 @@ } else { LogPrint("mempool", "not keeping orphan with rejected parents %s\n", - tx.GetId().ToString()); + tx.GetHash().ToString()); // We will continue to reject this tx since it has rejected // parents so avoid re-requesting it from other peers. - recentRejects->insert(tx.GetId()); + recentRejects->insert(tx.GetHash()); } } else { if (!state.CorruptionPossible()) { @@ -2205,7 +2215,7 @@ // malleated. See https://github.com/bitcoin/bitcoin/issues/8279 // for details. assert(recentRejects); - recentRejects->insert(tx.GetId()); + recentRejects->insert(inv.hash); if (RecursiveDynamicUsage(*ptx) < 100000) { AddToCompactExtraTransactions(ptx); } @@ -2225,12 +2235,12 @@ int nDoS = 0; if (!state.IsInvalid(nDoS) || nDoS == 0) { LogPrintf("Force relaying tx %s from whitelisted peer=%d\n", - tx.GetId().ToString(), pfrom->id); + tx.GetHash().ToString(), pfrom->id); RelayTransaction(tx, connman); } else { LogPrintf("Not relaying invalid transaction %s from " "whitelisted peer=%d (%s)\n", - tx.GetId().ToString(), pfrom->id, + tx.GetHash().ToString(), pfrom->id, FormatStateMessage(state)); } } @@ -2243,7 +2253,7 @@ int nDoS = 0; if (state.IsInvalid(nDoS)) { LogPrint("mempoolrej", "%s from peer=%d was not accepted: %s\n", - tx.GetId().ToString(), pfrom->id, + tx.GetHash().ToString(), pfrom->id, FormatStateMessage(state)); // Never send AcceptToMemoryPool's internal codes over P2P. if (state.GetRejectCode() < REJECT_INTERNAL) { @@ -2262,7 +2272,7 @@ // Ignore blocks received while importing else if (strCommand == NetMsgType::CMPCTBLOCK && !fImporting && !fReindex) { - CBlockHeaderAndShortTxIDs cmpctblock; + CBlockHeaderAndShortTxHashes cmpctblock; vRecv >> cmpctblock; { @@ -2299,7 +2309,7 @@ } } - // When we succeed in decoding a block's txids from a cmpctblock + // When we succeed in decoding a block's txhashes from a cmpctblock // message we typically jump to the BLOCKTXN handling code, with a // dummy (empty) BLOCKTXN message, to re-use the logic there in // completing processing of the putative block (without cs_main). @@ -3224,8 +3234,8 @@ public: CompareInvMempoolOrder(CTxMemPool *_mempool) { mp = _mempool; } - bool operator()(std::set::iterator a, - std::set::iterator b) { + bool operator()(std::set::iterator a, + std::set::iterator b) { /* As std::make_heap produces a max-heap, we want the entries with the * fewest ancestors/highest fee to sort later. */ return mp->CompareDepthAndScore(*b, *a); @@ -3459,7 +3469,7 @@ { LOCK(cs_most_recent_block); if (most_recent_block_hash == pBestIndex->GetBlockHash()) { - CBlockHeaderAndShortTxIDs cmpctblock( + CBlockHeaderAndShortTxHashes cmpctblock( *most_recent_block); connman.PushMessage( pto, @@ -3473,7 +3483,7 @@ bool ret = ReadBlockFromDisk(block, pBestIndex, consensusParams); assert(ret); - CBlockHeaderAndShortTxIDs cmpctblock(block); + CBlockHeaderAndShortTxHashes cmpctblock(block); connman.PushMessage( pto, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, cmpctblock)); @@ -3580,9 +3590,9 @@ LOCK(pto->cs_filter); for (const auto &txinfo : vtxinfo) { - const uint256 &txid = txinfo.tx->GetId(); - CInv inv(MSG_TX, txid); - pto->setInventoryTxToSend.erase(txid); + const txhash_t &txhash = txinfo.tx->GetHash(); + CInv inv(MSG_TX, txhash); + pto->setInventoryTxToSend.erase(txhash); if (filterrate != 0) { if (txinfo.feeRate.GetFeePerK() < filterrate) { continue; @@ -3593,7 +3603,7 @@ continue; } } - pto->filterInventoryKnown.insert(txid); + pto->filterInventoryKnown.insert(txhash); vInv.push_back(inv); if (vInv.size() == MAX_INV_SZ) { connman.PushMessage(pto, @@ -3607,9 +3617,9 @@ // Determine transactions to relay if (fSendTrickle) { // Produce a vector with all candidates for sending - std::vector::iterator> vInvTx; + std::vector::iterator> vInvTx; vInvTx.reserve(pto->setInventoryTxToSend.size()); - for (std::set::iterator it = + for (std::set::iterator it = pto->setInventoryTxToSend.begin(); it != pto->setInventoryTxToSend.end(); it++) { vInvTx.push_back(it); @@ -3635,9 +3645,9 @@ // Fetch the top element from the heap std::pop_heap(vInvTx.begin(), vInvTx.end(), compareInvMempoolOrder); - std::set::iterator it = vInvTx.back(); + std::set::iterator it = vInvTx.back(); vInvTx.pop_back(); - uint256 hash = *it; + txhash_t hash = *it; // Remove it from the to-be-sent set pto->setInventoryTxToSend.erase(it); // Check if not in the filter already diff --git a/src/policy/fees.h b/src/policy/fees.h --- a/src/policy/fees.h +++ b/src/policy/fees.h @@ -281,7 +281,7 @@ TxStatsInfo() : blockHeight(0), bucketIndex(0) {} }; - // map of txids to information about that transaction + // map of txhashes to information about that transaction std::map mapMemPoolTxs; /** Classes to track historical data on transaction confirmations */ diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp --- a/src/policy/fees.cpp +++ b/src/policy/fees.cpp @@ -354,11 +354,11 @@ void CBlockPolicyEstimator::processTransaction(const CTxMemPoolEntry &entry, bool validFeeEstimate) { uint32_t txHeight = entry.GetHeight(); - uint256 txid = entry.GetTx().GetId(); - if (mapMemPoolTxs.count(txid)) { + uint256 txhash = entry.GetTx().GetHash(); + if (mapMemPoolTxs.count(txhash)) { LogPrint("estimatefee", "Blockpolicy error mempool tx %s already being tracked\n", - txid.ToString().c_str()); + txhash.ToString().c_str()); return; } @@ -382,14 +382,14 @@ // Feerates are stored and reported as BCC-per-kb: CFeeRate feeRate(entry.GetFee(), entry.GetTxSize()); - mapMemPoolTxs[txid].blockHeight = txHeight; - mapMemPoolTxs[txid].bucketIndex = + mapMemPoolTxs[txhash].blockHeight = txHeight; + mapMemPoolTxs[txhash].bucketIndex = feeStats.NewTx(txHeight, double(feeRate.GetFeePerK().GetSatoshis())); } bool CBlockPolicyEstimator::processBlockTx(unsigned int nBlockHeight, const CTxMemPoolEntry *entry) { - if (!removeTx(entry->GetTx().GetId())) { + if (!removeTx(entry->GetTx().GetHash())) { // This transaction wasn't being tracked for fee estimation return false; } diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -11,18 +11,38 @@ #include "serialize.h" #include "uint256.h" +#include "boost/serialization/strong_typedef.hpp" + static const int SERIALIZE_TRANSACTION = 0x00; +/** A unspentid is either: + * The hash of a v1 or v2 transaction or + * The double sha256 of all transaction data *except the inputs* + * + * It is used as reference to a transaction in an Outpoint. */ +class unspentid_t : public uint256 { +public: + unspentid_t() {} + explicit unspentid_t(const uint256 &b) : uint256(b) {} +}; + +/** A txhash is the double sha256 hash of the full transaction data */ +class txhash_t : public uint256 { +public: + txhash_t() {} + explicit txhash_t(const uint256 &b) : uint256(b) {} +}; + /** An outpoint - a combination of a transaction hash and an index n into its * vout */ class COutPoint { public: - uint256 hash; + unspentid_t unspentid; uint32_t n; COutPoint() { SetNull(); } - COutPoint(uint256 hashIn, uint32_t nIn) { - hash = hashIn; + COutPoint(unspentid_t unspentidIn, uint32_t nIn) { + unspentid = unspentidIn; n = nIn; } @@ -30,23 +50,23 @@ template inline void SerializationOp(Stream &s, Operation ser_action) { - READWRITE(hash); + READWRITE(unspentid); READWRITE(n); } void SetNull() { - hash.SetNull(); + unspentid.SetNull(); n = (uint32_t)-1; } - bool IsNull() const { return (hash.IsNull() && n == (uint32_t)-1); } + bool IsNull() const { return (unspentid.IsNull() && n == (uint32_t)-1); } friend bool operator<(const COutPoint &a, const COutPoint &b) { - int cmp = a.hash.Compare(b.hash); + int cmp = a.unspentid.Compare(b.unspentid); return cmp < 0 || (cmp == 0 && a.n < b.n); } friend bool operator==(const COutPoint &a, const COutPoint &b) { - return (a.hash == b.hash && a.n == b.n); + return (a.unspentid == b.unspentid && a.n == b.n); } friend bool operator!=(const COutPoint &a, const COutPoint &b) { @@ -97,7 +117,7 @@ explicit CTxIn(COutPoint prevoutIn, CScript scriptSigIn = CScript(), uint32_t nSequenceIn = SEQUENCE_FINAL); - CTxIn(uint256 hashPrevTx, uint32_t nOut, CScript scriptSigIn = CScript(), + CTxIn(unspentid_t unspentid, uint32_t nOut, CScript scriptSigIn = CScript(), uint32_t nSequenceIn = SEQUENCE_FINAL); ADD_SERIALIZE_METHODS; @@ -238,9 +258,11 @@ private: /** Memory only. */ - const uint256 hash; + const txhash_t hash; + const unspentid_t unspentid; - uint256 ComputeHash() const; + txhash_t ComputeHash() const; + unspentid_t Computeunspentid() const; public: /** Construct a CTransaction that qualifies as IsNull() */ @@ -263,10 +285,13 @@ bool IsNull() const { return vin.empty() && vout.empty(); } - const uint256 &GetId() const { return hash; } + const txhash_t &GetHash() const { return hash; } - // Compute a hash that includes both transaction and witness data - uint256 GetHash() const; + /** + * Returns the identifier of the transaction used by outpoints. + * For v3 transactions, this is the immutableId + **/ + const unspentid_t &Getunspentid() const { return unspentid; } // Return sum of txouts. Amount GetValueOut() const; @@ -326,13 +351,20 @@ } /** Compute the hash of this CMutableTransaction. This is computed on the - * fly, as opposed to GetId() in CTransaction, which uses a cached result. + * fly, as opposed to GetHash() in CTransaction, which uses a cached result. + */ + txhash_t GetHash() const; + + /** Compute the unspentid of this CMutableTransaction. This is computed on + * the + * fly, as opposed to Getunspentid() in CTransaction, which uses a cached + * result. */ - uint256 GetId() const; + unspentid_t Getunspentid() const; friend bool operator==(const CMutableTransaction &a, const CMutableTransaction &b) { - return a.GetId() == b.GetId(); + return a.GetHash() == b.GetHash(); } }; diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp --- a/src/primitives/transaction.cpp +++ b/src/primitives/transaction.cpp @@ -10,7 +10,8 @@ #include "utilstrencodings.h" std::string COutPoint::ToString() const { - return strprintf("COutPoint(%s, %u)", hash.ToString().substr(0, 10), n); + return strprintf("COutPoint(%s, %u)", unspentid.ToString().substr(0, 10), + n); } CTxIn::CTxIn(COutPoint prevoutIn, CScript scriptSigIn, uint32_t nSequenceIn) { @@ -19,9 +20,9 @@ nSequence = nSequenceIn; } -CTxIn::CTxIn(uint256 hashPrevTx, uint32_t nOut, CScript scriptSigIn, +CTxIn::CTxIn(unspentid_t unspentid, uint32_t nOut, CScript scriptSigIn, uint32_t nSequenceIn) { - prevout = COutPoint(hashPrevTx, nOut); + prevout = COutPoint(unspentid, nOut); scriptSig = scriptSigIn; nSequence = nSequenceIn; } @@ -58,16 +59,21 @@ : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime) {} -uint256 CMutableTransaction::GetId() const { - return SerializeHash(*this, SER_GETHASH, 0); +unspentid_t CMutableTransaction::GetUnspentid() const { + return unspentid_t(SerializeHash(*this, SER_GETHASH, 0)); } -uint256 CTransaction::ComputeHash() const { - return SerializeHash(*this, SER_GETHASH, 0); +txhash_t CMutableTransaction::GetHash() const { + return txhash_t(SerializeHash(*this, SER_GETHASH, 0)); } -uint256 CTransaction::GetHash() const { - return GetId(); +unspentid_t CTransaction::Computeunspentid() const { + // TODO Compute Immutable unspentid + return unspentid_t(SerializeHash(*this, SER_GETHASH, 0)); +} + +txhash_t CTransaction::ComputeHash() const { + return txhash_t(SerializeHash(*this, SER_GETHASH, 0)); } /** @@ -79,10 +85,12 @@ hash() {} CTransaction::CTransaction(const CMutableTransaction &tx) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), - nLockTime(tx.nLockTime), hash(ComputeHash()) {} + nLockTime(tx.nLockTime), hash(ComputeHash()), + unspentid(Computeunspentid()) {} CTransaction::CTransaction(CMutableTransaction &&tx) : nVersion(tx.nVersion), vin(std::move(tx.vin)), vout(std::move(tx.vout)), - nLockTime(tx.nLockTime), hash(ComputeHash()) {} + nLockTime(tx.nLockTime), hash(ComputeHash()), + unspentid(Computeunspentid()) {} Amount CTransaction::GetValueOut() const { Amount nValueOut = 0; @@ -127,10 +135,11 @@ std::string CTransaction::ToString() const { std::string str; - str += strprintf("CTransaction(txid=%s, ver=%d, vin.size=%u, vout.size=%u, " - "nLockTime=%u)\n", - GetId().ToString().substr(0, 10), nVersion, vin.size(), - vout.size(), nLockTime); + str += + strprintf("CTransaction(txhash=%s, ver=%d, vin.size=%u, vout.size=%u, " + "nLockTime=%u)\n", + GetHash().ToString().substr(0, 10), nVersion, vin.size(), + vout.size(), nLockTime); for (unsigned int i = 0; i < vin.size(); i++) str += " " + vin[i].ToString() + "\n"; for (unsigned int i = 0; i < vout.size(); i++) diff --git a/src/protocol.h b/src/protocol.h --- a/src/protocol.h +++ b/src/protocol.h @@ -141,7 +141,7 @@ */ extern const char *GETADDR; /** - * The mempool message requests the TXIDs of transactions that the receiving + * The mempool message requests the hashes of transactions that the receiving * node has verified as valid but which have not yet appeared in a block. * @since protocol version 60002. * @see https://bitcoin.org/en/developer-reference#mempool @@ -223,8 +223,8 @@ */ extern const char *SENDCMPCT; /** - * Contains a CBlockHeaderAndShortTxIDs object - providing a header and - * list of "short txids". + * Contains a CBlockHeaderAndShortTxHashes object - providing a header and + * list of "short txhashes". * @since protocol version 70014 as described by BIP 152 */ extern const char *CMPCTBLOCK; diff --git a/src/qt/bitcoinstrings.cpp b/src/qt/bitcoinstrings.cpp --- a/src/qt/bitcoinstrings.cpp +++ b/src/qt/bitcoinstrings.cpp @@ -110,7 +110,7 @@ "" "Execute command when a wallet transaction changes (%s " "in cmd is replaced by " - "TxID)"), + "Txhash)"), QT_TRANSLATE_NOOP("bitcoin-core", "" "Execute command when the best block " "changes (%s in cmd is replaced by block " diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -235,7 +235,7 @@ // so its not a parent node in tree mode) copyTransactionHashAction->setEnabled(true); if (model->isLockedCoin( - uint256S(item->text(COLUMN_TXHASH).toStdString()), + txhash_t(uint256S(item->text(COLUMN_TXHASH).toStdString())), item->text(COLUMN_VOUT_INDEX).toUInt())) { lockAction->setEnabled(false); unlockAction->setEnabled(true); @@ -291,9 +291,9 @@ if (contextMenuItem->checkState(COLUMN_CHECKBOX) == Qt::Checked) contextMenuItem->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked); - COutPoint outpt( - uint256S(contextMenuItem->text(COLUMN_TXHASH).toStdString()), - contextMenuItem->text(COLUMN_VOUT_INDEX).toUInt()); + COutPoint outpt(unspentid_t(uint256S( + contextMenuItem->text(COLUMN_TXHASH).toStdString())), + contextMenuItem->text(COLUMN_VOUT_INDEX).toUInt()); model->lockCoin(outpt); contextMenuItem->setDisabled(true); contextMenuItem->setIcon( @@ -303,9 +303,9 @@ // context menu action: unlock coin void CoinControlDialog::unlockCoin() { - COutPoint outpt( - uint256S(contextMenuItem->text(COLUMN_TXHASH).toStdString()), - contextMenuItem->text(COLUMN_VOUT_INDEX).toUInt()); + COutPoint outpt(unspentid_t(uint256S( + contextMenuItem->text(COLUMN_TXHASH).toStdString())), + contextMenuItem->text(COLUMN_VOUT_INDEX).toUInt()); model->unlockCoin(outpt); contextMenuItem->setDisabled(false); contextMenuItem->setIcon(COLUMN_CHECKBOX, QIcon()); @@ -404,8 +404,9 @@ // transaction hash is 64 characters (this means its a child node, so its // not a parent node in tree mode) if (column == COLUMN_CHECKBOX && item->text(COLUMN_TXHASH).length() == 64) { - COutPoint outpt(uint256S(item->text(COLUMN_TXHASH).toStdString()), - item->text(COLUMN_VOUT_INDEX).toUInt()); + COutPoint outpt( + unspentid_t(uint256S(item->text(COLUMN_TXHASH).toStdString())), + item->text(COLUMN_VOUT_INDEX).toUInt()); if (item->checkState(COLUMN_CHECKBOX) == Qt::Unchecked) { coinControl->UnSelect(outpt); @@ -482,7 +483,7 @@ for (const COutput &out : vOutputs) { // unselect already spent, very unlikely scenario, this could happen // when selected are spent elsewhere, like rpc or another computer - uint256 txhash = out.tx->GetId(); + unspentid_t txhash = out.tx->tx->GetUnspentid(); COutPoint outpt(txhash, out.i); if (model->isSpent(outpt)) { coinControl->UnSelect(outpt); @@ -793,7 +794,7 @@ QVariant((qlonglong)out.nDepth)); // transaction hash - uint256 txhash = out.tx->GetId(); + txhash_t txhash = out.tx->GetHash(); itemOutput->setText(COLUMN_TXHASH, QString::fromStdString(txhash.GetHex())); @@ -802,7 +803,7 @@ // disable locked coins if (model->isLockedCoin(txhash, out.i)) { - COutPoint outpt(txhash, out.i); + COutPoint outpt(out.tx->tx->GetUnspentid(), out.i); // just to be sure coinControl->UnSelect(outpt); itemOutput->setDisabled(true); @@ -812,7 +813,8 @@ } // set checkbox - if (coinControl->IsSelected(COutPoint(txhash, out.i))) { + if (coinControl->IsSelected( + COutPoint(out.tx->tx->GetUnspentid(), out.i))) { itemOutput->setCheckState(COLUMN_CHECKBOX, Qt::Checked); } } diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -269,7 +269,7 @@ GUIUtil::HtmlEscape(wtx.mapValue["comment"], true) + "
"; strHTML += - "" + tr("Transaction ID") + ": " + rec->getTxID() + "
"; + "" + tr("Transaction ID") + ": " + rec->getTxHash() + "
"; strHTML += "" + tr("Transaction total size") + ": " + QString::number(wtx.tx->GetTotalSize()) + " bytes
"; strHTML += "" + tr("Output index") + ": " + diff --git a/src/qt/transactiondescdialog.cpp b/src/qt/transactiondescdialog.cpp --- a/src/qt/transactiondescdialog.cpp +++ b/src/qt/transactiondescdialog.cpp @@ -15,7 +15,7 @@ ui->setupUi(this); setWindowTitle( tr("Details for %1") - .arg(idx.data(TransactionTableModel::TxIDRole).toString())); + .arg(idx.data(TransactionTableModel::TxHashRole).toString())); QString desc = idx.data(TransactionTableModel::LongDescriptionRole).toString(); ui->detailText->setHtml(desc); diff --git a/src/qt/transactionrecord.h b/src/qt/transactionrecord.h --- a/src/qt/transactionrecord.h +++ b/src/qt/transactionrecord.h @@ -6,6 +6,7 @@ #define BITCOIN_QT_TRANSACTIONRECORD_H #include "amount.h" +#include "primitives/transaction.h" #include "uint256.h" #include @@ -102,11 +103,11 @@ : hash(), time(0), type(Other), address(""), debit(0), credit(0), idx(0) {} - TransactionRecord(uint256 _hash, qint64 _time) + TransactionRecord(txhash_t _hash, qint64 _time) : hash(_hash), time(_time), type(Other), address(""), debit(0), credit(0), idx(0) {} - TransactionRecord(uint256 _hash, qint64 _time, Type _type, + TransactionRecord(txhash_t _hash, qint64 _time, Type _type, const std::string &_address, const CAmount &_debit, const CAmount &_credit) : hash(_hash), time(_time), type(_type), address(_address), @@ -120,7 +121,7 @@ /** @name Immutable transaction attributes @{*/ - uint256 hash; + txhash_t hash; qint64 time; Type type; std::string address; @@ -138,7 +139,7 @@ bool involvesWatchAddress; /** Return the unique identifier for this transaction (part) */ - QString getTxID() const; + QString getTxHash() const; /** Return the output index of the subtransaction */ int getOutputIndex() const; diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp --- a/src/qt/transactionrecord.cpp +++ b/src/qt/transactionrecord.cpp @@ -37,7 +37,7 @@ CAmount nCredit = wtx.GetCredit(ISMINE_ALL); CAmount nDebit = wtx.GetDebit(ISMINE_ALL); CAmount nNet = nCredit - nDebit; - uint256 hash = wtx.GetId(); + txhash_t hash = wtx.GetHash(); std::map mapValue = wtx.mapValue; if (nNet > 0 || wtx.IsCoinBase()) { @@ -217,7 +217,7 @@ return status.cur_num_blocks != chainActive.Height(); } -QString TransactionRecord::getTxID() const { +QString TransactionRecord::getTxHash() const { return QString::fromStdString(hash.ToString()); } diff --git a/src/qt/transactiontablemodel.h b/src/qt/transactiontablemodel.h --- a/src/qt/transactiontablemodel.h +++ b/src/qt/transactiontablemodel.h @@ -58,7 +58,7 @@ /** Net amount of transaction */ AmountRole, /** Unique identifier */ - TxIDRole, + TxHashRole, /** Transaction hash */ TxHashRole, /** Transaction data, hex-encoded */ diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -42,10 +42,10 @@ const TransactionRecord &b) const { return a.hash < b.hash; } - bool operator()(const TransactionRecord &a, const uint256 &b) const { + bool operator()(const TransactionRecord &a, const txhash_t &b) const { return a.hash < b; } - bool operator()(const uint256 &a, const TransactionRecord &b) const { + bool operator()(const txhash_t &a, const TransactionRecord &b) const { return a < b.hash; } }; @@ -72,7 +72,7 @@ cachedWallet.clear(); { LOCK2(cs_main, wallet->cs_wallet); - for (std::map::iterator it = + for (std::map::iterator it = wallet->mapWallet.begin(); it != wallet->mapWallet.end(); ++it) { if (TransactionRecord::showTransaction(it->second)) @@ -87,7 +87,7 @@ * the wallet with that of the core. * Call with transaction that was added, removed or changed. */ - void updateWallet(const uint256 &hash, int status, bool showTransaction) { + void updateWallet(const txhash_t &hash, int status, bool showTransaction) { qDebug() << "TransactionTablePriv::updateWallet: " + QString::fromStdString(hash.ToString()) + " " + QString::number(status); @@ -125,7 +125,7 @@ if (showTransaction) { LOCK2(cs_main, wallet->cs_wallet); // Find transaction in wallet - std::map::iterator mi = + std::map::iterator mi = wallet->mapWallet.find(hash); if (mi == wallet->mapWallet.end()) { qWarning() << "TransactionTablePriv::updateWallet: " @@ -189,7 +189,7 @@ if (lockMain) { TRY_LOCK(wallet->cs_wallet, lockWallet); if (lockWallet && rec->statusUpdateNeeded()) { - std::map::iterator mi = + std::map::iterator mi = wallet->mapWallet.find(rec->hash); if (mi != wallet->mapWallet.end()) { @@ -205,7 +205,7 @@ QString describe(TransactionRecord *rec, int unit) { { LOCK2(cs_main, wallet->cs_wallet); - std::map::iterator mi = + std::map::iterator mi = wallet->mapWallet.find(rec->hash); if (mi != wallet->mapWallet.end()) { return TransactionDesc::toHTML(wallet, mi->second, rec, unit); @@ -216,7 +216,7 @@ QString getTxHex(TransactionRecord *rec) { LOCK2(cs_main, wallet->cs_wallet); - std::map::iterator mi = + std::map::iterator mi = wallet->mapWallet.find(rec->hash); if (mi != wallet->mapWallet.end()) { std::string strHex = @@ -258,7 +258,7 @@ void TransactionTableModel::updateTransaction(const QString &hash, int status, bool showTransaction) { - uint256 updated; + txhash_t updated; updated.SetHex(hash.toStdString()); priv->updateWallet(updated, status, showTransaction); @@ -606,8 +606,8 @@ QString::fromStdString(rec->address)); case AmountRole: return qint64(rec->credit + rec->debit); - case TxIDRole: - return rec->getTxID(); + case TxHashRole: + return rec->getTxHash(); case TxHashRole: return QString::fromStdString(rec->hash.ToString()); case TxHexRole: @@ -706,7 +706,7 @@ struct TransactionNotification { public: TransactionNotification() {} - TransactionNotification(uint256 _hash, ChangeType _status, + TransactionNotification(txhash_t _hash, ChangeType _status, bool _showTransaction) : hash(_hash), status(_status), showTransaction(_showTransaction) {} @@ -721,7 +721,7 @@ } private: - uint256 hash; + txhash_t hash; ChangeType status; bool showTransaction; }; @@ -730,10 +730,10 @@ static std::vector vQueueNotifications; static void NotifyTransactionChanged(TransactionTableModel *ttm, - CWallet *wallet, const uint256 &hash, + CWallet *wallet, const txhash_t &hash, ChangeType status) { // Find transaction in wallet - std::map::iterator mi = wallet->mapWallet.find(hash); + std::map::iterator mi = wallet->mapWallet.find(hash); // Determine whether to show transaction or not (determine this here so that // no relocking is needed in GUI thread) bool inWallet = mi != wallet->mapWallet.end(); diff --git a/src/qt/transactionview.h b/src/qt/transactionview.h --- a/src/qt/transactionview.h +++ b/src/qt/transactionview.h @@ -93,7 +93,7 @@ void editLabel(); void copyLabel(); void copyAmount(); - void copyTxID(); + void copyTxHash(); void copyTxHex(); void copyTxPlainText(); void openThirdPartyTxUrl(QString url); diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp --- a/src/qt/transactionview.cpp +++ b/src/qt/transactionview.cpp @@ -151,7 +151,7 @@ QAction *copyAddressAction = new QAction(tr("Copy address"), this); QAction *copyLabelAction = new QAction(tr("Copy label"), this); QAction *copyAmountAction = new QAction(tr("Copy amount"), this); - QAction *copyTxIDAction = new QAction(tr("Copy transaction ID"), this); + QAction *copyTxHashAction = new QAction(tr("Copy transaction ID"), this); QAction *copyTxHexAction = new QAction(tr("Copy raw transaction"), this); QAction *copyTxPlainText = new QAction(tr("Copy full transaction details"), this); @@ -163,7 +163,7 @@ contextMenu->addAction(copyAddressAction); contextMenu->addAction(copyLabelAction); contextMenu->addAction(copyAmountAction); - contextMenu->addAction(copyTxIDAction); + contextMenu->addAction(copyTxHashAction); contextMenu->addAction(copyTxHexAction); contextMenu->addAction(copyTxPlainText); contextMenu->addAction(showDetailsAction); @@ -195,7 +195,7 @@ connect(copyAddressAction, SIGNAL(triggered()), this, SLOT(copyAddress())); connect(copyLabelAction, SIGNAL(triggered()), this, SLOT(copyLabel())); connect(copyAmountAction, SIGNAL(triggered()), this, SLOT(copyAmount())); - connect(copyTxIDAction, SIGNAL(triggered()), this, SLOT(copyTxID())); + connect(copyTxHashAction, SIGNAL(triggered()), this, SLOT(copyTxHash())); connect(copyTxHexAction, SIGNAL(triggered()), this, SLOT(copyTxHex())); connect(copyTxPlainText, SIGNAL(triggered()), this, SLOT(copyTxPlainText())); @@ -364,7 +364,7 @@ writer.addColumn(BitcoinUnits::getAmountColumnTitle( model->getOptionsModel()->getDisplayUnit()), 0, TransactionTableModel::FormattedAmountRole); - writer.addColumn(tr("ID"), 0, TransactionTableModel::TxIDRole); + writer.addColumn(tr("ID"), 0, TransactionTableModel::TxHashRole); if (!writer.write()) { Q_EMIT message(tr("Exporting Failed"), @@ -389,7 +389,7 @@ // check if transaction can be abandoned, disable context menu action in // case it doesn't - uint256 hash; + txhash_t hash; hash.SetHex(selection.at(0) .data(TransactionTableModel::TxHashRole) .toString() @@ -407,7 +407,7 @@ transactionView->selectionModel()->selectedRows(0); // get the hash from the TxHashRole (QVariant / QString) - uint256 hash; + txhash_t hash; QString hashQStr = selection.at(0).data(TransactionTableModel::TxHashRole).toString(); hash.SetHex(hashQStr.toStdString()); @@ -435,8 +435,9 @@ TransactionTableModel::FormattedAmountRole); } -void TransactionView::copyTxID() { - GUIUtil::copyEntryData(transactionView, 0, TransactionTableModel::TxIDRole); +void TransactionView::copyTxHash() { + GUIUtil::copyEntryData(transactionView, 0, + TransactionTableModel::TxHashRole); } void TransactionView::copyTxHex() { diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -212,7 +212,7 @@ bool isSpent(const COutPoint &outpoint) const; void listCoins(std::map> &mapCoins) const; - bool isLockedCoin(uint256 hash, unsigned int n) const; + bool isLockedCoin(txhash_t hash, unsigned int n) const; void lockCoin(COutPoint &output); void unlockCoin(COutPoint &output); void listLockedCoins(std::vector &vOutpts); @@ -221,8 +221,8 @@ bool saveReceiveRequest(const std::string &sAddress, const int64_t nId, const std::string &sRequest); - bool transactionCanBeAbandoned(uint256 hash) const; - bool abandonTransaction(uint256 hash) const; + bool transactionCanBeAbandoned(txhash_t hash) const; + bool abandonTransaction(txhash_t hash) const; static bool isWalletEnabled(); diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -446,7 +446,7 @@ } static void NotifyTransactionChanged(WalletModel *walletmodel, CWallet *wallet, - const uint256 &hash, ChangeType status) { + const txhash_t &hash, ChangeType status) { Q_UNUSED(wallet); Q_UNUSED(hash); Q_UNUSED(status); @@ -543,18 +543,18 @@ std::vector &vOutputs) { LOCK2(cs_main, wallet->cs_wallet); for (const COutPoint &outpoint : vOutpoints) { - if (!wallet->mapWallet.count(outpoint.hash)) continue; - int nDepth = wallet->mapWallet[outpoint.hash].GetDepthInMainChain(); + const CWalletTx *wtx = wallet->GetWalletTx(outpoint.unspentid); + if (!wtx) continue; + int nDepth = wtx->GetDepthInMainChain(); if (nDepth < 0) continue; - COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, nDepth, true, - true); + COutput out(wtx, outpoint.n, nDepth, true, true); vOutputs.push_back(out); } } bool WalletModel::isSpent(const COutPoint &outpoint) const { LOCK2(cs_main, wallet->cs_wallet); - return wallet->IsSpent(outpoint.hash, outpoint.n); + return wallet->IsSpent(outpoint); } // AvailableCoins + LockedCoins grouped by wallet address (put change in one @@ -571,11 +571,11 @@ // add locked coins for (const COutPoint &outpoint : vLockedCoins) { - if (!wallet->mapWallet.count(outpoint.hash)) continue; - int nDepth = wallet->mapWallet[outpoint.hash].GetDepthInMainChain(); + const CWalletTx *wtx = wallet->GetWalletTx(outpoint.unspentid); + if (!wtx) continue; + int nDepth = wtx->GetDepthInMainChain(); if (nDepth < 0) continue; - COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, nDepth, true, - true); + COutput out(wtx, outpoint.n, nDepth, true, true); if (outpoint.n < out.tx->tx->vout.size() && wallet->IsMine(out.tx->tx->vout[outpoint.n]) == ISMINE_SPENDABLE) vCoins.push_back(out); @@ -587,10 +587,10 @@ while (wallet->IsChange(cout.tx->tx->vout[cout.i]) && cout.tx->tx->vin.size() > 0 && wallet->IsMine(cout.tx->tx->vin[0])) { - if (!wallet->mapWallet.count(cout.tx->tx->vin[0].prevout.hash)) - break; - cout = COutput(&wallet->mapWallet[cout.tx->tx->vin[0].prevout.hash], - cout.tx->tx->vin[0].prevout.n, 0, true, true); + const CWalletTx *wtx = + wallet->GetWalletTx(cout.tx->tx->vin[0].prevout.unspentid); + if (!wtx) break; + cout = COutput(wtx, cout.tx->tx->vin[0].prevout.n, 0, true, true); } CTxDestination address; @@ -603,9 +603,14 @@ } } -bool WalletModel::isLockedCoin(uint256 hash, unsigned int n) const { +bool WalletModel::isLockedCoin(txhash_t hash, unsigned int n) const { LOCK2(cs_main, wallet->cs_wallet); - return wallet->IsLockedCoin(hash, n); + const CWalletTx *wtx = wallet->GetWalletTx(hash); + if (!wtx) { + return false; + } + + return wallet->IsLockedCoin(COutPoint(wtx->tx->GetUnspentid(), n)); } void WalletModel::lockCoin(COutPoint &output) { @@ -653,7 +658,7 @@ return wallet->AddDestData(dest, key, sRequest); } -bool WalletModel::transactionCanBeAbandoned(uint256 hash) const { +bool WalletModel::transactionCanBeAbandoned(txhash_t hash) const { LOCK2(cs_main, wallet->cs_wallet); const CWalletTx *wtx = wallet->GetWalletTx(hash); if (!wtx || wtx->isAbandoned() || wtx->GetDepthInMainChain() > 0 || @@ -662,7 +667,7 @@ return true; } -bool WalletModel::abandonTransaction(uint256 hash) const { +bool WalletModel::abandonTransaction(txhash_t hash) const { LOCK2(cs_main, wallet->cs_wallet); return wallet->AbandonTransaction(hash); } diff --git a/src/rest.cpp b/src/rest.cpp --- a/src/rest.cpp +++ b/src/rest.cpp @@ -360,7 +360,7 @@ std::string hashStr; const RetFormat rf = ParseDataFormat(hashStr, strURIPart); - uint256 hash; + txhash_t hash; if (!ParseHashStr(hashStr, hash)) return RESTERR(req, HTTP_BAD_REQUEST, "Invalid hash: " + hashStr); @@ -437,22 +437,23 @@ if (uriParts.size() > 0) { // inputs is sent over URI scheme - // (/rest/getutxos/checkmempool/txid1-n/txid2-n/...) + // (/rest/getutxos/checkmempool/unspentid1-n/unspentid2-n/...) if (uriParts.size() > 0 && uriParts[0] == "checkmempool") fCheckMemPool = true; for (size_t i = (fCheckMemPool) ? 1 : 0; i < uriParts.size(); i++) { - uint256 txid; + unspentid_t unspentid; int32_t nOutput; - std::string strTxid = uriParts[i].substr(0, uriParts[i].find("-")); + std::string strunspentid = + uriParts[i].substr(0, uriParts[i].find("-")); std::string strOutput = uriParts[i].substr(uriParts[i].find("-") + 1); - if (!ParseInt32(strOutput, &nOutput) || !IsHex(strTxid)) + if (!ParseInt32(strOutput, &nOutput) || !IsHex(strunspentid)) return RESTERR(req, HTTP_BAD_REQUEST, "Parse error"); - txid.SetHex(strTxid); - vOutPoints.push_back(COutPoint(txid, (uint32_t)nOutput)); + unspentid.SetHex(strunspentid); + vOutPoints.push_back(COutPoint(unspentid, (uint32_t)nOutput)); } if (vOutPoints.size() > 0) { diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -127,7 +127,7 @@ TxToJSON(*tx, uint256(), objTx); txs.push_back(objTx); } else - txs.push_back(tx->GetId().GetHex()); + txs.push_back(tx->GetHash().GetHex()); } result.push_back(Pair("tx", txs)); result.push_back(Pair("time", block.GetBlockTime())); @@ -423,8 +423,8 @@ const CTransaction &tx = e.GetTx(); std::set setDepends; for (const CTxIn &txin : tx.vin) { - if (mempool.exists(txin.prevout.hash)) { - setDepends.insert(txin.prevout.hash.ToString()); + if (mempool.exists(txin.prevout.unspentid)) { + setDepends.insert(txin.prevout.unspentid.ToString()); } } @@ -441,19 +441,19 @@ LOCK(mempool.cs); UniValue o(UniValue::VOBJ); for (const CTxMemPoolEntry &e : mempool.mapTx) { - const uint256 &txid = e.GetTx().GetId(); + const uint256 &txhash = e.GetTx().GetHash(); UniValue info(UniValue::VOBJ); entryToJSON(info, e); - o.push_back(Pair(txid.ToString(), info)); + o.push_back(Pair(txhash.ToString(), info)); } return o; } else { - std::vector vtxids; - mempool.queryHashes(vtxids); + std::vector vtxhashes; + mempool.queryHashes(vtxhashes); UniValue a(UniValue::VARR); - for (const uint256 &txid : vtxids) { - a.push_back(txid.ToString()); + for (const txhash_t &txhash : vtxhashes) { + a.push_back(txhash.ToString()); } return a; @@ -497,16 +497,17 @@ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) { throw std::runtime_error( - "getmempoolancestors txid (verbose)\n" - "\nIf txid is in the mempool, returns all in-mempool ancestors.\n" + "getmempoolancestors txhash (verbose)\n" + "\nIf txhash is in the mempool, returns all in-mempool ancestors.\n" "\nArguments:\n" - "1. \"txid\" (string, required) The transaction id " + "1. \"txhash\" (string, required) The transaction " + "hash " "(must be in mempool)\n" "2. verbose (boolean, optional, default=false) " "True for a json object, false for array of transaction ids\n" "\nResult (for verbose=false):\n" "[ (json array of strings)\n" - " \"transactionid\" (string) The transaction id of an " + " \"txhash\" (string) The transaction hash of an " "in-mempool ancestor transaction\n" " ,...\n" "]\n" @@ -516,8 +517,8 @@ EntryDescriptionString() + " }, ...\n" "}\n" "\nExamples:\n" + - HelpExampleCli("getmempoolancestors", "\"mytxid\"") + - HelpExampleRpc("getmempoolancestors", "\"mytxid\"")); + HelpExampleCli("getmempoolancestors", "\"mytxhash\"") + + HelpExampleRpc("getmempoolancestors", "\"mytxhash\"")); } bool fVerbose = false; @@ -525,11 +526,11 @@ fVerbose = request.params[1].get_bool(); } - uint256 hash = ParseHashV(request.params[0], "parameter 1"); + txhash_t txhash = (txhash_t)ParseHashV(request.params[0], "parameter 1"); LOCK(mempool.cs); - CTxMemPool::txiter it = mempool.mapTx.find(hash); + CTxMemPool::txiter it = mempool.mapTx.find(txhash); if (it == mempool.mapTx.end()) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not in mempool"); @@ -544,7 +545,7 @@ if (!fVerbose) { UniValue o(UniValue::VARR); for (CTxMemPool::txiter ancestorIt : setAncestors) { - o.push_back(ancestorIt->GetTx().GetId().ToString()); + o.push_back(ancestorIt->GetTx().GetHash().ToString()); } return o; @@ -552,7 +553,7 @@ UniValue o(UniValue::VOBJ); for (CTxMemPool::txiter ancestorIt : setAncestors) { const CTxMemPoolEntry &e = *ancestorIt; - const uint256 &_hash = e.GetTx().GetId(); + const uint256 &_hash = e.GetTx().GetHash(); UniValue info(UniValue::VOBJ); entryToJSON(info, e); o.push_back(Pair(_hash.ToString(), info)); @@ -566,16 +567,18 @@ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) { throw std::runtime_error( - "getmempooldescendants txid (verbose)\n" - "\nIf txid is in the mempool, returns all in-mempool descendants.\n" + "getmempooldescendants txhash (verbose)\n" + "\nIf txhash is in the mempool, returns all in-mempool " + "descendants.\n" "\nArguments:\n" - "1. \"txid\" (string, required) The transaction id " + "1. \"txhash\" (string, required) The transaction " + "hash " "(must be in mempool)\n" "2. verbose (boolean, optional, default=false) " "True for a json object, false for array of transaction ids\n" "\nResult (for verbose=false):\n" "[ (json array of strings)\n" - " \"transactionid\" (string) The transaction id of an " + " \"txhash\" (string) The transaction hash of an " "in-mempool descendant transaction\n" " ,...\n" "]\n" @@ -585,18 +588,18 @@ EntryDescriptionString() + " }, ...\n" "}\n" "\nExamples:\n" + - HelpExampleCli("getmempooldescendants", "\"mytxid\"") + - HelpExampleRpc("getmempooldescendants", "\"mytxid\"")); + HelpExampleCli("getmempooldescendants", "\"mytxhash\"") + + HelpExampleRpc("getmempooldescendants", "\"mytxhash\"")); } bool fVerbose = false; if (request.params.size() > 1) fVerbose = request.params[1].get_bool(); - uint256 hash = ParseHashV(request.params[0], "parameter 1"); + txhash_t txhash(ParseHashV(request.params[0], "parameter 1")); LOCK(mempool.cs); - CTxMemPool::txiter it = mempool.mapTx.find(hash); + CTxMemPool::txiter it = mempool.mapTx.find(txhash); if (it == mempool.mapTx.end()) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not in mempool"); @@ -610,7 +613,7 @@ if (!fVerbose) { UniValue o(UniValue::VARR); for (CTxMemPool::txiter descendantIt : setDescendants) { - o.push_back(descendantIt->GetTx().GetId().ToString()); + o.push_back(descendantIt->GetTx().GetHash().ToString()); } return o; @@ -618,7 +621,7 @@ UniValue o(UniValue::VOBJ); for (CTxMemPool::txiter descendantIt : setDescendants) { const CTxMemPoolEntry &e = *descendantIt; - const uint256 &_hash = e.GetTx().GetId(); + const uint256 &_hash = e.GetTx().GetHash(); UniValue info(UniValue::VOBJ); entryToJSON(info, e); o.push_back(Pair(_hash.ToString(), info)); @@ -630,24 +633,24 @@ UniValue getmempoolentry(const Config &config, const JSONRPCRequest &request) { if (request.fHelp || request.params.size() != 1) { throw std::runtime_error( - "getmempoolentry txid\n" + "getmempoolentry txhash\n" "\nReturns mempool data for given transaction\n" "\nArguments:\n" - "1. \"txid\" (string, required) " + "1. \"txhash\" (string, required) " "The transaction id (must be in mempool)\n" "\nResult:\n" "{ (json object)\n" + EntryDescriptionString() + "}\n" "\nExamples:\n" + - HelpExampleCli("getmempoolentry", "\"mytxid\"") + - HelpExampleRpc("getmempoolentry", "\"mytxid\"")); + HelpExampleCli("getmempoolentry", "\"mytxhash\"") + + HelpExampleRpc("getmempoolentry", "\"mytxhash\"")); } - uint256 hash = ParseHashV(request.params[0], "parameter 1"); + txhash_t txhash(ParseHashV(request.params[0], "parameter 1")); LOCK(mempool.cs); - CTxMemPool::txiter it = mempool.mapTx.find(hash); + CTxMemPool::txiter it = mempool.mapTx.find(txhash); if (it == mempool.mapTx.end()) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not in mempool"); @@ -869,7 +872,8 @@ nDiskSize(0), nTotalAmount(0) {} }; -static void ApplyStats(CCoinsStats &stats, CHashWriter &ss, const uint256 &hash, +static void ApplyStats(CCoinsStats &stats, CHashWriter &ss, + const unspentid_t &hash, const std::map &outputs) { assert(!outputs.empty()); ss << hash; @@ -883,7 +887,7 @@ stats.nTransactionOutputs++; stats.nTotalAmount += output.second.GetTxOut().nValue.GetSatoshis(); stats.nBogoSize += - 32 /* txid */ + 4 /* vout index */ + 4 /* height + coinbase */ + + 32 /* txhash */ + 4 /* vout index */ + 4 /* height + coinbase */ + 8 /* amount */ + 2 /* scriptPubKey len */ + output.second.GetTxOut().scriptPubKey.size() /* scriptPubKey */; } @@ -901,18 +905,18 @@ stats.nHeight = mapBlockIndex.find(stats.hashBlock)->second->nHeight; } ss << stats.hashBlock; - uint256 prevkey; + unspentid_t prevkey; std::map outputs; while (pcursor->Valid()) { boost::this_thread::interruption_point(); COutPoint key; Coin coin; if (pcursor->GetKey(key) && pcursor->GetValue(coin)) { - if (!outputs.empty() && key.hash != prevkey) { + if (!outputs.empty() && key.unspentid != prevkey) { ApplyStats(stats, ss, prevkey, outputs); outputs.clear(); } - prevkey = key.hash; + prevkey = key.unspentid; outputs[key.n] = std::move(coin); } else { return error("%s: unable to read value", __func__); @@ -1039,10 +1043,11 @@ if (request.fHelp || request.params.size() < 2 || request.params.size() > 3) { throw std::runtime_error( - "gettxout \"txid\" n ( include_mempool )\n" + "gettxout \"txhash\" n ( include_mempool )\n" "\nReturns details about an unspent transaction output.\n" "\nArguments:\n" - "1. \"txid\" (string, required) The transaction id\n" + "1. \"unspentid\" (string, required) The Unspent transaction " + "id\n" "2. n (numeric, required) vout number\n" "3. include_mempool (boolean, optional) Whether to include the " "mempool\n" @@ -1073,9 +1078,9 @@ "\nExamples:\n" "\nGet unspent transactions\n" + HelpExampleCli("listunspent", "") + "\nView the details\n" + - HelpExampleCli("gettxout", "\"txid\" 1") + + HelpExampleCli("gettxout", "\"txhash\" 1") + "\nAs a json rpc call\n" + - HelpExampleRpc("gettxout", "\"txid\", 1")); + HelpExampleRpc("gettxout", "\"txhash\", 1")); } LOCK(cs_main); @@ -1083,7 +1088,7 @@ UniValue ret(UniValue::VOBJ); std::string strHash = request.params[0].get_str(); - uint256 hash(uint256S(strHash)); + unspentid_t hash(uint256S(strHash)); int n = request.params[1].get_int(); COutPoint out(hash, n); bool fMempool = true; @@ -1639,12 +1644,12 @@ { "blockchain", "getblockheader", getblockheader, true, {"blockhash","verbose"} }, { "blockchain", "getchaintips", getchaintips, true, {} }, { "blockchain", "getdifficulty", getdifficulty, true, {} }, - { "blockchain", "getmempoolancestors", getmempoolancestors, true, {"txid","verbose"} }, - { "blockchain", "getmempooldescendants", getmempooldescendants, true, {"txid","verbose"} }, - { "blockchain", "getmempoolentry", getmempoolentry, true, {"txid"} }, + { "blockchain", "getmempoolancestors", getmempoolancestors, true, {"txhash","verbose"} }, + { "blockchain", "getmempooldescendants", getmempooldescendants, true, {"txhash","verbose"} }, + { "blockchain", "getmempoolentry", getmempoolentry, true, {"txhash"} }, { "blockchain", "getmempoolinfo", getmempoolinfo, true, {} }, { "blockchain", "getrawmempool", getrawmempool, true, {"verbose"} }, - { "blockchain", "gettxout", gettxout, true, {"txid","n","include_mempool"} }, + { "blockchain", "gettxout", gettxout, true, {"txhash","n","include_mempool"} }, { "blockchain", "gettxoutsetinfo", gettxoutsetinfo, true, {} }, { "blockchain", "pruneblockchain", pruneblockchain, true, {"height"} }, { "blockchain", "verifychain", verifychain, true, {"checklevel","nblocks"} }, diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -88,7 +88,7 @@ {"fundrawtransaction", 1, "options"}, {"gettxout", 1, "n"}, {"gettxout", 2, "include_mempool"}, - {"gettxoutproof", 0, "txids"}, + {"gettxoutproof", 0, "txhashes"}, {"lockunspent", 0, "unlock"}, {"lockunspent", 1, "transactions"}, {"importprivkey", 2, "rescan"}, diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -303,11 +303,11 @@ const JSONRPCRequest &request) { if (request.fHelp || request.params.size() != 3) { throw std::runtime_error( - "prioritisetransaction \n" + "prioritisetransaction \n" "Accepts the transaction into mined blocks at a higher (or lower) " "priority\n" "\nArguments:\n" - "1. \"txid\" (string, required) The transaction id.\n" + "1. \"txhash\" (string, required) The transaction hash.\n" "2. priority_delta (numeric, required) The priority to add or " "subtract.\n" " The transaction selection algorithm considers " @@ -323,16 +323,16 @@ "\nResult:\n" "true (boolean) Returns true\n" "\nExamples:\n" + - HelpExampleCli("prioritisetransaction", "\"txid\" 0.0 10000") + - HelpExampleRpc("prioritisetransaction", "\"txid\", 0.0, 10000")); + HelpExampleCli("prioritisetransaction", "\"txhash\" 0.0 10000") + + HelpExampleRpc("prioritisetransaction", "\"txhash\", 0.0, 10000")); } LOCK(cs_main); - uint256 hash = ParseHashStr(request.params[0].get_str(), "txid"); + txhash_t txhash(ParseHashStr(request.params[0].get_str(), "txhash")); CAmount nAmount = request.params[2].get_int64(); - mempool.PrioritiseTransaction(hash, request.params[0].get_str(), + mempool.PrioritiseTransaction(txhash, request.params[0].get_str(), request.params[1].get_real(), nAmount); return true; } @@ -435,7 +435,8 @@ " {\n" " \"data\" : \"xxxx\", (string) transaction " "data encoded in hexadecimal (byte-for-byte)\n" - " \"txid\" : \"xxxx\", (string) transaction id " + " \"unspentid\" : \"xxxx\", (string) " + "transaction id " "encoded in little-endian hexadecimal\n" " \"hash\" : \"xxxx\", (string) hash encoded " "in little-endian hexadecimal (including witness data)\n" @@ -680,12 +681,12 @@ aCaps.push_back("proposal"); UniValue transactions(UniValue::VARR); - std::map setTxIndex; + std::map setTxIndex; int i = 0; for (const auto &it : pblock->vtx) { const CTransaction &tx = *it; - uint256 txId = tx.GetId(); - setTxIndex[txId] = i++; + unspentid_t unspentid = tx.Getunspentid(); + setTxIndex[unspentid] = i++; if (tx.IsCoinBase()) { continue; @@ -694,13 +695,13 @@ UniValue entry(UniValue::VOBJ); entry.push_back(Pair("data", EncodeHexTx(tx))); - entry.push_back(Pair("txid", txId.GetHex())); + entry.push_back(Pair("unspentid", unspentid.GetHex())); entry.push_back(Pair("hash", tx.GetHash().GetHex())); UniValue deps(UniValue::VARR); for (const CTxIn &in : tx.vin) { - if (setTxIndex.count(in.prevout.hash)) - deps.push_back(setTxIndex[in.prevout.hash]); + if (setTxIndex.count(in.prevout.unspentid)) + deps.push_back(setTxIndex[in.prevout.unspentid]); } entry.push_back(Pair("depends", deps)); @@ -1076,7 +1077,7 @@ // ---------- ------------------------ ---------------------- ---------- {"mining", "getnetworkhashps", getnetworkhashps, true, {"nblocks", "height"}}, {"mining", "getmininginfo", getmininginfo, true, {}}, - {"mining", "prioritisetransaction", prioritisetransaction, true, {"txid", "priority_delta", "fee_delta"}}, + {"mining", "prioritisetransaction", prioritisetransaction, true, {"txhash", "priority_delta", "fee_delta"}}, {"mining", "getblocktemplate", getblocktemplate, true, {"template_request"}}, {"mining", "submitblock", submitblock, true, {"hexdata", "parameters"}}, diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -62,7 +62,7 @@ void TxToJSON(const CTransaction &tx, const uint256 hashBlock, UniValue &entry) { - entry.push_back(Pair("txid", tx.GetId().GetHex())); + entry.push_back(Pair("unspentid", tx.Getunspentid().GetHex())); entry.push_back(Pair("hash", tx.GetHash().GetHex())); entry.push_back(Pair( "size", (int)::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION))); @@ -77,7 +77,7 @@ in.push_back(Pair("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end()))); } else { - in.push_back(Pair("txid", txin.prevout.hash.GetHex())); + in.push_back(Pair("unspentid", txin.prevout.unspentid.GetHex())); in.push_back(Pair("vout", (int64_t)txin.prevout.n)); UniValue o(UniValue::VOBJ); o.push_back(Pair("asm", ScriptToAsmStr(txin.scriptSig, true))); @@ -127,44 +127,41 @@ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) { throw std::runtime_error( - "getrawtransaction \"txid\" ( verbose )\n" + "getrawtransaction \"txhash\" ( verbose )\n" "\nNOTE: By default this function only works for mempool " "transactions. If the -txindex option is\n" "enabled, it also works for blockchain transactions.\n" - "DEPRECATED: for now, it also works for transactions with unspent " - "outputs.\n" "\nReturn the raw transaction data.\n" "\nIf verbose is 'true', returns an Object with information about " - "'txid'.\n" + "'txhash'.\n" "If verbose is 'false' or omitted, returns a string that is " - "serialized, hex-encoded data for 'txid'.\n" + "serialized, hex-encoded data for 'txhash'.\n" "\nArguments:\n" - "1. \"txid\" (string, required) The transaction id\n" + "1. \"txhash\" (string, required) The transaction id\n" "2. verbose (bool, optional, default=false) If false, return " "a string, otherwise return a json object\n" "\nResult (if verbose is not set or set to false):\n" "\"data\" (string) The serialized, hex-encoded data for " - "'txid'\n" + "'txhash'\n" "\nResult (if verbose is set to true):\n" "{\n" " \"hex\" : \"data\", (string) The serialized, hex-encoded " - "data for 'txid'\n" - " \"txid\" : \"id\", (string) The transaction id (same as " + "data for 'txhash'\n" + " \"txhash\" : \"id\", (string) The transaction hash (same " + "as " "provided)\n" - " \"hash\" : \"id\", (string) The transaction hash " - "(differs from txid for witness transactions)\n" " \"size\" : n, (numeric) The serialized transaction " "size\n" " \"version\" : n, (numeric) The version\n" " \"locktime\" : ttt, (numeric) The lock time\n" " \"vin\" : [ (array of json objects)\n" " {\n" - " \"txid\": \"id\", (string) The transaction id\n" + " \"unspentid\": \"id\", (string) The transaction id\n" " \"vout\": n, (numeric) \n" " \"scriptSig\": { (json object) The script\n" " \"asm\": \"asm\", (string) asm\n" @@ -203,14 +200,14 @@ "}\n" "\nExamples:\n" + - HelpExampleCli("getrawtransaction", "\"mytxid\"") + - HelpExampleCli("getrawtransaction", "\"mytxid\" true") + - HelpExampleRpc("getrawtransaction", "\"mytxid\", true")); + HelpExampleCli("getrawtransaction", "\"mytxhash\"") + + HelpExampleCli("getrawtransaction", "\"mytxhash\" true") + + HelpExampleRpc("getrawtransaction", "\"mytxhash\", true")); } LOCK(cs_main); - uint256 hash = ParseHashV(request.params[0], "parameter 1"); + txhash_t hash = txhash_t(ParseHashV(request.params[0], "parameter 1")); // Accept either a bool (true) or a num (>=1) to indicate verbose output. bool fVerbose = false; @@ -258,8 +255,8 @@ if (request.fHelp || (request.params.size() != 1 && request.params.size() != 2)) { throw std::runtime_error( - "gettxoutproof [\"txid\",...] ( blockhash )\n" - "\nReturns a hex-encoded proof that \"txid\" was included in a " + "gettxoutproof [\"txhash\",...] ( blockhash )\n" + "\nReturns a hex-encoded proof that \"txhash\" was included in a " "block.\n" "\nNOTE: This function only works if a transaction index is " "maintained using the\n" @@ -267,38 +264,40 @@ "which the transaction\n" "is included manually (by blockhash).\n" "\nArguments:\n" - "1. \"txids\" (string) A json array of txids to filter\n" + "1. \"txhashes\" (string) A json array of txhashes to " + "filter\n" " [\n" - " \"txid\" (string) A transaction hash\n" + " \"txhash\" (string) A transaction hash\n" " ,...\n" " ]\n" "2. \"blockhash\" (string, optional) If specified, looks for " - "txid in the block with this hash\n" + "txhash in the block with this hash\n" "\nResult:\n" "\"data\" (string) A string that is a serialized, " "hex-encoded data for the proof.\n"); } - std::set setTxids; - uint256 oneTxid; - UniValue txids = request.params[0].get_array(); - for (unsigned int idx = 0; idx < txids.size(); idx++) { - const UniValue &txid = txids[idx]; - if (txid.get_str().length() != 64 || !IsHex(txid.get_str())) { + std::set setTxhashes; + txhash_t oneTxhash; + UniValue txhashes = request.params[0].get_array(); + for (unsigned int idx = 0; idx < txhashes.size(); idx++) { + const UniValue &txhash = txhashes[idx]; + if (txhash.get_str().length() != 64 || !IsHex(txhash.get_str())) { throw JSONRPCError(RPC_INVALID_PARAMETER, - std::string("Invalid txid ") + txid.get_str()); + std::string("Invalid txhash ") + + txhash.get_str()); } - uint256 hash(uint256S(txid.get_str())); - if (setTxids.count(hash)) { + txhash_t hash(uint256S(txhash.get_str())); + if (setTxhashes.count(hash)) { throw JSONRPCError( RPC_INVALID_PARAMETER, - std::string("Invalid parameter, duplicated txid: ") + - txid.get_str()); + std::string("Invalid parameter, duplicated txhash: ") + + txhash.get_str()); } - setTxids.insert(hash); - oneTxid = hash; + setTxhashes.insert(hash); + oneTxhash = hash; } LOCK(cs_main); @@ -321,7 +320,7 @@ } CTransactionRef tx; - if (!GetTransaction(config, oneTxid, tx, hashBlock) || + if (!GetTransaction(config, oneTxhash, tx, hashBlock) || hashBlock.IsNull()) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not yet in block"); @@ -341,19 +340,19 @@ unsigned int ntxFound = 0; for (const auto &tx : block.vtx) { - if (setTxids.count(tx->GetId())) { + if (setTxhashes.count(tx->GetHash())) { ntxFound++; } } - if (ntxFound != setTxids.size()) { + if (ntxFound != setTxhashes.size()) { throw JSONRPCError( RPC_INVALID_ADDRESS_OR_KEY, "(Not all) transactions not found in specified block"); } CDataStream ssMB(SER_NETWORK, PROTOCOL_VERSION); - CMerkleBlock mb(block, setTxids); + CMerkleBlock mb(block, setTxhashes); ssMB << mb; std::string strHex = HexStr(ssMB.begin(), ssMB.end()); return strHex; @@ -371,7 +370,7 @@ "1. \"proof\" (string, required) The hex-encoded proof " "generated by gettxoutproof\n" "\nResult:\n" - "[\"txid\"] (array, strings) The txid(s) which the proof " + "[\"txhash\"] (array, strings) The txhashes which the proof " "commits to, or empty array if the proof is invalid\n"); } @@ -409,7 +408,7 @@ if (request.fHelp || request.params.size() < 2 || request.params.size() > 3) { throw std::runtime_error( - "createrawtransaction [{\"txid\":\"id\",\"vout\":n},...] " + "createrawtransaction [{\"unspentid\":\"id\",\"vout\":n},...] " "{\"address\":amount,\"data\":\"hex\",...} ( locktime )\n" "\nCreate a transaction spending the given inputs and creating new " "outputs.\n" @@ -423,7 +422,8 @@ "json objects\n" " [\n" " {\n" - " \"txid\":\"id\", (string, required) The transaction " + " \"unspentid\":\"id\", (string, required) The unspent " + "transaction " "id\n" " \"vout\":n, (numeric, required) The output " "number\n" @@ -451,18 +451,22 @@ "transaction\n" "\nExamples:\n" + - HelpExampleCli("createrawtransaction", - "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" " - "\"{\\\"address\\\":0.01}\"") + - HelpExampleCli("createrawtransaction", - "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" " - "\"{\\\"data\\\":\\\"00010203\\\"}\"") + - HelpExampleRpc("createrawtransaction", - "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", " - "\"{\\\"address\\\":0.01}\"") + - HelpExampleRpc("createrawtransaction", - "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", " - "\"{\\\"data\\\":\\\"00010203\\\"}\"")); + HelpExampleCli( + "createrawtransaction", + "\"[{\\\"unspentid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" " + "\"{\\\"address\\\":0.01}\"") + + HelpExampleCli( + "createrawtransaction", + "\"[{\\\"unspentid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" " + "\"{\\\"data\\\":\\\"00010203\\\"}\"") + + HelpExampleRpc( + "createrawtransaction", + "\"[{\\\"unspentid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", " + "\"{\\\"address\\\":0.01}\"") + + HelpExampleRpc( + "createrawtransaction", + "\"[{\\\"unspentid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", " + "\"{\\\"data\\\":\\\"00010203\\\"}\"")); } RPCTypeCheck(request.params, @@ -492,7 +496,7 @@ const UniValue &input = inputs[idx]; const UniValue &o = input.get_obj(); - uint256 txid = ParseHashO(o, "txid"); + unspentid_t unspentid = unspentid_t(ParseHashO(o, "unspentid")); const UniValue &vout_v = find_value(o, "vout"); if (!vout_v.isNum()) { @@ -523,7 +527,7 @@ nSequence = uint32_t(seqNr64); } - CTxIn in(COutPoint(txid, nOutput), CScript(), nSequence); + CTxIn in(COutPoint(unspentid, nOutput), CScript(), nSequence); rawTx.vin.push_back(in); } @@ -576,15 +580,14 @@ "\nResult:\n" "{\n" - " \"txid\" : \"id\", (string) The transaction id\n" + " \"unspentid\" : \"id\", (string) The transaction id\n" " \"hash\" : \"id\", (string) The transaction hash " - "(differs from txid for witness transactions)\n" " \"size\" : n, (numeric) The transaction size\n" " \"version\" : n, (numeric) The version\n" " \"locktime\" : ttt, (numeric) The lock time\n" " \"vin\" : [ (array of json objects)\n" " {\n" - " \"txid\": \"id\", (string) The transaction id\n" + " \"unspentid\": \"id\", (string) The transaction id\n" " \"vout\": n, (numeric) The output number\n" " \"scriptSig\": { (json object) The script\n" " \"asm\": \"asm\", (string) asm\n" @@ -696,7 +699,7 @@ static void TxInErrorToJSON(const CTxIn &txin, UniValue &vErrorsRet, const std::string &strMessage) { UniValue entry(UniValue::VOBJ); - entry.push_back(Pair("txid", txin.prevout.hash.ToString())); + entry.push_back(Pair("unspentid", txin.prevout.unspentid.ToString())); entry.push_back(Pair("vout", (uint64_t)txin.prevout.n)); entry.push_back(Pair("scriptSig", HexStr(txin.scriptSig.begin(), txin.scriptSig.end()))); @@ -711,7 +714,7 @@ request.params.size() > 4) { throw std::runtime_error( "signrawtransaction \"hexstring\" ( " - "[{\"txid\":\"id\",\"vout\":n,\"scriptPubKey\":\"hex\"," + "[{\"unspentid\":\"id\",\"vout\":n,\"scriptPubKey\":\"hex\"," "\"redeemScript\":\"hex\"},...] [\"privatekey1\",...] sighashtype " ")\n" "\nSign inputs for raw transaction (serialized, hex-encoded).\n" @@ -736,7 +739,7 @@ " [ (json array of json objects, or 'null' if " "none provided)\n" " {\n" - " \"txid\":\"id\", (string, required) The " + " \"unspentid\":\"id\", (string, required) The " "transaction id\n" " \"vout\":n, (numeric, required) The " "output number\n" @@ -780,7 +783,7 @@ " \"errors\" : [ (json array of objects) Script " "verification errors (if there are any)\n" " {\n" - " \"txid\" : \"hash\", (string) The hash of the " + " \"unspentid\" : \"unspentid\", (string) The hash of the " "referenced, previous transaction\n" " \"vout\" : n, (numeric) The index of the " "output to spent and used as input\n" @@ -883,16 +886,17 @@ for (size_t idx = 0; idx < prevTxs.size(); idx++) { const UniValue &p = prevTxs[idx]; if (!p.isObject()) { - throw JSONRPCError(RPC_DESERIALIZATION_ERROR, - "expected object with " - "{\"txid'\",\"vout\",\"scriptPubKey\"}"); + throw JSONRPCError( + RPC_DESERIALIZATION_ERROR, + "expected object with " + "{\"unspentid'\",\"vout\",\"scriptPubKey\"}"); } UniValue prevOut = p.get_obj(); RPCTypeCheckObj(prevOut, { - {"txid", UniValueType(UniValue::VSTR)}, + {"unspentid", UniValueType(UniValue::VSTR)}, {"vout", UniValueType(UniValue::VNUM)}, {"scriptPubKey", UniValueType(UniValue::VSTR)}, // "amount" is also required but check is done @@ -901,7 +905,8 @@ // (which are valid JSON) }); - uint256 txid = ParseHashO(prevOut, "txid"); + const unspentid_t unspentid = + unspentid_t(ParseHashO(prevOut, "unspentid")); int nOut = find_value(prevOut, "vout").get_int(); if (nOut < 0) { @@ -909,7 +914,7 @@ "vout must be positive"); } - COutPoint out(txid, nOut); + COutPoint out(unspentid, nOut); std::vector pkData(ParseHexO(prevOut, "scriptPubKey")); CScript scriptPubKey(pkData.begin(), pkData.end()); @@ -951,7 +956,7 @@ if (fGivenKeys && scriptPubKey.IsPayToScriptHash()) { RPCTypeCheckObj( prevOut, { - {"txid", UniValueType(UniValue::VSTR)}, + {"unspentid", UniValueType(UniValue::VSTR)}, {"vout", UniValueType(UniValue::VNUM)}, {"scriptPubKey", UniValueType(UniValue::VSTR)}, {"redeemScript", UniValueType(UniValue::VSTR)}, @@ -1085,8 +1090,8 @@ "\nExamples:\n" "\nCreate a transaction\n" + HelpExampleCli("createrawtransaction", - "\"[{\\\"txid\\\" : " - "\\\"mytxid\\\",\\\"vout\\\":0}]\" " + "\"[{\\\"unspentid\\\" : " + "\\\"myunspentid\\\",\\\"vout\\\":0}]\" " "\"{\\\"myaddress\\\":0.01}\"") + "Sign the transaction, and get back the hex\n" + HelpExampleCli("signrawtransaction", "\"myhex\"") + @@ -1106,7 +1111,8 @@ } CTransactionRef tx(MakeTransactionRef(std::move(mtx))); - const uint256 &txid = tx->GetId(); + const unspentid_t &unspentid = tx->Getunspentid(); + const txhash_t &txhash = tx->GetHash(); bool fLimitFree = false; CAmount nMaxRawTxFee = maxTxFee; @@ -1117,11 +1123,11 @@ CCoinsViewCache &view = *pcoinsTip; bool fHaveChain = false; for (size_t o = 0; !fHaveChain && o < tx->vout.size(); o++) { - const Coin &existingCoin = view.AccessCoin(COutPoint(txid, o)); + const Coin &existingCoin = view.AccessCoin(COutPoint(unspentid, o)); fHaveChain = !existingCoin.IsSpent(); } - bool fHaveMempool = mempool.exists(txid); + bool fHaveMempool = mempool.exists(txhash); if (!fHaveMempool && !fHaveChain) { // Push to local node and sync with wallets. CValidationState state; @@ -1153,23 +1159,23 @@ "Error: Peer-to-peer functionality missing or disabled"); } - CInv inv(MSG_TX, txid); + CInv inv(MSG_TX, txhash); g_connman->ForEachNode([&inv](CNode *pnode) { pnode->PushInventory(inv); }); - return txid.GetHex(); + return txhash.GetHex(); } // clang-format off static const CRPCCommand commands[] = { // category name actor (function) okSafeMode // ------------------- ------------------------ ---------------------- ---------- - { "rawtransactions", "getrawtransaction", getrawtransaction, true, {"txid","verbose"} }, + { "rawtransactions", "getrawtransaction", getrawtransaction, true, {"txhash","verbose"} }, { "rawtransactions", "createrawtransaction", createrawtransaction, true, {"inputs","outputs","locktime"} }, { "rawtransactions", "decoderawtransaction", decoderawtransaction, true, {"hexstring"} }, { "rawtransactions", "decodescript", decodescript, true, {"hexstring"} }, { "rawtransactions", "sendrawtransaction", sendrawtransaction, false, {"hexstring","allowhighfees"} }, { "rawtransactions", "signrawtransaction", signrawtransaction, false, {"hexstring","prevtxs","privkeys","sighashtype"} }, /* uses wallet if enabled */ - { "blockchain", "gettxoutproof", gettxoutproof, true, {"txids", "blockhash"} }, + { "blockchain", "gettxoutproof", gettxoutproof, true, {"txhashes", "blockhash"} }, { "blockchain", "verifytxoutproof", verifytxoutproof, true, {"proof"} }, }; // clang-format on diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp --- a/src/test/DoS_tests.cpp +++ b/src/test/DoS_tests.cpp @@ -152,7 +152,7 @@ CMutableTransaction tx; tx.vin.resize(1); tx.vin[0].prevout.n = 0; - tx.vin[0].prevout.hash = GetRandHash(); + tx.vin[0].prevout.unspentid = unspentid_t(GetRandHash()); tx.vin[0].scriptSig << OP_1; tx.vout.resize(1); tx.vout[0].nValue = 1 * CENT.GetSatoshis(); @@ -169,7 +169,7 @@ CMutableTransaction tx; tx.vin.resize(1); tx.vin[0].prevout.n = 0; - tx.vin[0].prevout.hash = txPrev->GetId(); + tx.vin[0].prevout.unspentid = txPrev->GetUnspentid(); tx.vout.resize(1); tx.vout[0].nValue = 1 * CENT.GetSatoshis(); tx.vout[0].scriptPubKey = @@ -191,7 +191,7 @@ tx.vin.resize(2777); for (unsigned int j = 0; j < tx.vin.size(); j++) { tx.vin[j].prevout.n = j; - tx.vin[j].prevout.hash = txPrev->GetId(); + tx.vin[j].prevout.unspentid = txPrev->GetUnspentid(); } SignSignature(keystore, *txPrev, tx, 0, SIGHASH_ALL); // Re-use same signature for other inputs diff --git a/src/test/bitcoin-util-test.py b/src/test/bitcoin-util-test.py --- a/src/test/bitcoin-util-test.py +++ b/src/test/bitcoin-util-test.py @@ -1,16 +1,16 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright 2014 BitPay Inc. # Copyright 2016 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. -from __future__ import division,print_function,unicode_literals +from __future__ import division, print_function, unicode_literals import os import bctest import buildenv import argparse import logging -help_text="""Test framework for bitcoin utils. +help_text = """Test framework for bitcoin utils. Runs automatically during `make check`. @@ -40,6 +40,6 @@ level = logging.ERROR formatter = '%(asctime)s - %(levelname)s - %(message)s' # Add the format/level to the logger - logging.basicConfig(format = formatter, level=level) + logging.basicConfig(format=formatter, level=level) bctest.bctester(srcdir + "/test/data", "bitcoin-util-test.json", buildenv) diff --git a/src/test/blockcheck_tests.cpp b/src/test/blockcheck_tests.cpp --- a/src/test/blockcheck_tests.cpp +++ b/src/test/blockcheck_tests.cpp @@ -62,7 +62,7 @@ RunCheckOnBlock(config, block); // No coinbase - tx.vin[0].prevout.hash = GetRandHash(); + tx.vin[0].prevout.unspentid = unspentid_t(GetRandHash()); tx.vin[0].prevout.n = 0; block.vtx[0] = MakeTransactionRef(tx); @@ -83,7 +83,7 @@ auto maxTxCount = ((DEFAULT_MAX_BLOCK_SIZE - 1) / txSize) - 1; for (size_t i = 1; i < maxTxCount; i++) { - tx.vin[0].prevout.hash = GetRandHash(); + tx.vin[0].prevout.unspentid = unspentid_t(GetRandHash()); block.vtx.push_back(MakeTransactionRef(tx)); } @@ -92,7 +92,7 @@ // But reject it with one more transaction as it goes over the maximum // allowed block size. - tx.vin[0].prevout.hash = GetRandHash(); + tx.vin[0].prevout.unspentid = unspentid_t(GetRandHash()); block.vtx.push_back(MakeTransactionRef(tx)); RunCheckOnBlock(config, block, "bad-blk-length"); } diff --git a/src/test/blockencodings_tests.cpp b/src/test/blockencodings_tests.cpp --- a/src/test/blockencodings_tests.cpp +++ b/src/test/blockencodings_tests.cpp @@ -34,13 +34,13 @@ block.hashPrevBlock = GetRandHash(); block.nBits = 0x207fffff; - tx.vin[0].prevout.hash = GetRandHash(); + tx.vin[0].prevout.unspentid = unspentid_t(GetRandHash()); 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 = GetRandHash(); + tx.vin[i].prevout.unspentid = unspentid_t(GetRandHash()); tx.vin[i].prevout.n = 0; } block.vtx[2] = MakeTransactionRef(tx); @@ -63,19 +63,19 @@ TestMemPoolEntryHelper entry; CBlock block(BuildBlockTestCase()); - pool.addUnchecked(block.vtx[2]->GetId(), entry.FromTx(*block.vtx[2])); + pool.addUnchecked(block.vtx[2]->GetHash(), entry.FromTx(*block.vtx[2])); BOOST_CHECK_EQUAL( - pool.mapTx.find(block.vtx[2]->GetId())->GetSharedTx().use_count(), + pool.mapTx.find(block.vtx[2]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0); - // Do a simple ShortTxIDs RT + // Do a simple ShortTxHashes RT { - CBlockHeaderAndShortTxIDs shortIDs(block); + CBlockHeaderAndShortTxHashes shortIDs(block); CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); stream << shortIDs; - CBlockHeaderAndShortTxIDs shortIDs2; + CBlockHeaderAndShortTxHashes shortIDs2; stream >> shortIDs2; PartiallyDownloadedBlock partialBlock(GetConfig(), &pool); @@ -86,7 +86,7 @@ BOOST_CHECK(partialBlock.IsTxAvailable(2)); BOOST_CHECK_EQUAL( - pool.mapTx.find(block.vtx[2]->GetId())->GetSharedTx().use_count(), + pool.mapTx.find(block.vtx[2]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1); size_t poolSize = pool.size(); @@ -125,25 +125,25 @@ } class TestHeaderAndShortIDs { - // Utility to encode custom CBlockHeaderAndShortTxIDs + // Utility to encode custom CBlockHeaderAndShortTxHashes public: CBlockHeader header; uint64_t nonce; - std::vector shorttxids; + std::vector shortTxHashes; std::vector prefilledtxn; - TestHeaderAndShortIDs(const CBlockHeaderAndShortTxIDs &orig) { + TestHeaderAndShortIDs(const CBlockHeaderAndShortTxHashes &orig) { CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); stream << orig; stream >> *this; } TestHeaderAndShortIDs(const CBlock &block) - : TestHeaderAndShortIDs(CBlockHeaderAndShortTxIDs(block)) {} + : TestHeaderAndShortIDs(CBlockHeaderAndShortTxHashes(block)) {} - uint64_t GetShortID(const uint256 &txhash) const { + uint64_t GetShortID(const txhash_t &txhash) const { CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); stream << *this; - CBlockHeaderAndShortTxIDs base; + CBlockHeaderAndShortTxHashes base; stream >> base; return base.GetShortID(txhash); } @@ -154,15 +154,15 @@ inline void SerializationOp(Stream &s, Operation ser_action) { READWRITE(header); READWRITE(nonce); - size_t shorttxids_size = shorttxids.size(); - READWRITE(VARINT(shorttxids_size)); - shorttxids.resize(shorttxids_size); - for (size_t i = 0; i < shorttxids.size(); i++) { - uint32_t lsb = shorttxids[i] & 0xffffffff; - uint16_t msb = (shorttxids[i] >> 32) & 0xffff; + size_t shortTxHashes_size = shortTxHashes.size(); + READWRITE(VARINT(shortTxHashes_size)); + shortTxHashes.resize(shortTxHashes_size); + for (size_t i = 0; i < shortTxHashes.size(); i++) { + uint32_t lsb = shortTxHashes[i] & 0xffffffff; + uint16_t msb = (shortTxHashes[i] >> 32) & 0xffff; READWRITE(lsb); READWRITE(msb); - shorttxids[i] = (uint64_t(msb) << 32) | uint64_t(lsb); + shortTxHashes[i] = (uint64_t(msb) << 32) | uint64_t(lsb); } READWRITE(prefilledtxn); } @@ -173,26 +173,28 @@ TestMemPoolEntryHelper entry; CBlock block(BuildBlockTestCase()); - pool.addUnchecked(block.vtx[2]->GetId(), entry.FromTx(*block.vtx[2])); + pool.addUnchecked(block.vtx[2]->GetHash(), entry.FromTx(*block.vtx[2])); BOOST_CHECK_EQUAL( - pool.mapTx.find(block.vtx[2]->GetId())->GetSharedTx().use_count(), + pool.mapTx.find(block.vtx[2]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0); - uint256 txhash; + txhash_t txhash; // Test with pre-forwarding tx 1, but not coinbase { TestHeaderAndShortIDs shortIDs(block); shortIDs.prefilledtxn.resize(1); shortIDs.prefilledtxn[0] = {1, block.vtx[1]}; - shortIDs.shorttxids.resize(2); - shortIDs.shorttxids[0] = shortIDs.GetShortID(block.vtx[0]->GetId()); - shortIDs.shorttxids[1] = shortIDs.GetShortID(block.vtx[2]->GetId()); + shortIDs.shortTxHashes.resize(2); + shortIDs.shortTxHashes[0] = + shortIDs.GetShortID(block.vtx[0]->GetHash()); + shortIDs.shortTxHashes[1] = + shortIDs.GetShortID(block.vtx[2]->GetHash()); CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); stream << shortIDs; - CBlockHeaderAndShortTxIDs shortIDs2; + CBlockHeaderAndShortTxHashes shortIDs2; stream >> shortIDs2; PartiallyDownloadedBlock partialBlock(GetConfig(), &pool); @@ -203,7 +205,7 @@ BOOST_CHECK(partialBlock.IsTxAvailable(2)); BOOST_CHECK_EQUAL( - pool.mapTx.find(block.vtx[2]->GetId())->GetSharedTx().use_count(), + pool.mapTx.find(block.vtx[2]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1); CBlock block2; @@ -236,7 +238,7 @@ BlockMerkleRoot(block3, &mutated).ToString()); BOOST_CHECK(!mutated); - txhash = block.vtx[2]->GetId(); + txhash = block.vtx[2]->GetHash(); block.vtx.clear(); block2.vtx.clear(); block3.vtx.clear(); @@ -254,12 +256,12 @@ TestMemPoolEntryHelper entry; CBlock block(BuildBlockTestCase()); - pool.addUnchecked(block.vtx[1]->GetId(), entry.FromTx(*block.vtx[1])); + pool.addUnchecked(block.vtx[1]->GetHash(), entry.FromTx(*block.vtx[1])); BOOST_CHECK_EQUAL( - pool.mapTx.find(block.vtx[1]->GetId())->GetSharedTx().use_count(), + pool.mapTx.find(block.vtx[1]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0); - uint256 txhash; + txhash_t txhash; // Test with pre-forwarding coinbase + tx 2 with tx 1 in mempool { @@ -268,13 +270,14 @@ shortIDs.prefilledtxn[0] = {0, block.vtx[0]}; // id == 1 as it is 1 after index 1 shortIDs.prefilledtxn[1] = {1, block.vtx[2]}; - shortIDs.shorttxids.resize(1); - shortIDs.shorttxids[0] = shortIDs.GetShortID(block.vtx[1]->GetId()); + shortIDs.shortTxHashes.resize(1); + shortIDs.shortTxHashes[0] = + shortIDs.GetShortID(block.vtx[1]->GetHash()); CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); stream << shortIDs; - CBlockHeaderAndShortTxIDs shortIDs2; + CBlockHeaderAndShortTxHashes shortIDs2; stream >> shortIDs2; PartiallyDownloadedBlock partialBlock(GetConfig(), &pool); @@ -285,7 +288,7 @@ BOOST_CHECK(partialBlock.IsTxAvailable(2)); BOOST_CHECK_EQUAL( - pool.mapTx.find(block.vtx[1]->GetId())->GetSharedTx().use_count(), + pool.mapTx.find(block.vtx[1]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1); CBlock block2; @@ -298,7 +301,7 @@ BlockMerkleRoot(block2, &mutated).ToString()); BOOST_CHECK(!mutated); - txhash = block.vtx[1]->GetId(); + txhash = block.vtx[1]->GetHash(); block.vtx.clear(); block2.vtx.clear(); @@ -334,12 +337,12 @@ // Test simple header round-trip with only coinbase { - CBlockHeaderAndShortTxIDs shortIDs(block); + CBlockHeaderAndShortTxHashes shortIDs(block); CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); stream << shortIDs; - CBlockHeaderAndShortTxIDs shortIDs2; + CBlockHeaderAndShortTxHashes shortIDs2; stream >> shortIDs2; PartiallyDownloadedBlock partialBlock(GetConfig(), &pool); diff --git a/src/test/bloom_tests.cpp b/src/test/bloom_tests.cpp --- a/src/test/bloom_tests.cpp +++ b/src/test/bloom_tests.cpp @@ -216,19 +216,21 @@ "Simple Bloom filter didn't match output address"); filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); - filter.insert(COutPoint(uint256S("0x90c122d70786e899529d71dbeba91ba216982fb" - "6ba58f3bdaab65e73b7e9260b"), - 0)); + filter.insert(COutPoint( + unspentid_t(uint256S("0x90c122d70786e899529d71dbeba91ba216982fb" + "6ba58f3bdaab65e73b7e9260b")), + 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("0x90c122d70786e899529d71dbeba91ba216982fb6" - "ba58f3bdaab65e73b7e9260b"), - 0); + COutPoint prevOutPoint( + unspentid_t(uint256S("0x90c122d70786e899529d71dbeba91ba216982fb6" + "ba58f3bdaab65e73b7e9260b")), + 0); { std::vector data(32 + sizeof(unsigned int)); - memcpy(&data[0], prevOutPoint.hash.begin(), 32); + memcpy(&data[0], prevOutPoint.unspentid.begin(), 32); memcpy(&data[32], &prevOutPoint.n, sizeof(unsigned int)); filter.insert(data); } @@ -248,17 +250,19 @@ "Simple Bloom filter matched random address"); filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); - filter.insert(COutPoint(uint256S("0x90c122d70786e899529d71dbeba91ba216982fb" - "6ba58f3bdaab65e73b7e9260b"), - 1)); + filter.insert(COutPoint( + unspentid_t(uint256S("0x90c122d70786e899529d71dbeba91ba216982fb" + "6ba58f3bdaab65e73b7e9260b")), + 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("0x000000d70786e899529d71dbeba91ba216982fb" - "6ba58f3bdaab65e73b7e9260b"), - 0)); + filter.insert(COutPoint( + unspentid_t(uint256S("0x000000d70786e899529d71dbeba91ba216982fb" + "6ba58f3bdaab65e73b7e9260b")), + 0)); BOOST_CHECK_MESSAGE(!filter.IsRelevantAndUpdate(tx), "Simple Bloom filter matched COutPoint for an output " "we didn't care about"); @@ -928,15 +932,15 @@ BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash()); // We should match the generation outpoint - BOOST_CHECK( - filter.contains(COutPoint(uint256S("0x147caa76786596590baa4e98f5d9f48b8" - "6c7765e489f7a6ff3360fe5c674360b"), - 0))); + BOOST_CHECK(filter.contains( + COutPoint(unspentid_t(uint256S("0x147caa76786596590baa4e98f5d9f48b8" + "6c7765e489f7a6ff3360fe5c674360b")), + 0))); // ... but not the 4th transaction's output (its not pay-2-pubkey) - BOOST_CHECK( - !filter.contains(COutPoint(uint256S("0x02981fa052f0481dbc5868f4fc216603" - "5a10f27a03cfd2de67326471df5bc041"), - 0))); + BOOST_CHECK(!filter.contains( + COutPoint(unspentid_t(uint256S("0x02981fa052f0481dbc5868f4fc216603" + "5a10f27a03cfd2de67326471df5bc041")), + 0))); } BOOST_AUTO_TEST_CASE(merkle_block_4_test_update_none) { @@ -1039,14 +1043,14 @@ BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash()); // We shouldn't match any outpoints (UPDATE_NONE) - BOOST_CHECK( - !filter.contains(COutPoint(uint256S("0x147caa76786596590baa4e98f5d9f48b" - "86c7765e489f7a6ff3360fe5c674360b"), - 0))); - BOOST_CHECK( - !filter.contains(COutPoint(uint256S("0x02981fa052f0481dbc5868f4fc216603" - "5a10f27a03cfd2de67326471df5bc041"), - 0))); + BOOST_CHECK(!filter.contains( + COutPoint(unspentid_t(uint256S("0x147caa76786596590baa4e98f5d9f48b" + "86c7765e489f7a6ff3360fe5c674360b")), + 0))); + BOOST_CHECK(!filter.contains( + COutPoint(unspentid_t(uint256S("0x02981fa052f0481dbc5868f4fc216603" + "5a10f27a03cfd2de67326471df5bc041")), + 0))); } static std::vector RandomData() { diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp --- a/src/test/coins_tests.cpp +++ b/src/test/coins_tests.cpp @@ -106,7 +106,7 @@ // stack of caches on top of CCoinsViewTest. // // It will randomly create/update/delete Coin entries to a tip of caches, with -// txids picked from a limited list of random 256-bit hashes. Occasionally, a +// txhashes picked from a limited list of random 256-bit hashes. Occasionally, a // new tip is added to the stack of caches, or the tip is flushed and removed. // // During the process, booleans are kept to make sure that the randomized @@ -136,22 +136,21 @@ // Use a limited set of random transaction ids, so we do test overwriting // entries. - std::vector txids; - txids.resize(NUM_SIMULATION_ITERATIONS / 8); - for (size_t i = 0; i < txids.size(); i++) { - txids[i] = GetRandHash(); + std::vector unspentids; + unspentids.resize(NUM_SIMULATION_ITERATIONS / 8); + for (size_t i = 0; i < unspentids.size(); i++) { + unspentids[i] = unspentid_t(GetRandHash()); } for (unsigned int i = 0; i < NUM_SIMULATION_ITERATIONS; i++) { // Do a random modification. { - // txid we're going to modify in this iteration. - uint256 txid = txids[insecure_rand() % txids.size()]; - Coin &coin = result[COutPoint(txid, 0)]; + // unspentid we're going to modify in this iteration. + unspentid_t unspentid = + unspentids[insecure_rand() % unspentids.size()]; + Coin &coin = result[COutPoint(unspentid, 0)]; const Coin &entry = - (insecure_rand() % 500 == 0) - ? AccessByTxid(*stack.back(), txid) - : stack.back()->AccessCoin(COutPoint(txid, 0)); + stack.back()->AccessCoin(COutPoint(unspentid, 0)); BOOST_CHECK(coin == entry); if (insecure_rand() % 5 == 0 || coin.IsSpent()) { @@ -170,18 +169,18 @@ } Coin newcoin(txout, 1, false); - stack.back()->AddCoin(COutPoint(txid, 0), newcoin, + stack.back()->AddCoin(COutPoint(unspentid, 0), newcoin, !coin.IsSpent() || insecure_rand() & 1); } else { removed_an_entry = true; coin.Clear(); - stack.back()->SpendCoin(COutPoint(txid, 0)); + stack.back()->SpendCoin(COutPoint(unspentid, 0)); } } // One every 10 iterations, remove a random entry from the cache if (insecure_rand() % 10) { - COutPoint out(txids[insecure_rand() % txids.size()], 0); + COutPoint out(unspentids[insecure_rand() % unspentids.size()], 0); int cacheid = insecure_rand() % stack.size(); stack[cacheid]->Uncache(out); uncached_an_entry |= !stack[cacheid]->HaveCoinInCache(out); @@ -262,7 +261,8 @@ UtxoData::iterator FindRandomFrom(const std::set &utxoSet) { assert(utxoSet.size()); - auto utxoSetIt = utxoSet.lower_bound(COutPoint(GetRandHash(), 0)); + auto utxoSetIt = + utxoSet.lower_bound(COutPoint(unspentid_t(GetRandHash()), 0)); if (utxoSetIt == utxoSet.end()) { utxoSetIt = utxoSet.begin(); } @@ -289,7 +289,7 @@ // Start with one cache. stack.push_back(new CCoinsViewCacheTest(&base)); - // Track the txids we've used in various sets + // Track the unspentids we've used in various sets std::set coinbase_coins; std::set disconnected_coins; std::set duplicate_coins; @@ -323,7 +323,7 @@ duplicate_coins.insert(utxod->first); } else { - coinbase_coins.insert(COutPoint(tx.GetId(), 0)); + coinbase_coins.insert(COutPoint(tx.Getunspentid(), 0)); } assert(CTransaction(tx).IsCoinBase()); } @@ -381,7 +381,7 @@ } // Update the expected result to know about the new output coins assert(tx.vout.size() == 1); - const COutPoint outpoint(tx.GetId(), 0); + const COutPoint outpoint(tx.Getunspentid(), 0); result[outpoint] = Coin(tx.vout[0], height, CTransaction(tx).IsCoinBase()); diff --git a/src/test/mempool_tests.cpp b/src/test/mempool_tests.cpp --- a/src/test/mempool_tests.cpp +++ b/src/test/mempool_tests.cpp @@ -31,7 +31,7 @@ for (int i = 0; i < 3; i++) { txChild[i].vin.resize(1); txChild[i].vin[0].scriptSig = CScript() << OP_11; - txChild[i].vin[0].prevout.hash = txParent.GetId(); + txChild[i].vin[0].prevout.unspentid = txParent.GetUnspentid(); txChild[i].vin[0].prevout.n = i; txChild[i].vout.resize(1); txChild[i].vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; @@ -41,7 +41,7 @@ for (int i = 0; i < 3; i++) { txGrandChild[i].vin.resize(1); txGrandChild[i].vin[0].scriptSig = CScript() << OP_11; - txGrandChild[i].vin[0].prevout.hash = txChild[i].GetId(); + txGrandChild[i].vin[0].prevout.unspentid = txChild[i].GetUnspentid(); txGrandChild[i].vin[0].prevout.n = 0; txGrandChild[i].vout.resize(1); txGrandChild[i].vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; @@ -56,16 +56,16 @@ BOOST_CHECK_EQUAL(testPool.size(), poolSize); // Just the parent: - testPool.addUnchecked(txParent.GetId(), entry.FromTx(txParent)); + testPool.addUnchecked(txParent.GetHash(), entry.FromTx(txParent)); poolSize = testPool.size(); testPool.removeRecursive(txParent); BOOST_CHECK_EQUAL(testPool.size(), poolSize - 1); // Parent, children, grandchildren: - testPool.addUnchecked(txParent.GetId(), entry.FromTx(txParent)); + testPool.addUnchecked(txParent.GetHash(), entry.FromTx(txParent)); for (int i = 0; i < 3; i++) { - testPool.addUnchecked(txChild[i].GetId(), entry.FromTx(txChild[i])); - testPool.addUnchecked(txGrandChild[i].GetId(), + testPool.addUnchecked(txChild[i].GetHash(), entry.FromTx(txChild[i])); + testPool.addUnchecked(txGrandChild[i].GetHash(), entry.FromTx(txGrandChild[i])); } // Remove Child[0], GrandChild[0] should be removed: @@ -88,8 +88,8 @@ // Add children and grandchildren, but NOT the parent (simulate the parent // being in a block) for (int i = 0; i < 3; i++) { - testPool.addUnchecked(txChild[i].GetId(), entry.FromTx(txChild[i])); - testPool.addUnchecked(txGrandChild[i].GetId(), + testPool.addUnchecked(txChild[i].GetHash(), entry.FromTx(txChild[i])); + testPool.addUnchecked(txGrandChild[i].GetHash(), entry.FromTx(txGrandChild[i])); } @@ -122,7 +122,7 @@ BOOST_CHECK_EQUAL(testPool.size(), 0); // Add the transaction - testPool.addUnchecked(txParent.GetId(), entry.FromTx(txParent)); + testPool.addUnchecked(txParent.GetHash(), entry.FromTx(txParent)); BOOST_CHECK_EQUAL(testPool.size(), 1); BOOST_CHECK_EQUAL(testPool.mapTx.size(), 1); BOOST_CHECK_EQUAL(testPool.mapNextTx.size(), 1); @@ -143,7 +143,7 @@ it = pool.mapTx.get().begin(); int count = 0; for (; it != pool.mapTx.get().end(); ++it, ++count) { - BOOST_CHECK_EQUAL(it->GetTx().GetId().ToString(), sortedOrder[count]); + BOOST_CHECK_EQUAL(it->GetTx().GetHash().ToString(), sortedOrder[count]); } } @@ -156,7 +156,7 @@ tx1.vout.resize(1); tx1.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx1.vout[0].nValue = 10 * COIN.GetSatoshis(); - pool.addUnchecked(tx1.GetId(), + pool.addUnchecked(tx1.GetHash(), entry.Fee(10000LL).Priority(10.0).FromTx(tx1)); /* highest fee */ @@ -164,7 +164,7 @@ tx2.vout.resize(1); tx2.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx2.vout[0].nValue = 2 * COIN.GetSatoshis(); - pool.addUnchecked(tx2.GetId(), + pool.addUnchecked(tx2.GetHash(), entry.Fee(20000LL).Priority(9.0).FromTx(tx2)); /* lowest fee */ @@ -172,14 +172,15 @@ tx3.vout.resize(1); tx3.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx3.vout[0].nValue = 5 * COIN.GetSatoshis(); - pool.addUnchecked(tx3.GetId(), entry.Fee(0LL).Priority(100.0).FromTx(tx3)); + pool.addUnchecked(tx3.GetHash(), + entry.Fee(0LL).Priority(100.0).FromTx(tx3)); /* 2nd highest fee */ CMutableTransaction tx4 = CMutableTransaction(); tx4.vout.resize(1); tx4.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx4.vout[0].nValue = 6 * COIN.GetSatoshis(); - pool.addUnchecked(tx4.GetId(), + pool.addUnchecked(tx4.GetHash(), entry.Fee(15000LL).Priority(1.0).FromTx(tx4)); /* equal fee rate to tx1, but newer */ @@ -189,16 +190,16 @@ tx5.vout[0].nValue = 11 * COIN.GetSatoshis(); entry.nTime = 1; entry.dPriority = 10.0; - pool.addUnchecked(tx5.GetId(), entry.Fee(10000LL).FromTx(tx5)); + pool.addUnchecked(tx5.GetHash(), entry.Fee(10000LL).FromTx(tx5)); BOOST_CHECK_EQUAL(pool.size(), 5); std::vector sortedOrder; sortedOrder.resize(5); - sortedOrder[0] = tx3.GetId().ToString(); // 0 - sortedOrder[1] = tx5.GetId().ToString(); // 10000 - sortedOrder[2] = tx1.GetId().ToString(); // 10000 - sortedOrder[3] = tx4.GetId().ToString(); // 15000 - sortedOrder[4] = tx2.GetId().ToString(); // 20000 + sortedOrder[0] = tx3.GetHash().ToString(); // 0 + sortedOrder[1] = tx5.GetHash().ToString(); // 10000 + sortedOrder[2] = tx1.GetHash().ToString(); // 10000 + sortedOrder[3] = tx4.GetHash().ToString(); // 15000 + sortedOrder[4] = tx2.GetHash().ToString(); // 20000 CheckSort(pool, sortedOrder); /* low fee but with high fee child */ @@ -207,17 +208,17 @@ tx6.vout.resize(1); tx6.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx6.vout[0].nValue = 20 * COIN.GetSatoshis(); - pool.addUnchecked(tx6.GetId(), entry.Fee(0LL).FromTx(tx6)); + pool.addUnchecked(tx6.GetHash(), entry.Fee(0LL).FromTx(tx6)); BOOST_CHECK_EQUAL(pool.size(), 6); // Check that at this point, tx6 is sorted low - sortedOrder.insert(sortedOrder.begin(), tx6.GetId().ToString()); + sortedOrder.insert(sortedOrder.begin(), tx6.GetHash().ToString()); CheckSort(pool, sortedOrder); CTxMemPool::setEntries setAncestors; - setAncestors.insert(pool.mapTx.find(tx6.GetId())); + setAncestors.insert(pool.mapTx.find(tx6.GetHash())); CMutableTransaction tx7 = CMutableTransaction(); tx7.vin.resize(1); - tx7.vin[0].prevout = COutPoint(tx6.GetId(), 0); + tx7.vin[0].prevout = COutPoint(tx6.GetUnspentid(), 0); tx7.vin[0].scriptSig = CScript() << OP_11; tx7.vout.resize(2); tx7.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; @@ -234,57 +235,57 @@ true); BOOST_CHECK(setAncestorsCalculated == setAncestors); - pool.addUnchecked(tx7.GetId(), entry.FromTx(tx7), setAncestors); + pool.addUnchecked(tx7.GetHash(), entry.FromTx(tx7), setAncestors); BOOST_CHECK_EQUAL(pool.size(), 7); // Now tx6 should be sorted higher (high fee child): tx7, tx6, tx2, ... sortedOrder.erase(sortedOrder.begin()); - sortedOrder.push_back(tx6.GetId().ToString()); - sortedOrder.push_back(tx7.GetId().ToString()); + sortedOrder.push_back(tx6.GetHash().ToString()); + sortedOrder.push_back(tx7.GetHash().ToString()); CheckSort(pool, sortedOrder); /* low fee child of tx7 */ CMutableTransaction tx8 = CMutableTransaction(); tx8.vin.resize(1); - tx8.vin[0].prevout = COutPoint(tx7.GetId(), 0); + tx8.vin[0].prevout = COutPoint(tx7.GetUnspentid(), 0); tx8.vin[0].scriptSig = CScript() << OP_11; tx8.vout.resize(1); tx8.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx8.vout[0].nValue = 10 * COIN.GetSatoshis(); - setAncestors.insert(pool.mapTx.find(tx7.GetId())); - pool.addUnchecked(tx8.GetId(), entry.Fee(0LL).Time(2).FromTx(tx8), + setAncestors.insert(pool.mapTx.find(tx7.GetHash())); + pool.addUnchecked(tx8.GetHash(), entry.Fee(0LL).Time(2).FromTx(tx8), setAncestors); // Now tx8 should be sorted low, but tx6/tx both high - sortedOrder.insert(sortedOrder.begin(), tx8.GetId().ToString()); + sortedOrder.insert(sortedOrder.begin(), tx8.GetHash().ToString()); CheckSort(pool, sortedOrder); /* low fee child of tx7 */ CMutableTransaction tx9 = CMutableTransaction(); tx9.vin.resize(1); - tx9.vin[0].prevout = COutPoint(tx7.GetId(), 1); + tx9.vin[0].prevout = COutPoint(tx7.GetUnspentid(), 1); tx9.vin[0].scriptSig = CScript() << OP_11; tx9.vout.resize(1); tx9.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx9.vout[0].nValue = 1 * COIN.GetSatoshis(); - pool.addUnchecked(tx9.GetId(), entry.Fee(0LL).Time(3).FromTx(tx9), + pool.addUnchecked(tx9.GetHash(), entry.Fee(0LL).Time(3).FromTx(tx9), setAncestors); // tx9 should be sorted low BOOST_CHECK_EQUAL(pool.size(), 9); - sortedOrder.insert(sortedOrder.begin(), tx9.GetId().ToString()); + sortedOrder.insert(sortedOrder.begin(), tx9.GetHash().ToString()); CheckSort(pool, sortedOrder); std::vector snapshotOrder = sortedOrder; - setAncestors.insert(pool.mapTx.find(tx8.GetId())); - setAncestors.insert(pool.mapTx.find(tx9.GetId())); + setAncestors.insert(pool.mapTx.find(tx8.GetHash())); + setAncestors.insert(pool.mapTx.find(tx9.GetHash())); /* tx10 depends on tx8 and tx9 and has a high fee*/ CMutableTransaction tx10 = CMutableTransaction(); tx10.vin.resize(2); - tx10.vin[0].prevout = COutPoint(tx8.GetId(), 0); + tx10.vin[0].prevout = COutPoint(tx8.GetUnspentid(), 0); tx10.vin[0].scriptSig = CScript() << OP_11; - tx10.vin[1].prevout = COutPoint(tx9.GetId(), 0); + tx10.vin[1].prevout = COutPoint(tx9.GetUnspentid(), 0); tx10.vin[1].scriptSig = CScript() << OP_11; tx10.vout.resize(1); tx10.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; @@ -298,7 +299,7 @@ true); BOOST_CHECK(setAncestorsCalculated == setAncestors); - pool.addUnchecked(tx10.GetId(), entry.FromTx(tx10), setAncestors); + pool.addUnchecked(tx10.GetHash(), entry.FromTx(tx10), setAncestors); /** * tx8 and tx9 should both now be sorted higher @@ -317,21 +318,21 @@ */ // take out tx9, tx8 from the beginning sortedOrder.erase(sortedOrder.begin(), sortedOrder.begin() + 2); - sortedOrder.insert(sortedOrder.begin() + 5, tx9.GetId().ToString()); - sortedOrder.insert(sortedOrder.begin() + 6, tx8.GetId().ToString()); + sortedOrder.insert(sortedOrder.begin() + 5, tx9.GetHash().ToString()); + sortedOrder.insert(sortedOrder.begin() + 6, tx8.GetHash().ToString()); // tx10 is just before tx6 - sortedOrder.insert(sortedOrder.begin() + 7, tx10.GetId().ToString()); + sortedOrder.insert(sortedOrder.begin() + 7, tx10.GetHash().ToString()); CheckSort(pool, sortedOrder); // there should be 10 transactions in the mempool BOOST_CHECK_EQUAL(pool.size(), 10); // Now try removing tx10 and verify the sort order returns to normal - pool.removeRecursive(pool.mapTx.find(tx10.GetId())->GetTx()); + pool.removeRecursive(pool.mapTx.find(tx10.GetHash())->GetTx()); CheckSort(pool, snapshotOrder); - pool.removeRecursive(pool.mapTx.find(tx9.GetId())->GetTx()); - pool.removeRecursive(pool.mapTx.find(tx8.GetId())->GetTx()); + pool.removeRecursive(pool.mapTx.find(tx9.GetHash())->GetTx()); + pool.removeRecursive(pool.mapTx.find(tx8.GetHash())->GetTx()); /* Now check the sort on the mining score index. * Final order should be: * @@ -343,22 +344,22 @@ * (Ties resolved by hash) */ sortedOrder.clear(); - sortedOrder.push_back(tx7.GetId().ToString()); - sortedOrder.push_back(tx2.GetId().ToString()); - sortedOrder.push_back(tx4.GetId().ToString()); - if (tx1.GetId() < tx5.GetId()) { - sortedOrder.push_back(tx5.GetId().ToString()); - sortedOrder.push_back(tx1.GetId().ToString()); + sortedOrder.push_back(tx7.GetHash().ToString()); + sortedOrder.push_back(tx2.GetHash().ToString()); + sortedOrder.push_back(tx4.GetHash().ToString()); + if (tx1.GetHash() < tx5.GetHash()) { + sortedOrder.push_back(tx5.GetHash().ToString()); + sortedOrder.push_back(tx1.GetHash().ToString()); } else { - sortedOrder.push_back(tx1.GetId().ToString()); - sortedOrder.push_back(tx5.GetId().ToString()); + sortedOrder.push_back(tx1.GetHash().ToString()); + sortedOrder.push_back(tx5.GetHash().ToString()); } - if (tx3.GetId() < tx6.GetId()) { - sortedOrder.push_back(tx6.GetId().ToString()); - sortedOrder.push_back(tx3.GetId().ToString()); + if (tx3.GetHash() < tx6.GetHash()) { + sortedOrder.push_back(tx6.GetHash().ToString()); + sortedOrder.push_back(tx3.GetHash().ToString()); } else { - sortedOrder.push_back(tx3.GetId().ToString()); - sortedOrder.push_back(tx6.GetId().ToString()); + sortedOrder.push_back(tx3.GetHash().ToString()); + sortedOrder.push_back(tx6.GetHash().ToString()); } CheckSort(pool, sortedOrder); } @@ -372,7 +373,7 @@ tx1.vout.resize(1); tx1.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx1.vout[0].nValue = 10 * COIN.GetSatoshis(); - pool.addUnchecked(tx1.GetId(), + pool.addUnchecked(tx1.GetHash(), entry.Fee(10000LL).Priority(10.0).FromTx(tx1)); /* highest fee */ @@ -380,7 +381,7 @@ tx2.vout.resize(1); tx2.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx2.vout[0].nValue = 2 * COIN.GetSatoshis(); - pool.addUnchecked(tx2.GetId(), + pool.addUnchecked(tx2.GetHash(), entry.Fee(20000LL).Priority(9.0).FromTx(tx2)); uint64_t tx2Size = GetTransactionSize(tx2); @@ -389,14 +390,15 @@ tx3.vout.resize(1); tx3.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx3.vout[0].nValue = 5 * COIN.GetSatoshis(); - pool.addUnchecked(tx3.GetId(), entry.Fee(0LL).Priority(100.0).FromTx(tx3)); + pool.addUnchecked(tx3.GetHash(), + entry.Fee(0LL).Priority(100.0).FromTx(tx3)); /* 2nd highest fee */ CMutableTransaction tx4 = CMutableTransaction(); tx4.vout.resize(1); tx4.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx4.vout[0].nValue = 6 * COIN.GetSatoshis(); - pool.addUnchecked(tx4.GetId(), + pool.addUnchecked(tx4.GetHash(), entry.Fee(15000LL).Priority(1.0).FromTx(tx4)); /* equal fee rate to tx1, but newer */ @@ -404,24 +406,24 @@ tx5.vout.resize(1); tx5.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx5.vout[0].nValue = 11 * COIN.GetSatoshis(); - pool.addUnchecked(tx5.GetId(), entry.Fee(10000LL).FromTx(tx5)); + pool.addUnchecked(tx5.GetHash(), entry.Fee(10000LL).FromTx(tx5)); BOOST_CHECK_EQUAL(pool.size(), 5); std::vector sortedOrder; sortedOrder.resize(5); - sortedOrder[0] = tx2.GetId().ToString(); // 20000 - sortedOrder[1] = tx4.GetId().ToString(); // 15000 + sortedOrder[0] = tx2.GetHash().ToString(); // 20000 + sortedOrder[1] = tx4.GetHash().ToString(); // 15000 // tx1 and tx5 are both 10000 // Ties are broken by hash, not timestamp, so determine which hash comes // first. - if (tx1.GetId() < tx5.GetId()) { - sortedOrder[2] = tx1.GetId().ToString(); - sortedOrder[3] = tx5.GetId().ToString(); + if (tx1.GetHash() < tx5.GetHash()) { + sortedOrder[2] = tx1.GetHash().ToString(); + sortedOrder[3] = tx5.GetHash().ToString(); } else { - sortedOrder[2] = tx5.GetId().ToString(); - sortedOrder[3] = tx1.GetId().ToString(); + sortedOrder[2] = tx5.GetHash().ToString(); + sortedOrder[3] = tx1.GetHash().ToString(); } - sortedOrder[4] = tx3.GetId().ToString(); // 0 + sortedOrder[4] = tx3.GetHash().ToString(); // 0 CheckSort(pool, sortedOrder); @@ -433,20 +435,20 @@ tx6.vout[0].nValue = 20 * COIN.GetSatoshis(); uint64_t tx6Size = GetTransactionSize(tx6); - pool.addUnchecked(tx6.GetId(), entry.Fee(0LL).FromTx(tx6)); + pool.addUnchecked(tx6.GetHash(), entry.Fee(0LL).FromTx(tx6)); BOOST_CHECK_EQUAL(pool.size(), 6); // Ties are broken by hash - if (tx3.GetId() < tx6.GetId()) { - sortedOrder.push_back(tx6.GetId().ToString()); + if (tx3.GetHash() < tx6.GetHash()) { + sortedOrder.push_back(tx6.GetHash().ToString()); } else { - sortedOrder.insert(sortedOrder.end() - 1, tx6.GetId().ToString()); + sortedOrder.insert(sortedOrder.end() - 1, tx6.GetHash().ToString()); } CheckSort(pool, sortedOrder); CMutableTransaction tx7 = CMutableTransaction(); tx7.vin.resize(1); - tx7.vin[0].prevout = COutPoint(tx6.GetId(), 0); + tx7.vin[0].prevout = COutPoint(tx6.GetUnspentid(), 0); tx7.vin[0].scriptSig = CScript() << OP_11; tx7.vout.resize(1); tx7.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; @@ -457,9 +459,9 @@ CAmount fee = (20000 / tx2Size) * (tx7Size + tx6Size) - 1; // CTxMemPoolEntry entry7(tx7, fee, 2, 10.0, 1, true); - pool.addUnchecked(tx7.GetId(), entry.Fee(fee).FromTx(tx7)); + pool.addUnchecked(tx7.GetHash(), entry.Fee(fee).FromTx(tx7)); BOOST_CHECK_EQUAL(pool.size(), 7); - sortedOrder.insert(sortedOrder.begin() + 1, tx7.GetId().ToString()); + sortedOrder.insert(sortedOrder.begin() + 1, tx7.GetHash().ToString()); CheckSort(pool, sortedOrder); /* after tx6 is mined, tx7 should move up in the sort */ @@ -469,11 +471,11 @@ sortedOrder.erase(sortedOrder.begin() + 1); // Ties are broken by hash - if (tx3.GetId() < tx6.GetId()) + if (tx3.GetHash() < tx6.GetHash()) sortedOrder.pop_back(); else sortedOrder.erase(sortedOrder.end() - 2); - sortedOrder.insert(sortedOrder.begin(), tx7.GetId().ToString()); + sortedOrder.insert(sortedOrder.begin(), tx7.GetHash().ToString()); CheckSort(pool, sortedOrder); } @@ -488,7 +490,7 @@ tx1.vout.resize(1); tx1.vout[0].scriptPubKey = CScript() << OP_1 << OP_EQUAL; tx1.vout[0].nValue = 10 * COIN.GetSatoshis(); - pool.addUnchecked(tx1.GetId(), entry.Fee(10000LL).FromTx(tx1, &pool)); + pool.addUnchecked(tx1.GetHash(), entry.Fee(10000LL).FromTx(tx1, &pool)); CMutableTransaction tx2 = CMutableTransaction(); tx2.vin.resize(1); @@ -496,39 +498,39 @@ tx2.vout.resize(1); tx2.vout[0].scriptPubKey = CScript() << OP_2 << OP_EQUAL; tx2.vout[0].nValue = 10 * COIN.GetSatoshis(); - pool.addUnchecked(tx2.GetId(), entry.Fee(5000LL).FromTx(tx2, &pool)); + pool.addUnchecked(tx2.GetHash(), entry.Fee(5000LL).FromTx(tx2, &pool)); // should do nothing pool.TrimToSize(pool.DynamicMemoryUsage()); - BOOST_CHECK(pool.exists(tx1.GetId())); - BOOST_CHECK(pool.exists(tx2.GetId())); + BOOST_CHECK(pool.exists(tx1.GetHash())); + BOOST_CHECK(pool.exists(tx2.GetHash())); // should remove the lower-feerate transaction pool.TrimToSize(pool.DynamicMemoryUsage() * 3 / 4); - BOOST_CHECK(pool.exists(tx1.GetId())); - BOOST_CHECK(!pool.exists(tx2.GetId())); + BOOST_CHECK(pool.exists(tx1.GetHash())); + BOOST_CHECK(!pool.exists(tx2.GetHash())); - pool.addUnchecked(tx2.GetId(), entry.FromTx(tx2, &pool)); + pool.addUnchecked(tx2.GetHash(), entry.FromTx(tx2, &pool)); CMutableTransaction tx3 = CMutableTransaction(); tx3.vin.resize(1); - tx3.vin[0].prevout = COutPoint(tx2.GetId(), 0); + tx3.vin[0].prevout = COutPoint(tx2.GetUnspentid(), 0); tx3.vin[0].scriptSig = CScript() << OP_2; tx3.vout.resize(1); tx3.vout[0].scriptPubKey = CScript() << OP_3 << OP_EQUAL; tx3.vout[0].nValue = 10 * COIN.GetSatoshis(); - pool.addUnchecked(tx3.GetId(), entry.Fee(20000LL).FromTx(tx3, &pool)); + pool.addUnchecked(tx3.GetHash(), entry.Fee(20000LL).FromTx(tx3, &pool)); // tx3 should pay for tx2 (CPFP) pool.TrimToSize(pool.DynamicMemoryUsage() * 3 / 4); - BOOST_CHECK(!pool.exists(tx1.GetId())); - BOOST_CHECK(pool.exists(tx2.GetId())); - BOOST_CHECK(pool.exists(tx3.GetId())); + BOOST_CHECK(!pool.exists(tx1.GetHash())); + BOOST_CHECK(pool.exists(tx2.GetHash())); + BOOST_CHECK(pool.exists(tx3.GetHash())); // mempool is limited to tx1's size in memory usage, so nothing fits pool.TrimToSize(GetTransactionSize(tx1)); - BOOST_CHECK(!pool.exists(tx1.GetId())); - BOOST_CHECK(!pool.exists(tx2.GetId())); - BOOST_CHECK(!pool.exists(tx3.GetId())); + BOOST_CHECK(!pool.exists(tx1.GetHash())); + BOOST_CHECK(!pool.exists(tx2.GetHash())); + BOOST_CHECK(!pool.exists(tx3.GetHash())); CFeeRate maxFeeRateRemoved(25000, GetTransactionSize(tx3) + GetTransactionSize(tx2)); @@ -549,7 +551,7 @@ CMutableTransaction tx5 = CMutableTransaction(); tx5.vin.resize(2); - tx5.vin[0].prevout = COutPoint(tx4.GetId(), 0); + tx5.vin[0].prevout = COutPoint(tx4.GetUnspentid(), 0); tx5.vin[0].scriptSig = CScript() << OP_4; tx5.vin[1].prevout.SetNull(); tx5.vin[1].scriptSig = CScript() << OP_5; @@ -561,7 +563,7 @@ CMutableTransaction tx6 = CMutableTransaction(); tx6.vin.resize(2); - tx6.vin[0].prevout = COutPoint(tx4.GetId(), 1); + tx6.vin[0].prevout = COutPoint(tx4.GetUnspentid(), 1); tx6.vin[0].scriptSig = CScript() << OP_4; tx6.vin[1].prevout.SetNull(); tx6.vin[1].scriptSig = CScript() << OP_6; @@ -573,9 +575,9 @@ CMutableTransaction tx7 = CMutableTransaction(); tx7.vin.resize(2); - tx7.vin[0].prevout = COutPoint(tx5.GetId(), 0); + tx7.vin[0].prevout = COutPoint(tx5.GetUnspentid(), 0); tx7.vin[0].scriptSig = CScript() << OP_5; - tx7.vin[1].prevout = COutPoint(tx6.GetId(), 0); + tx7.vin[1].prevout = COutPoint(tx6.GetUnspentid(), 0); tx7.vin[1].scriptSig = CScript() << OP_6; tx7.vout.resize(2); tx7.vout[0].scriptPubKey = CScript() << OP_7 << OP_EQUAL; @@ -583,31 +585,31 @@ tx7.vout[1].scriptPubKey = CScript() << OP_7 << OP_EQUAL; tx7.vout[1].nValue = 10 * COIN.GetSatoshis(); - pool.addUnchecked(tx4.GetId(), entry.Fee(7000LL).FromTx(tx4, &pool)); - pool.addUnchecked(tx5.GetId(), entry.Fee(1000LL).FromTx(tx5, &pool)); - pool.addUnchecked(tx6.GetId(), entry.Fee(1100LL).FromTx(tx6, &pool)); - pool.addUnchecked(tx7.GetId(), entry.Fee(9000LL).FromTx(tx7, &pool)); + pool.addUnchecked(tx4.GetHash(), entry.Fee(7000LL).FromTx(tx4, &pool)); + pool.addUnchecked(tx5.GetHash(), entry.Fee(1000LL).FromTx(tx5, &pool)); + pool.addUnchecked(tx6.GetHash(), entry.Fee(1100LL).FromTx(tx6, &pool)); + pool.addUnchecked(tx7.GetHash(), entry.Fee(9000LL).FromTx(tx7, &pool)); // we only require this remove, at max, 2 txn, because its not clear what // we're really optimizing for aside from that pool.TrimToSize(pool.DynamicMemoryUsage() - 1); - BOOST_CHECK(pool.exists(tx4.GetId())); - BOOST_CHECK(pool.exists(tx6.GetId())); - BOOST_CHECK(!pool.exists(tx7.GetId())); + BOOST_CHECK(pool.exists(tx4.GetHash())); + BOOST_CHECK(pool.exists(tx6.GetHash())); + BOOST_CHECK(!pool.exists(tx7.GetHash())); - if (!pool.exists(tx5.GetId())) - pool.addUnchecked(tx5.GetId(), entry.Fee(1000LL).FromTx(tx5, &pool)); - pool.addUnchecked(tx7.GetId(), entry.Fee(9000LL).FromTx(tx7, &pool)); + if (!pool.exists(tx5.GetHash())) + pool.addUnchecked(tx5.GetHash(), entry.Fee(1000LL).FromTx(tx5, &pool)); + pool.addUnchecked(tx7.GetHash(), entry.Fee(9000LL).FromTx(tx7, &pool)); // should maximize mempool size by only removing 5/7 pool.TrimToSize(pool.DynamicMemoryUsage() / 2); - BOOST_CHECK(pool.exists(tx4.GetId())); - BOOST_CHECK(!pool.exists(tx5.GetId())); - BOOST_CHECK(pool.exists(tx6.GetId())); - BOOST_CHECK(!pool.exists(tx7.GetId())); + BOOST_CHECK(pool.exists(tx4.GetHash())); + BOOST_CHECK(!pool.exists(tx5.GetHash())); + BOOST_CHECK(pool.exists(tx6.GetHash())); + BOOST_CHECK(!pool.exists(tx7.GetHash())); - pool.addUnchecked(tx5.GetId(), entry.Fee(1000LL).FromTx(tx5, &pool)); - pool.addUnchecked(tx7.GetId(), entry.Fee(9000LL).FromTx(tx7, &pool)); + pool.addUnchecked(tx5.GetHash(), entry.Fee(1000LL).FromTx(tx5, &pool)); + pool.addUnchecked(tx7.GetHash(), entry.Fee(9000LL).FromTx(tx7, &pool)); std::vector vtx; SetMockTime(42); diff --git a/src/test/merkle_tests.cpp b/src/test/merkle_tests.cpp --- a/src/test/merkle_tests.cpp +++ b/src/test/merkle_tests.cpp @@ -18,7 +18,7 @@ vMerkleTree.reserve(block.vtx.size() * 2 + 16); for (std::vector::const_iterator it(block.vtx.begin()); it != block.vtx.end(); ++it) - vMerkleTree.push_back((*it)->GetId()); + vMerkleTree.push_back((*it)->GetHash()); int j = 0; bool mutated = false; for (int nSize = block.vtx.size(); nSize > 1; nSize = (nSize + 1) / 2) { @@ -145,7 +145,7 @@ BlockGetMerkleBranch(block, merkleTree, mtx); BOOST_CHECK(oldBranch == newBranch); BOOST_CHECK( - ComputeMerkleRootFromBranch(block.vtx[mtx]->GetId(), + ComputeMerkleRootFromBranch(block.vtx[mtx]->GetHash(), newBranch, mtx) == oldRoot); } } diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -94,45 +94,48 @@ CMutableTransaction tx; tx.vin.resize(1); tx.vin[0].scriptSig = CScript() << OP_1; - tx.vin[0].prevout.hash = txFirst[0]->GetId(); + tx.vin[0].prevout.unspentid = txFirst[0]->Getunspentid(); tx.vin[0].prevout.n = 0; tx.vout.resize(1); tx.vout[0].nValue = 5000000000LL - 1000; // This tx has a low fee: 1000 satoshis. - // Save this txid for later use. - uint256 hashParentTx = tx.GetId(); + // Save this hash for later use. + txhash_t hashParentTx = tx.GetHash(); + unspentid_t unspentidParentTx = tx.Getunspentid(); mempool.addUnchecked( hashParentTx, entry.Fee(1000).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); // This tx has a medium fee: 10000 satoshis. - tx.vin[0].prevout.hash = txFirst[1]->GetId(); + tx.vin[0].prevout.unspentid = txFirst[1]->Getunspentid(); tx.vout[0].nValue = 5000000000LL - 10000; - uint256 hashMediumFeeTx = tx.GetId(); + txhash_t hashMediumFeeTx = tx.GetHash(); mempool.addUnchecked( hashMediumFeeTx, entry.Fee(10000).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); // This tx has a high fee, but depends on the first transaction. - tx.vin[0].prevout.hash = hashParentTx; + tx.vin[0].prevout.unspentid = unspentidParentTx; // 50k satoshi fee. tx.vout[0].nValue = 5000000000LL - 1000 - 50000; - uint256 hashHighFeeTx = tx.GetId(); + txhash_t hashHighFeeTx = tx.GetHash(); + unspentid_t unspentidHighFeeTx = tx.Getunspentid(); mempool.addUnchecked( hashHighFeeTx, entry.Fee(50000).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); std::unique_ptr pblocktemplate = BlockAssembler(config, chainparams).CreateNewBlock(scriptPubKey); - BOOST_CHECK(pblocktemplate->block.vtx[1]->GetId() == hashParentTx); - BOOST_CHECK(pblocktemplate->block.vtx[2]->GetId() == hashHighFeeTx); - BOOST_CHECK(pblocktemplate->block.vtx[3]->GetId() == hashMediumFeeTx); + BOOST_CHECK(pblocktemplate->block.vtx[1]->GetHash() == hashParentTx); + BOOST_CHECK(pblocktemplate->block.vtx[2]->GetHash() == hashHighFeeTx); + BOOST_CHECK(pblocktemplate->block.vtx[3]->GetHash() == hashMediumFeeTx); // Test that a package below the block min tx fee doesn't get included - tx.vin[0].prevout.hash = hashHighFeeTx; + tx.vin[0].prevout.unspentid = unspentidHighFeeTx; // 0 fee. tx.vout[0].nValue = 5000000000LL - 1000 - 50000; - uint256 hashFreeTx = tx.GetId(); + txhash_t hashFreeTx = tx.GetHash(); + unspentid_t unspentidFreeTx = tx.Getunspentid(); mempool.addUnchecked(hashFreeTx, entry.Fee(0).FromTx(tx)); size_t freeTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); @@ -140,16 +143,16 @@ // below the block min tx fee (assuming 1 child tx of the same size). CAmount feeToUse = blockMinFeeRate.GetFee(2 * freeTxSize).GetSatoshis() - 1; - tx.vin[0].prevout.hash = hashFreeTx; + tx.vin[0].prevout.unspentid = unspentidFreeTx; tx.vout[0].nValue = 5000000000LL - 1000 - 50000 - feeToUse; - uint256 hashLowFeeTx = tx.GetId(); + txhash_t hashLowFeeTx = tx.GetHash(); mempool.addUnchecked(hashLowFeeTx, entry.Fee(feeToUse).FromTx(tx)); pblocktemplate = BlockAssembler(config, chainparams).CreateNewBlock(scriptPubKey); // Verify that the free tx and the low fee tx didn't get selected. for (size_t i = 0; i < pblocktemplate->block.vtx.size(); ++i) { - BOOST_CHECK(pblocktemplate->block.vtx[i]->GetId() != hashFreeTx); - BOOST_CHECK(pblocktemplate->block.vtx[i]->GetId() != hashLowFeeTx); + BOOST_CHECK(pblocktemplate->block.vtx[i]->GetHash() != hashFreeTx); + BOOST_CHECK(pblocktemplate->block.vtx[i]->GetHash() != hashLowFeeTx); } // Test that packages above the min relay fee do get included, even if one @@ -158,31 +161,32 @@ mempool.removeRecursive(tx); // Now we should be just over the min relay fee. tx.vout[0].nValue -= 2; - hashLowFeeTx = tx.GetId(); + hashLowFeeTx = tx.GetHash(); mempool.addUnchecked(hashLowFeeTx, entry.Fee(feeToUse + 2).FromTx(tx)); pblocktemplate = BlockAssembler(config, chainparams).CreateNewBlock(scriptPubKey); - BOOST_CHECK(pblocktemplate->block.vtx[4]->GetId() == hashFreeTx); - BOOST_CHECK(pblocktemplate->block.vtx[5]->GetId() == hashLowFeeTx); + BOOST_CHECK(pblocktemplate->block.vtx[4]->GetHash() == hashFreeTx); + BOOST_CHECK(pblocktemplate->block.vtx[5]->GetHash() == hashLowFeeTx); // Test that transaction selection properly updates ancestor fee // calculations as ancestor transactions get included in a block. Add a // 0-fee transaction that has 2 outputs. - tx.vin[0].prevout.hash = txFirst[2]->GetId(); + tx.vin[0].prevout.unspentid = txFirst[2]->Getunspentid(); tx.vout.resize(2); tx.vout[0].nValue = 5000000000LL - 100000000; // 1BCC output. tx.vout[1].nValue = 100000000; - uint256 hashFreeTx2 = tx.GetId(); + txhash_t hashFreeTx2 = tx.GetHash(); + unspentid_t unspentidFreeTx2 = tx.Getunspentid(); mempool.addUnchecked(hashFreeTx2, entry.Fee(0).SpendsCoinbase(true).FromTx(tx)); // This tx can't be mined by itself. - tx.vin[0].prevout.hash = hashFreeTx2; + tx.vin[0].prevout.unspentid = unspentidFreeTx2; tx.vout.resize(1); feeToUse = blockMinFeeRate.GetFee(freeTxSize).GetSatoshis(); tx.vout[0].nValue = 5000000000LL - 100000000 - feeToUse; - uint256 hashLowFeeTx2 = tx.GetId(); + txhash_t hashLowFeeTx2 = tx.GetHash(); mempool.addUnchecked(hashLowFeeTx2, entry.Fee(feeToUse).SpendsCoinbase(false).FromTx(tx)); pblocktemplate = @@ -190,8 +194,8 @@ // Verify that this tx isn't selected. for (size_t i = 0; i < pblocktemplate->block.vtx.size(); ++i) { - BOOST_CHECK(pblocktemplate->block.vtx[i]->GetId() != hashFreeTx2); - BOOST_CHECK(pblocktemplate->block.vtx[i]->GetId() != hashLowFeeTx2); + BOOST_CHECK(pblocktemplate->block.vtx[i]->GetHash() != hashFreeTx2); + BOOST_CHECK(pblocktemplate->block.vtx[i]->GetHash() != hashLowFeeTx2); } // This tx will be mineable, and should cause hashLowFeeTx2 to be selected @@ -199,10 +203,10 @@ tx.vin[0].prevout.n = 1; // 10k satoshi fee. tx.vout[0].nValue = 100000000 - 10000; - mempool.addUnchecked(tx.GetId(), entry.Fee(10000).FromTx(tx)); + mempool.addUnchecked(tx.GetHash(), entry.Fee(10000).FromTx(tx)); pblocktemplate = BlockAssembler(config, chainparams).CreateNewBlock(scriptPubKey); - BOOST_CHECK(pblocktemplate->block.vtx[8]->GetId() == hashLowFeeTx2); + BOOST_CHECK(pblocktemplate->block.vtx[8]->GetHash() == hashLowFeeTx2); } void TestCoinbaseMessageEB(uint64_t eb, std::string cbmsg) { @@ -253,7 +257,8 @@ std::unique_ptr pblocktemplate; CMutableTransaction tx, tx2; CScript script; - uint256 hash; + txhash_t hash; + unspentid_t unspentid; TestMemPoolEntryHelper entry; entry.nFee = 11; entry.dPriority = 111.0; @@ -313,13 +318,13 @@ // NOTE: OP_NOP is used to force 20 SigOps for the CHECKMULTISIG tx.vin[0].scriptSig = CScript() << OP_0 << OP_0 << OP_0 << OP_NOP << OP_CHECKMULTISIG << OP_1; - tx.vin[0].prevout.hash = txFirst[0]->GetId(); + tx.vin[0].prevout.unspentid = txFirst[0]->Getunspentid(); tx.vin[0].prevout.n = 0; tx.vout.resize(1); tx.vout[0].nValue = BLOCKSUBSIDY; for (unsigned int i = 0; i < 1001; ++i) { tx.vout[0].nValue -= LOWFEE; - hash = tx.GetId(); + hash = tx.GetHash(); // Only first tx spends coinbase. bool spendsCoinbase = (i == 0) ? true : false; // If we don't set the # of sig ops in the CTxMemPoolEntry, template @@ -328,18 +333,19 @@ .Time(GetTime()) .SpendsCoinbase(spendsCoinbase) .FromTx(tx)); - tx.vin[0].prevout.hash = hash; + tx.vin[0].prevout.unspentid = tx.Getunspentid(); } BOOST_CHECK_THROW( BlockAssembler(config, chainparams).CreateNewBlock(scriptPubKey), std::runtime_error); mempool.clear(); - tx.vin[0].prevout.hash = txFirst[0]->GetId(); + tx.vin[0].prevout.unspentid = txFirst[0]->Getunspentid(); tx.vout[0].nValue = BLOCKSUBSIDY; for (unsigned int i = 0; i < 1001; ++i) { tx.vout[0].nValue -= LOWFEE; - hash = tx.GetId(); + hash = tx.GetHash(); + unspentid = tx.Getunspentid(); // Only first tx spends coinbase. bool spendsCoinbase = (i == 0) ? true : false; // If we do set the # of sig ops in the CTxMemPoolEntry, template @@ -349,7 +355,7 @@ .SpendsCoinbase(spendsCoinbase) .SigOpsCost(80) .FromTx(tx)); - tx.vin[0].prevout.hash = hash; + tx.vin[0].prevout.unspentid = unspentid; } BOOST_CHECK( pblocktemplate = @@ -363,18 +369,19 @@ for (unsigned int i = 0; i < 18; ++i) tx.vin[0].scriptSig << vchData << OP_DROP; tx.vin[0].scriptSig << OP_1; - tx.vin[0].prevout.hash = txFirst[0]->GetId(); + tx.vin[0].prevout.unspentid = txFirst[0]->Getunspentid(); tx.vout[0].nValue = BLOCKSUBSIDY; for (unsigned int i = 0; i < 128; ++i) { tx.vout[0].nValue -= LOWFEE; - hash = tx.GetId(); + hash = tx.GetHash(); + unspentid = tx.Getunspentid(); // Only first tx spends coinbase. bool spendsCoinbase = (i == 0) ? true : false; mempool.addUnchecked(hash, entry.Fee(LOWFEE) .Time(GetTime()) .SpendsCoinbase(spendsCoinbase) .FromTx(tx)); - tx.vin[0].prevout.hash = hash; + tx.vin[0].prevout.unspentid = unspentid; } BOOST_CHECK( pblocktemplate = @@ -382,7 +389,7 @@ mempool.clear(); // Orphan in mempool, template creation fails. - hash = tx.GetId(); + hash = tx.GetHash(); mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).FromTx(tx)); BOOST_CHECK_THROW( BlockAssembler(config, chainparams).CreateNewBlock(scriptPubKey), @@ -391,20 +398,21 @@ // Child with higher priority than parent. tx.vin[0].scriptSig = CScript() << OP_1; - tx.vin[0].prevout.hash = txFirst[1]->GetId(); + tx.vin[0].prevout.unspentid = txFirst[1]->Getunspentid(); tx.vout[0].nValue = BLOCKSUBSIDY - HIGHFEE; - hash = tx.GetId(); + hash = tx.GetHash(); + unspentid = tx.Getunspentid(); mempool.addUnchecked( hash, entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); - tx.vin[0].prevout.hash = hash; + tx.vin[0].prevout.unspentid = unspentid; tx.vin.resize(2); tx.vin[1].scriptSig = CScript() << OP_1; - tx.vin[1].prevout.hash = txFirst[0]->GetId(); + tx.vin[1].prevout.unspentid = txFirst[0]->Getunspentid(); tx.vin[1].prevout.n = 0; // First txn output + fresh coinbase - new txn fee. tx.vout[0].nValue = tx.vout[0].nValue + BLOCKSUBSIDY - HIGHERFEE; - hash = tx.GetId(); + hash = tx.GetHash(); mempool.addUnchecked( hash, entry.Fee(HIGHERFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); @@ -418,7 +426,7 @@ tx.vin[0].prevout.SetNull(); tx.vin[0].scriptSig = CScript() << OP_0 << OP_1; tx.vout[0].nValue = 0; - hash = tx.GetId(); + hash = tx.GetHash(); // Give it a fee so it'll get mined. mempool.addUnchecked( hash, @@ -429,21 +437,22 @@ mempool.clear(); // Invalid (pre-p2sh) txn in mempool, template creation fails. - tx.vin[0].prevout.hash = txFirst[0]->GetId(); + tx.vin[0].prevout.unspentid = txFirst[0]->Getunspentid(); tx.vin[0].prevout.n = 0; tx.vin[0].scriptSig = CScript() << OP_1; tx.vout[0].nValue = BLOCKSUBSIDY - LOWFEE; script = CScript() << OP_0; tx.vout[0].scriptPubKey = GetScriptForDestination(CScriptID(script)); - hash = tx.GetId(); + hash = tx.GetHash(); + unspentid = tx.Getunspentid(); mempool.addUnchecked( hash, entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); - tx.vin[0].prevout.hash = hash; + tx.vin[0].prevout.unspentid = unspentid; tx.vin[0].scriptSig = CScript() << std::vector(script.begin(), script.end()); tx.vout[0].nValue -= LOWFEE; - hash = tx.GetId(); + hash = tx.GetHash(); mempool.addUnchecked( hash, entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); @@ -453,16 +462,16 @@ mempool.clear(); // Double spend txn pair in mempool, template creation fails. - tx.vin[0].prevout.hash = txFirst[0]->GetId(); + tx.vin[0].prevout.unspentid = txFirst[0]->Getunspentid(); tx.vin[0].scriptSig = CScript() << OP_1; tx.vout[0].nValue = BLOCKSUBSIDY - HIGHFEE; tx.vout[0].scriptPubKey = CScript() << OP_1; - hash = tx.GetId(); + hash = tx.GetHash(); mempool.addUnchecked( hash, entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); tx.vout[0].scriptPubKey = CScript() << OP_2; - hash = tx.GetId(); + hash = tx.GetHash(); mempool.addUnchecked( hash, entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); @@ -521,7 +530,7 @@ tx.vin.resize(1); prevheights.resize(1); // Only 1 transaction. - tx.vin[0].prevout.hash = txFirst[0]->GetId(); + tx.vin[0].prevout.unspentid = txFirst[0]->Getunspentid(); tx.vin[0].prevout.n = 0; tx.vin[0].scriptSig = CScript() << OP_1; // txFirst[0] is the 2nd block @@ -531,7 +540,7 @@ tx.vout[0].nValue = BLOCKSUBSIDY - HIGHFEE; tx.vout[0].scriptPubKey = CScript() << OP_1; tx.nLockTime = 0; - hash = tx.GetId(); + hash = tx.GetHash(); mempool.addUnchecked( hash, entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); @@ -552,7 +561,7 @@ CreateBlockIndex(chainActive.Tip()->nHeight + 2))); // Relative time locked. - tx.vin[0].prevout.hash = txFirst[1]->GetId(); + tx.vin[0].prevout.unspentid = txFirst[1]->Getunspentid(); // txFirst[1] is the 3rd block. tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG | (((chainActive.Tip()->GetMedianTimePast() + 1 - @@ -560,7 +569,7 @@ CTxIn::SEQUENCE_LOCKTIME_GRANULARITY) + 1); prevheights[0] = baseheight + 2; - hash = tx.GetId(); + hash = tx.GetHash(); mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx)); { @@ -590,11 +599,11 @@ } // Absolute height locked. - tx.vin[0].prevout.hash = txFirst[2]->GetId(); + tx.vin[0].prevout.unspentid = txFirst[2]->Getunspentid(); tx.vin[0].nSequence = CTxIn::SEQUENCE_FINAL - 1; prevheights[0] = baseheight + 3; tx.nLockTime = chainActive.Tip()->nHeight + 1; - hash = tx.GetId(); + hash = tx.GetHash(); mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx)); { @@ -620,11 +629,12 @@ } // Absolute time locked. - tx.vin[0].prevout.hash = txFirst[3]->GetId(); + tx.vin[0].prevout.unspentid = txFirst[3]->Getunspentid(); tx.nLockTime = chainActive.Tip()->GetMedianTimePast(); prevheights.resize(1); prevheights[0] = baseheight + 4; - hash = tx.GetId(); + hash = tx.GetHash(); + unspentid = tx.Getunspentid(); mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx)); { @@ -650,7 +660,7 @@ } // mempool-dependent transactions (not added) - tx.vin[0].prevout.hash = hash; + tx.vin[0].prevout.unspentid = unspentid; prevheights[0] = chainActive.Tip()->nHeight + 1; tx.nLockTime = 0; tx.vin[0].nSequence = 0; diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp --- a/src/test/multisig_tests.cpp +++ b/src/test/multisig_tests.cpp @@ -71,7 +71,7 @@ txTo[i].vin.resize(1); txTo[i].vout.resize(1); txTo[i].vin[0].prevout.n = i; - txTo[i].vin[0].prevout.hash = txFrom.GetId(); + txTo[i].vin[0].prevout.unspentid = txFrom.GetUnspentid(); txTo[i].vout[0].nValue = 1; } @@ -345,7 +345,7 @@ txTo[i].vin.resize(1); txTo[i].vout.resize(1); txTo[i].vin[0].prevout.n = i; - txTo[i].vin[0].prevout.hash = txFrom.GetId(); + txTo[i].vin[0].prevout.unspentid = txFrom.GetUnspentid(); txTo[i].vout[0].nValue = 1; } diff --git a/src/test/pmt_tests.cpp b/src/test/pmt_tests.cpp --- a/src/test/pmt_tests.cpp +++ b/src/test/pmt_tests.cpp @@ -48,9 +48,9 @@ // calculate actual merkle root and height uint256 merkleRoot1 = BlockMerkleRoot(block); - std::vector vTxid(nTx, uint256()); + std::vector vTxhash(nTx, uint256()); for (unsigned int j = 0; j < nTx; j++) - vTxid[j] = block.vtx[j]->GetId(); + vTxhash[j] = block.vtx[j]->GetHash(); int nHeight = 1, nTx_ = nTx; while (nTx_ > 1) { nTx_ = (nTx_ + 1) / 2; @@ -60,17 +60,17 @@ // check with random subsets with inclusion chances 1, 1/2, 1/4, ..., // 1/128 for (int att = 1; att < 15; att++) { - // build random subset of txid's + // build random subset of txhashes std::vector vMatch(nTx, false); - std::vector vMatchTxid1; + std::vector vMatchTxhash1; for (unsigned int j = 0; j < nTx; j++) { bool fInclude = (insecure_rand() & ((1 << (att / 2)) - 1)) == 0; vMatch[j] = fInclude; - if (fInclude) vMatchTxid1.push_back(vTxid[j]); + if (fInclude) vMatchTxhash1.push_back(vTxhash[j]); } // build the partial merkle tree - CPartialMerkleTree pmt1(vTxid, vMatch); + CPartialMerkleTree pmt1(vTxhash, vMatch); // serialize CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); @@ -78,17 +78,17 @@ // verify CPartialMerkleTree's size guarantees unsigned int n = - std::min(nTx, 1 + vMatchTxid1.size() * nHeight); + std::min(nTx, 1 + vMatchTxhash1.size() * nHeight); BOOST_CHECK(ss.size() <= 10 + (258 * n + 7) / 8); // deserialize into a tester copy CPartialMerkleTreeTester pmt2; ss >> pmt2; - // extract merkle root and matched txids from copy - std::vector vMatchTxid2; + // extract merkle root and matched txhashes from copy + std::vector vMatchTxhash2; std::vector vIndex; - uint256 merkleRoot2 = pmt2.ExtractMatches(vMatchTxid2, vIndex); + uint256 merkleRoot2 = pmt2.ExtractMatches(vMatchTxhash2, vIndex); // check that it has the same merkle root as the original, and a // valid one @@ -97,14 +97,15 @@ // check that it contains the matched transactions (in the same // order!) - BOOST_CHECK(vMatchTxid1 == vMatchTxid2); + BOOST_CHECK(vMatchTxhash1 == vMatchTxhash2); // check that random bit flips break the authentication for (int j = 0; j < 4; j++) { CPartialMerkleTreeTester pmt3(pmt2); pmt3.Damage(); - std::vector vMatchTxid3; - uint256 merkleRoot3 = pmt3.ExtractMatches(vMatchTxid3, vIndex); + std::vector vMatchTxhash3; + uint256 merkleRoot3 = + pmt3.ExtractMatches(vMatchTxhash3, vIndex); BOOST_CHECK(merkleRoot3 != merkleRoot1); } } @@ -112,7 +113,7 @@ } BOOST_AUTO_TEST_CASE(pmt_malleability) { - std::vector vTxid = { + std::vector vTxhash = { ArithToUint256(1), ArithToUint256(2), ArithToUint256(3), ArithToUint256(4), ArithToUint256(5), ArithToUint256(6), ArithToUint256(7), ArithToUint256(8), ArithToUint256(9), @@ -120,9 +121,9 @@ std::vector vMatch = {false, false, false, false, false, false, false, false, false, true, true, false}; - CPartialMerkleTree tree(vTxid, vMatch); + CPartialMerkleTree tree(vTxhash, vMatch); std::vector vIndex; - BOOST_CHECK(tree.ExtractMatches(vTxid, vIndex).IsNull()); + BOOST_CHECK(tree.ExtractMatches(vTxhash, vIndex).IsNull()); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/policyestimator_tests.cpp b/src/test/policyestimator_tests.cpp --- a/src/test/policyestimator_tests.cpp +++ b/src/test/policyestimator_tests.cpp @@ -29,7 +29,7 @@ // Store the hashes of transactions that have been added to the mempool by // their associate fee txHashes[j] is populated with transactions either of // fee = basefee * (j+1) - std::vector txHashes[10]; + std::vector txHashes[10]; // Create a transaction template CScript garbage; @@ -56,7 +56,7 @@ for (int k = 0; k < 4; k++) { // make transaction unique tx.vin[0].prevout.n = 10000 * blocknum + 100 * j + k; - uint256 hash = tx.GetId(); + txhash_t hash = tx.GetHash(); mpool.addUnchecked(hash, entry.Fee(feeV[j]) .Time(GetTime()) .Priority(0) @@ -152,13 +152,13 @@ // add 4 fee txs for (int k = 0; k < 4; k++) { tx.vin[0].prevout.n = 10000 * blocknum + 100 * j + k; - uint256 txid = tx.GetId(); - mpool.addUnchecked(txid, entry.Fee(feeV[j]) - .Time(GetTime()) - .Priority(0) - .Height(blocknum) - .FromTx(tx, &mpool)); - txHashes[j].push_back(txid); + txhash_t txhash = tx.GetHash(); + mpool.addUnchecked(txhash, entry.Fee(feeV[j]) + .Time(GetTime()) + .Priority(0) + .Height(blocknum) + .FromTx(tx, &mpool)); + txHashes[j].push_back(txhash); } } mpool.removeForBlock(block, ++blocknum); @@ -198,13 +198,13 @@ // add 4 fee txs for (int k = 0; k < 4; k++) { tx.vin[0].prevout.n = 10000 * blocknum + 100 * j + k; - uint256 txid = tx.GetId(); - mpool.addUnchecked(txid, entry.Fee(feeV[j]) - .Time(GetTime()) - .Priority(0) - .Height(blocknum) - .FromTx(tx, &mpool)); - CTransactionRef ptx = mpool.get(txid); + txhash_t txhash = tx.GetHash(); + mpool.addUnchecked(txhash, entry.Fee(feeV[j]) + .Time(GetTime()) + .Priority(0) + .Height(blocknum) + .FromTx(tx, &mpool)); + CTransactionRef ptx = mpool.get(txhash); if (ptx) block.push_back(ptx); } } @@ -221,7 +221,7 @@ // value below the mempool min fee and that estimateSmartPriority returns // essentially an infinite value mpool.addUnchecked( - tx.GetId(), + tx.GetHash(), entry.Fee(feeV[5]).Time(GetTime()).Priority(0).Height(blocknum).FromTx( tx, &mpool)); // evict that transaction which should set a mempool min fee of diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp --- a/src/test/rpc_tests.cpp +++ b/src/test/rpc_tests.cpp @@ -129,7 +129,7 @@ BOOST_AUTO_TEST_CASE(rpc_rawsign) { UniValue r; // input is a 1-of-2 multisig (so is output): - std::string prevout = "[{\"txid\":" + std::string prevout = "[{\"unspentid\":" "\"b4cc287e58f87cdae59417329f710f3ecd75a4ee1d2872b724" "8f50977c8493f3\"," "\"vout\":1,\"scriptPubKey\":" @@ -162,7 +162,7 @@ // (We will re-use the tx + keys from the above rpc_rawsign test for // simplicity.) UniValue r; - std::string prevout = "[{\"txid\":" + std::string prevout = "[{\"unspentid\":" "\"b4cc287e58f87cdae59417329f710f3ecd75a4ee1d2872b724" "8f50977c8493f3\"," "\"vout\":1,\"scriptPubKey\":" @@ -196,13 +196,13 @@ BOOST_AUTO_TEST_CASE(rpc_createraw_op_return) { BOOST_CHECK_NO_THROW( CallRPC("createrawtransaction " - "[{\"txid\":" + "[{\"unspentid\":" "\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff1" "50ed\",\"vout\":0}] {\"data\":\"68656c6c6f776f726c64\"}")); // Allow more than one data transaction output BOOST_CHECK_NO_THROW(CallRPC("createrawtransaction " - "[{\"txid\":" + "[{\"unspentid\":" "\"a3b807410df0b60fcb9736768df5823938b2f838694" "939ba45f3c0a1bff150ed\",\"vout\":0}] " "{\"data\":\"68656c6c6f776f726c64\",\"data\":" @@ -211,7 +211,7 @@ // Key not "data" (bad address) BOOST_CHECK_THROW( CallRPC("createrawtransaction " - "[{\"txid\":" + "[{\"unspentid\":" "\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff1" "50ed\",\"vout\":0}] {\"somedata\":\"68656c6c6f776f726c64\"}"), std::runtime_error); @@ -219,13 +219,13 @@ // Bad hex encoding of data output BOOST_CHECK_THROW( CallRPC("createrawtransaction " - "[{\"txid\":" + "[{\"unspentid\":" "\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff1" "50ed\",\"vout\":0}] {\"data\":\"12345\"}"), std::runtime_error); BOOST_CHECK_THROW( CallRPC("createrawtransaction " - "[{\"txid\":" + "[{\"unspentid\":" "\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff1" "50ed\",\"vout\":0}] {\"data\":\"12345g\"}"), std::runtime_error); @@ -233,7 +233,7 @@ // Data 81 bytes long BOOST_CHECK_NO_THROW( CallRPC("createrawtransaction " - "[{\"txid\":" + "[{\"unspentid\":" "\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff1" "50ed\",\"vout\":0}] " "{\"data\":" diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_P2SH_tests.cpp --- a/src/test/script_P2SH_tests.cpp +++ b/src/test/script_P2SH_tests.cpp @@ -34,7 +34,7 @@ txTo.vin.resize(1); txTo.vout.resize(1); txTo.vin[0].prevout.n = 0; - txTo.vin[0].prevout.hash = txFrom.GetId(); + txTo.vin[0].prevout.unspentid = txFrom.GetUnspentid(); txTo.vin[0].scriptSig = scriptSig; txTo.vout[0].nValue = 1; @@ -92,7 +92,7 @@ txTo[i].vin.resize(1); txTo[i].vout.resize(1); txTo[i].vin[0].prevout.n = i; - txTo[i].vin[0].prevout.hash = txFrom.GetId(); + txTo[i].vin[0].prevout.unspentid = txFrom.GetUnspentid(); txTo[i].vout[0].nValue = 1; BOOST_CHECK_MESSAGE(IsMine(keystore, txFrom.vout[i].scriptPubKey), strprintf("IsMine %d", i)); @@ -197,8 +197,9 @@ txTo[i].vin.resize(1); txTo[i].vout.resize(1); txTo[i].vin[0].prevout.n = i; - txTo[i].vin[0].prevout.hash = txFrom.GetId(); + txTo[i].vin[0].prevout.unspentid = txFrom.GetUnspentid(); txTo[i].vout[0].nValue = 1 * CENT.GetSatoshis(); + txTo[i].vout[0].nValue = 1 * CENT; txTo[i].vout[0].scriptPubKey = inner[i]; BOOST_CHECK_MESSAGE(IsMine(keystore, txFrom.vout[i].scriptPubKey), strprintf("IsMine %d", i)); @@ -388,7 +389,7 @@ txTo.vin.resize(5); for (int i = 0; i < 5; i++) { txTo.vin[i].prevout.n = i; - txTo.vin[i].prevout.hash = txFrom.GetId(); + txTo.vin[i].prevout.unspentid = txFrom.GetUnspentid(); } BOOST_CHECK( SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL | SIGHASH_FORKID)); @@ -416,7 +417,7 @@ txToNonStd1.vout[0].nValue = 1000; txToNonStd1.vin.resize(1); txToNonStd1.vin[0].prevout.n = 5; - txToNonStd1.vin[0].prevout.hash = txFrom.GetId(); + txToNonStd1.vin[0].prevout.unspentid = txFrom.GetUnspentid(); txToNonStd1.vin[0].scriptSig << std::vector(sixteenSigops.begin(), sixteenSigops.end()); @@ -430,7 +431,7 @@ txToNonStd2.vout[0].nValue = 1000; txToNonStd2.vin.resize(1); txToNonStd2.vin[0].prevout.n = 6; - txToNonStd2.vin[0].prevout.hash = txFrom.GetId(); + txToNonStd2.vin[0].prevout.unspentid = txFrom.GetUnspentid(); txToNonStd2.vin[0].scriptSig << std::vector(twentySigops.begin(), twentySigops.end()); diff --git a/src/test/script_antireplay_tests.cpp b/src/test/script_antireplay_tests.cpp --- a/src/test/script_antireplay_tests.cpp +++ b/src/test/script_antireplay_tests.cpp @@ -81,7 +81,7 @@ CMutableTransaction tx; tx.nVersion = 1; tx.vin.resize(1); - tx.vin[0].prevout.hash = GetRandHash(); + tx.vin[0].prevout.unspentid = unspentid_t(GetRandHash()); tx.vin[0].prevout.n = 0; tx.vin[0].scriptSig = CScript(); tx.vout.resize(1); diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -140,7 +140,7 @@ txSpend.nLockTime = 0; txSpend.vin.resize(1); txSpend.vout.resize(1); - txSpend.vin[0].prevout.hash = txCredit.GetId(); + txSpend.vin[0].prevout.unspentid = txCredit.GetUnspentid(); txSpend.vin[0].prevout.n = 0; txSpend.vin[0].scriptSig = scriptSig; txSpend.vin[0].nSequence = CTxIn::SEQUENCE_FINAL; diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp --- a/src/test/sighash_tests.cpp +++ b/src/test/sighash_tests.cpp @@ -102,7 +102,7 @@ for (int in = 0; in < ins; in++) { tx.vin.push_back(CTxIn()); CTxIn &txin = tx.vin.back(); - txin.prevout.hash = GetRandHash(); + txin.prevout.unspentid = unspentid_t(GetRandHash()); txin.prevout.n = insecure_rand() % 4; RandomScript(txin.scriptSig); txin.nSequence = diff --git a/src/test/sigopcount_tests.cpp b/src/test/sigopcount_tests.cpp --- a/src/test/sigopcount_tests.cpp +++ b/src/test/sigopcount_tests.cpp @@ -97,7 +97,7 @@ spendingTx.nVersion = 1; spendingTx.vin.resize(1); - spendingTx.vin[0].prevout.hash = creationTx.GetId(); + spendingTx.vin[0].prevout.unspentid = creationTx.GetUnspentid(); spendingTx.vin[0].prevout.n = 0; spendingTx.vin[0].scriptSig = scriptSig; spendingTx.vout.resize(1); @@ -189,7 +189,7 @@ CMutableTransaction tx; tx.nVersion = 1; tx.vin.resize(1); - tx.vin[0].prevout.hash = GetRandHash(); + tx.vin[0].prevout.unspentid = unspentid_t(GetRandHash()); tx.vin[0].prevout.n = 0; tx.vin[0].scriptSig = CScript(); tx.vout.resize(1); diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -74,7 +74,7 @@ fValid = false; break; } - COutPoint outpoint(uint256S(vinput[0].get_str()), + COutPoint outpoint(unspentid_t(uint256S(vinput[0].get_str())), vinput[1].get_int()); mapprevOutScriptPubKeys[outpoint] = ParseScript(vinput[2].get_str()); @@ -165,7 +165,7 @@ fValid = false; break; } - COutPoint outpoint(uint256S(vinput[0].get_str()), + COutPoint outpoint(unspentid_t(uint256S(vinput[0].get_str())), vinput[1].get_int()); mapprevOutScriptPubKeys[outpoint] = ParseScript(vinput[2].get_str()); @@ -299,14 +299,14 @@ CMutableTransaction t1; t1.vin.resize(3); - t1.vin[0].prevout.hash = dummyTransactions[0].GetId(); + t1.vin[0].prevout.unspentid = dummyTransactions[0].GetUnspentid(); t1.vin[0].prevout.n = 1; t1.vin[0].scriptSig << std::vector(65, 0); - t1.vin[1].prevout.hash = dummyTransactions[1].GetId(); + t1.vin[1].prevout.unspentid = dummyTransactions[1].GetUnspentid(); t1.vin[1].prevout.n = 0; t1.vin[1].scriptSig << std::vector(65, 0) << std::vector(33, 4); - t1.vin[2].prevout.hash = dummyTransactions[1].GetId(); + t1.vin[2].prevout.unspentid = dummyTransactions[1].GetUnspentid(); t1.vin[2].prevout.n = 1; t1.vin[2].scriptSig << std::vector(65, 0) << std::vector(33, 4); @@ -341,7 +341,7 @@ CMutableTransaction inputm; inputm.nVersion = 1; inputm.vin.resize(1); - inputm.vin[0].prevout.hash = output->GetId(); + inputm.vin[0].prevout.unspentid = output->GetUnspentid(); inputm.vin[0].prevout.n = 0; inputm.vout.resize(1); inputm.vout[0].nValue = 1; @@ -529,7 +529,7 @@ CMutableTransaction t; t.vin.resize(1); - t.vin[0].prevout.hash = dummyTransactions[0].GetId(); + t.vin[0].prevout.unspentid = dummyTransactions[0].GetUnspentid(); t.vin[0].prevout.n = 1; t.vin[0].scriptSig << std::vector(65, 0); t.vout.resize(1); diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp --- a/src/test/txvalidationcache_tests.cpp +++ b/src/test/txvalidationcache_tests.cpp @@ -44,7 +44,7 @@ for (int i = 0; i < 2; i++) { spends[i].nVersion = 1; spends[i].vin.resize(1); - spends[i].vin[0].prevout.hash = coinbaseTxns[0].GetId(); + spends[i].vin[0].prevout.unspentid = coinbaseTxns[0].GetUnspentid(); spends[i].vin[0].prevout.n = 0; spends[i].vout.resize(1); spends[i].vout[0].nValue = 11 * CENT.GetSatoshis(); @@ -171,7 +171,7 @@ spend_tx.nVersion = 1; spend_tx.vin.resize(1); - spend_tx.vin[0].prevout.hash = coinbaseTxns[0].GetId(); + spend_tx.vin[0].prevout.unspentid = coinbaseTxns[0].GetUnspentid(); spend_tx.vin[0].prevout.n = 0; spend_tx.vout.resize(4); spend_tx.vout[0].nValue = 11 * CENT.GetSatoshis(); @@ -246,7 +246,8 @@ CMutableTransaction invalid_under_p2sh_tx; invalid_under_p2sh_tx.nVersion = 1; invalid_under_p2sh_tx.vin.resize(1); - invalid_under_p2sh_tx.vin[0].prevout.hash = spend_tx.GetId(); + invalid_under_p2sh_tx.vin[0].prevout.unspentid = + spend_tx.GetUnspentid(); invalid_under_p2sh_tx.vin[0].prevout.n = 0; invalid_under_p2sh_tx.vout.resize(1); invalid_under_p2sh_tx.vout[0].nValue = 11 * CENT.GetSatoshis(); @@ -265,7 +266,7 @@ invalid_with_cltv_tx.nVersion = 1; invalid_with_cltv_tx.nLockTime = 100; invalid_with_cltv_tx.vin.resize(1); - invalid_with_cltv_tx.vin[0].prevout.hash = spend_tx.GetId(); + invalid_with_cltv_tx.vin[0].prevout.unspentid = spend_tx.GetUnspentid(); invalid_with_cltv_tx.vin[0].prevout.n = 1; invalid_with_cltv_tx.vin[0].nSequence = 0; invalid_with_cltv_tx.vout.resize(1); @@ -300,7 +301,7 @@ CMutableTransaction invalid_with_csv_tx; invalid_with_csv_tx.nVersion = 2; invalid_with_csv_tx.vin.resize(1); - invalid_with_csv_tx.vin[0].prevout.hash = spend_tx.GetId(); + invalid_with_csv_tx.vin[0].prevout.unspentid = spend_tx.GetUnspentid(); invalid_with_csv_tx.vin[0].prevout.n = 2; invalid_with_csv_tx.vin[0].nSequence = 100; invalid_with_csv_tx.vout.resize(1); @@ -337,9 +338,9 @@ tx.nVersion = 1; tx.vin.resize(2); - tx.vin[0].prevout.hash = spend_tx.GetId(); + tx.vin[0].prevout.unspentid = spend_tx.GetUnspentid(); tx.vin[0].prevout.n = 0; - tx.vin[1].prevout.hash = spend_tx.GetId(); + tx.vin[1].prevout.unspentid = spend_tx.GetUnspentid(); tx.vin[1].prevout.n = 3; tx.vout.resize(1); tx.vout[0].nValue = 22 * CENT.GetSatoshis(); diff --git a/src/test/undo_tests.cpp b/src/test/undo_tests.cpp --- a/src/test/undo_tests.cpp +++ b/src/test/undo_tests.cpp @@ -39,8 +39,9 @@ ApplyBlockUndo(blockUndo, block, &pindex, view); } -static bool HasSpendableCoin(const CCoinsViewCache &view, const uint256 &txid) { - return !view.AccessCoin(COutPoint(txid, 0)).IsSpent(); +static bool HasSpendableCoin(const CCoinsViewCache &view, + const unspentid_t &unspentid) { + return !view.AccessCoin(COutPoint(unspentid, 0)).IsSpent(); } BOOST_AUTO_TEST_CASE(connect_utxo_extblock) { @@ -67,7 +68,7 @@ block.vtx[0] = MakeTransactionRef(tx); tx.vout[0].scriptPubKey = CScript() << OP_TRUE; - tx.vin[0].prevout.hash = GetRandHash(); + tx.vin[0].prevout.unspentid = unspentid_t(GetRandHash()); tx.vin[0].prevout.n = 0; tx.vin[0].nSequence = CTxIn::SEQUENCE_FINAL; tx.vin[0].scriptSig.resize(0); @@ -76,7 +77,7 @@ auto prevTx0 = CTransaction(tx); AddCoins(view, prevTx0, 100); - tx.vin[0].prevout.hash = prevTx0.GetId(); + tx.vin[0].prevout.unspentid = prevTx0.GetUnspentid(); auto tx0 = CTransaction(tx); block.vtx[1] = MakeTransactionRef(tx0); @@ -85,16 +86,16 @@ UpdateUTXOSet(block, view, blockundo, chainparams, 123456); BOOST_CHECK(view.GetBestBlock() == block.GetHash()); - BOOST_CHECK(HasSpendableCoin(view, coinbaseTx.GetId())); - BOOST_CHECK(HasSpendableCoin(view, tx0.GetId())); - BOOST_CHECK(!HasSpendableCoin(view, prevTx0.GetId())); + BOOST_CHECK(HasSpendableCoin(view, coinbaseTx.GetUnspentid())); + BOOST_CHECK(HasSpendableCoin(view, tx0.GetUnspentid())); + BOOST_CHECK(!HasSpendableCoin(view, prevTx0.GetUnspentid())); UndoBlock(block, view, blockundo, chainparams, 123456); BOOST_CHECK(view.GetBestBlock() == block.hashPrevBlock); - BOOST_CHECK(!HasSpendableCoin(view, coinbaseTx.GetId())); - BOOST_CHECK(!HasSpendableCoin(view, tx0.GetId())); - BOOST_CHECK(HasSpendableCoin(view, prevTx0.GetId())); + BOOST_CHECK(!HasSpendableCoin(view, coinbaseTx.GetUnspentid())); + BOOST_CHECK(!HasSpendableCoin(view, tx0.GetUnspentid())); + BOOST_CHECK(HasSpendableCoin(view, prevTx0.GetUnspentid())); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/txdb.h b/src/txdb.h --- a/src/txdb.h +++ b/src/txdb.h @@ -121,8 +121,8 @@ bool ReadLastBlockFile(int &nFile); bool WriteReindexing(bool fReindex); bool ReadReindexing(bool &fReindex); - bool ReadTxIndex(const uint256 &txid, CDiskTxPos &pos); - bool WriteTxIndex(const std::vector> &list); + bool ReadTxIndex(const txhash_t &unspentid, CDiskTxPos &pos); + bool WriteTxIndex(const std::vector> &list); bool WriteFlag(const std::string &name, bool fValue); bool ReadFlag(const std::string &name, bool &fValue); bool LoadBlockIndexGuts( diff --git a/src/txdb.cpp b/src/txdb.cpp --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -35,13 +35,13 @@ template void Serialize(Stream &s) const { s << key; - s << outpoint->hash; + s << outpoint->unspentid; s << VARINT(outpoint->n); } template void Unserialize(Stream &s) { s >> key; - s >> outpoint->hash; + s >> outpoint->unspentid; s >> VARINT(outpoint->n); } }; @@ -194,14 +194,14 @@ return WriteBatch(batch, true); } -bool CBlockTreeDB::ReadTxIndex(const uint256 &txid, CDiskTxPos &pos) { - return Read(std::make_pair(DB_TXINDEX, txid), pos); +bool CBlockTreeDB::ReadTxIndex(const txhash_t &txhash, CDiskTxPos &pos) { + return Read(std::make_pair(DB_TXINDEX, txhash), pos); } bool CBlockTreeDB::WriteTxIndex( - const std::vector> &vect) { + const std::vector> &vect) { CDBBatch batch(*this); - for (std::vector>::const_iterator it = + for (std::vector>::const_iterator it = vect.begin(); it != vect.end(); it++) batch.Write(std::make_pair(DB_TXINDEX, it->first), it->second); @@ -335,7 +335,7 @@ CDBBatch batch(db); while (pcursor->Valid()) { boost::this_thread::interruption_point(); - std::pair key; + std::pair key; if (!pcursor->GetKey(key) || key.first != DB_COINS) { break; } diff --git a/src/txmempool.h b/src/txmempool.h --- a/src/txmempool.h +++ b/src/txmempool.h @@ -232,10 +232,18 @@ }; // extracts a TxMemPoolEntry's transaction hash -struct mempoolentry_txid { - typedef uint256 result_type; +struct mempoolentry_txhash { + typedef txhash_t result_type; result_type operator()(const CTxMemPoolEntry &entry) const { - return entry.GetTx().GetId(); + return entry.GetTx().GetHash(); + } +}; + +// extracts a TxMemPoolEntry's unspentid +struct mempoolentry_unspentid { + typedef unspentid_t result_type; + result_type operator()(const CTxMemPoolEntry &entry) const { + return entry.GetTx().Getunspentid(); } }; @@ -293,7 +301,7 @@ double(b.GetTxSize() * a.GetModFeesWithDescendants().GetSatoshis()); double f2 = double(a.GetTxSize() * b.GetModifiedFee().GetSatoshis()); if (f1 == f2) { - return b.GetTx().GetId() < a.GetTx().GetId(); + return b.GetTx().GetHash() < a.GetTx().GetHash(); } return f1 > f2; } @@ -320,7 +328,7 @@ double f2 = aSize * bFees; if (f1 == f2) { - return a.GetTx().GetId() < b.GetTx().GetId(); + return a.GetTx().GetHash() < b.GetTx().GetHash(); } return f1 > f2; @@ -328,6 +336,7 @@ }; // Multi_index tag names +struct unspentid_idx {}; struct descendant_score {}; struct entry_time {}; struct mining_score {}; @@ -373,16 +382,16 @@ REPLACED }; -class SaltedTxidHasher { +class SaltedTxHasher { private: /** Salt */ const uint64_t k0, k1; public: - SaltedTxidHasher(); + SaltedTxHasher(); - size_t operator()(const uint256 &txid) const { - return SipHashUint256(k0, k1, txid); + size_t operator()(const uint256 &hash) const { + return SipHashUint256(k0, k1, hash); } }; @@ -492,9 +501,13 @@ typedef boost::multi_index_container< CTxMemPoolEntry, boost::multi_index::indexed_by< - // sorted by txid + // sorted by hash boost::multi_index::hashed_unique< - mempoolentry_txid, SaltedTxidHasher>, + mempoolentry_txhash, SaltedTxHasher>, + // sorted by unspentid + boost::multi_index::hashed_unique< + boost::multi_index::tag, + mempoolentry_unspentid, SaltedTxHasher>, // sorted by fee rate boost::multi_index::ordered_non_unique< boost::multi_index::tag, @@ -522,11 +535,11 @@ typedef indexed_transaction_set::nth_index<0>::type::iterator txiter; //!< All tx hashes/entries in mapTx, in random order - std::vector> vTxHashes; + std::vector> vTxHashes; struct CompareIteratorByHash { bool operator()(const txiter &a, const txiter &b) const { - return a->GetTx().GetId() < b->GetTx().GetId(); + return a->GetTx().GetHash() < b->GetTx().GetHash(); } }; typedef std::set setEntries; @@ -551,9 +564,23 @@ std::vector GetSortedDepthAndScore() const; + typedef indexed_transaction_set::index::type + mapTxByunspentid; + + txiter findByunspentid(const unspentid_t &unspentid) const { + + mapTxByunspentid::iterator pit = + mapTx.get().find(unspentid); + if (pit == mapTx.get().end()) { + return mapTx.end(); + } else { + return mapTx.find(pit->GetTx().GetHash()); + } + } + public: indirectmap mapNextTx; - std::map> mapDeltas; + std::map> mapDeltas; /** Create a new CTxMemPool. */ @@ -575,9 +602,9 @@ // to track size/count of descendant transactions. First version of // addUnchecked can be used to have it call CalculateMemPoolAncestors(), and // then invoke the second version. - bool addUnchecked(const uint256 &hash, const CTxMemPoolEntry &entry, + bool addUnchecked(const txhash_t &txhash, const CTxMemPoolEntry &entry, bool validFeeEstimate = true); - bool addUnchecked(const uint256 &hash, const CTxMemPoolEntry &entry, + bool addUnchecked(const txhash_t &txhash, const CTxMemPoolEntry &entry, setEntries &setAncestors, bool validFeeEstimate = true); void removeRecursive( @@ -592,8 +619,8 @@ void clear(); // lock free void _clear(); - bool CompareDepthAndScore(const uint256 &hasha, const uint256 &hashb); - void queryHashes(std::vector &vtxid); + bool CompareDepthAndScore(const txhash_t &hasha, const txhash_t &hashb); + void queryHashes(std::vector &vtxhash); bool isSpent(const COutPoint &outpoint); unsigned int GetTransactionsUpdated() const; void AddTransactionsUpdated(unsigned int n); @@ -605,11 +632,11 @@ bool HasNoInputsOf(const CTransaction &tx) const; /** Affect CreateNewBlock prioritisation of transactions */ - void PrioritiseTransaction(const uint256 hash, const std::string strHash, + void PrioritiseTransaction(const txhash_t txhash, const std::string strHash, double dPriorityDelta, const Amount nFeeDelta); - void ApplyDeltas(const uint256 hash, double &dPriorityDelta, + void ApplyDeltas(const txhash_t txhash, double &dPriorityDelta, Amount nFeeDelta) const; - void ClearPrioritisation(const uint256 hash); + void ClearPrioritisation(const txhash_t txhash); public: /** @@ -634,7 +661,7 @@ * disconnected block that have been accepted back into the mempool. */ void - UpdateTransactionsFromBlock(const std::vector &hashesToUpdate); + UpdateTransactionsFromBlock(const std::vector &hashesToUpdate); /** * Try to calculate all in-mempool ancestors of entry. @@ -684,7 +711,7 @@ /** Returns false if the transaction is in the mempool and not within the * chain limit specified. */ - bool TransactionWithinChainLimit(const uint256 &txid, + bool TransactionWithinChainLimit(const txhash_t &txhash, size_t chainLimit) const; unsigned long size() { @@ -697,19 +724,25 @@ return totalTxSize; } - bool exists(uint256 hash) const { + bool exists(txhash_t txhash) const { LOCK(cs); - return mapTx.count(hash) != 0; + return mapTx.count(txhash) != 0; } bool exists(const COutPoint &outpoint) const { LOCK(cs); - auto it = mapTx.find(outpoint.hash); + auto it = findByunspentid(outpoint.unspentid); return it != mapTx.end() && outpoint.n < it->GetTx().vout.size(); } - CTransactionRef get(const uint256 &hash) const; - TxMempoolInfo info(const uint256 &hash) const; + bool exists(unspentid_t unspentid) const { + LOCK(cs); + return (mapTx.get().count(unspentid) != 0); + } + + CTransactionRef get(const txhash_t &txhash) const; + CTransactionRef get(const unspentid_t &unspentid) const; + TxMempoolInfo info(const txhash_t &txhash) const; std::vector infoAll() const; /** @@ -759,7 +792,7 @@ * transaction again, if encountered in another transaction chain. */ void UpdateForDescendants(txiter updateIt, cacheMap &cachedDescendants, - const std::set &setExclude); + const std::set &setExclude); /** Update ancestors of hash to add/remove it as a descendant transaction. */ void UpdateAncestorsOf(bool add, txiter hash, setEntries &setAncestors); diff --git a/src/txmempool.cpp b/src/txmempool.cpp --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -79,7 +79,7 @@ // descendants. void CTxMemPool::UpdateForDescendants(txiter updateIt, cacheMap &cachedDescendants, - const std::set &setExclude) { + const std::set &setExclude) { setEntries stageEntries, setAllDescendants; stageEntries = GetMemPoolChildren(updateIt); @@ -108,7 +108,7 @@ Amount modifyFee = 0; int64_t modifyCount = 0; for (txiter cit : setAllDescendants) { - if (!setExclude.count(cit->GetTx().GetId())) { + if (!setExclude.count(cit->GetTx().GetHash())) { modifySize += cit->GetTxSize(); modifyFee += cit->GetModifiedFee(); modifyCount++; @@ -130,7 +130,7 @@ // descendants to the parent. For each such descendant, also update the ancestor // state to include the parent. void CTxMemPool::UpdateTransactionsFromBlock( - const std::vector &vHashesToUpdate) { + const std::vector &vHashesToUpdate) { LOCK(cs); // For each entry in vHashesToUpdate, store the set of in-mempool, but not // in-vHashesToUpdate transactions, so that we don't have to recalculate @@ -139,27 +139,30 @@ // Use a set for lookups into vHashesToUpdate (these entries are already // accounted for in the state of their ancestors) - std::set setAlreadyIncluded(vHashesToUpdate.begin(), - vHashesToUpdate.end()); + std::set setAlreadyIncluded(vHashesToUpdate.begin(), + vHashesToUpdate.end()); // Iterate in reverse, so that whenever we are looking at at a transaction // we are sure that all in-mempool descendants have already been processed. // This maximizes the benefit of the descendant cache and guarantees that // setMemPoolChildren will be updated, an assumption made in // UpdateForDescendants. - for (const uint256 &hash : boost::adaptors::reverse(vHashesToUpdate)) { + for (const txhash_t &txhash : boost::adaptors::reverse(vHashesToUpdate)) { // we cache the in-mempool children to avoid duplicate updates setEntries setChildren; // calculate children from mapNextTx - txiter it = mapTx.find(hash); + txiter it = mapTx.find(txhash); if (it == mapTx.end()) { continue; } - auto iter = mapNextTx.lower_bound(COutPoint(hash, 0)); + + unspentid_t unspentid = it->GetTx().Getunspentid(); + auto iter = mapNextTx.lower_bound(COutPoint(unspentid, 0)); // First calculate the children, and update setMemPoolChildren to // include them, and update their setMemPoolParents to include this tx. - for (; iter != mapNextTx.end() && iter->first->hash == hash; ++iter) { - const uint256 &childHash = iter->second->GetId(); + for (; iter != mapNextTx.end() && iter->first->unspentid == unspentid; + ++iter) { + const txhash_t &childHash = iter->second->GetHash(); txiter childIter = mapTx.find(childHash); assert(childIter != mapTx.end()); // We can skip updating entries we've encountered before or that are @@ -190,7 +193,7 @@ // GetMemPoolParents() is only valid for entries in the mempool, so we // iterate mapTx to find parents. for (unsigned int i = 0; i < tx.vin.size(); i++) { - txiter piter = mapTx.find(tx.vin[i].prevout.hash); + txiter piter = findByunspentid(tx.vin[i].prevout.unspentid); if (piter != mapTx.end()) { parentHashes.insert(piter); if (parentHashes.size() + 1 > limitAncestorCount) { @@ -221,12 +224,12 @@ limitDescendantSize) { errString = strprintf( "exceeds descendant size limit for tx %s [limit: %u]", - stageit->GetTx().GetId().ToString(), limitDescendantSize); + stageit->GetTx().GetHash().ToString(), limitDescendantSize); return false; } else if (stageit->GetCountWithDescendants() + 1 > limitDescendantCount) { errString = strprintf("too many descendants for tx %s [limit: %u]", - stageit->GetTx().GetId().ToString(), + stageit->GetTx().GetHash().ToString(), limitDescendantCount); return false; } else if (totalSizeWithAncestors > limitAncestorSize) { @@ -406,7 +409,8 @@ nTransactionsUpdated += n; } -bool CTxMemPool::addUnchecked(const uint256 &hash, const CTxMemPoolEntry &entry, +bool CTxMemPool::addUnchecked(const txhash_t &txhash, + const CTxMemPoolEntry &entry, setEntries &setAncestors, bool validFeeEstimate) { NotifyEntryAdded(entry.GetSharedTx()); // Add to memory pool without checking anything. @@ -418,8 +422,8 @@ // Update transaction for any feeDelta created by PrioritiseTransaction // TODO: refactor so that the fee delta is calculated before inserting into // mapTx. - std::map>::const_iterator pos = - mapDeltas.find(hash); + std::map>::const_iterator pos = + mapDeltas.find(txhash); if (pos != mapDeltas.end()) { const std::pair &deltas = pos->second; if (deltas.second != 0) { @@ -433,10 +437,10 @@ cachedInnerUsage += entry.DynamicMemoryUsage(); const CTransaction &tx = newit->GetTx(); - std::set setParentTransactions; + std::set setParentTransactions; for (unsigned int i = 0; i < tx.vin.size(); i++) { mapNextTx.insert(std::make_pair(&tx.vin[i].prevout, &tx)); - setParentTransactions.insert(tx.vin[i].prevout.hash); + setParentTransactions.insert(tx.vin[i].prevout.unspentid); } // Don't bother worrying about child transactions of this one. Normal case // of a new transaction arriving is that there can't be any children, @@ -446,8 +450,8 @@ // the mess we're leaving here. // Update ancestors with information about this tx - for (const uint256 &phash : setParentTransactions) { - txiter pit = mapTx.find(phash); + for (const unspentid_t &phash : setParentTransactions) { + auto pit = findByunspentid(phash); if (pit != mapTx.end()) { UpdateParent(newit, pit, true); } @@ -467,7 +471,7 @@ void CTxMemPool::removeUnchecked(txiter it, MemPoolRemovalReason reason) { NotifyEntryRemoved(it->GetSharedTx(), reason); - const uint256 txid = it->GetTx().GetId(); + const txhash_t txhash = it->GetTx().GetHash(); for (const CTxIn &txin : it->GetTx().vin) { mapNextTx.erase(txin.prevout); } @@ -488,7 +492,7 @@ mapLinks.erase(it); mapTx.erase(it); nTransactionsUpdated++; - minerPolicyEstimator->removeTx(txid); + minerPolicyEstimator->removeTx(txhash); } // Calculates descendants of entry that are not already in setDescendants, and @@ -526,7 +530,7 @@ { LOCK(cs); setEntries txToRemove; - txiter origit = mapTx.find(origTx.GetId()); + txiter origit = mapTx.find(origTx.GetHash()); if (origit != mapTx.end()) { txToRemove.insert(origit); } else { @@ -535,9 +539,9 @@ // during chain re-orgs if origTx isn't re-accepted into the mempool // for any reason. for (unsigned int i = 0; i < origTx.vout.size(); i++) { - auto it = mapNextTx.find(COutPoint(origTx.GetId(), i)); + auto it = mapNextTx.find(COutPoint(origTx.Getunspentid(), i)); if (it == mapNextTx.end()) continue; - txiter nextit = mapTx.find(it->second->GetId()); + txiter nextit = mapTx.find(it->second->GetHash()); assert(nextit != mapTx.end()); txToRemove.insert(nextit); } @@ -576,7 +580,7 @@ } else if (it->GetSpendsCoinbase()) { for (const CTxIn &txin : tx.vin) { indexed_transaction_set::const_iterator it2 = - mapTx.find(txin.prevout.hash); + findByunspentid(txin.prevout.unspentid); if (it2 != mapTx.end()) { continue; } @@ -611,7 +615,7 @@ if (it != mapNextTx.end()) { const CTransaction &txConflict = *it->second; if (txConflict != tx) { - ClearPrioritisation(txConflict.GetId()); + ClearPrioritisation(txConflict.GetHash()); removeRecursive(txConflict, MemPoolRemovalReason::CONFLICT); } } @@ -627,23 +631,23 @@ LOCK(cs); std::vector entries; for (const auto &tx : vtx) { - uint256 txid = tx->GetId(); + txhash_t txhash = tx->GetHash(); - indexed_transaction_set::iterator i = mapTx.find(txid); + indexed_transaction_set::iterator i = mapTx.find(txhash); if (i != mapTx.end()) entries.push_back(&*i); } // Before the txs in the new block have been removed from the mempool, // update policy estimates minerPolicyEstimator->processBlock(nBlockHeight, entries); for (const auto &tx : vtx) { - txiter it = mapTx.find(tx->GetId()); + txiter it = mapTx.find(tx->GetHash()); if (it != mapTx.end()) { setEntries stage; stage.insert(it); RemoveStaged(stage, true, MemPoolRemovalReason::BLOCK); } removeConflicts(*tx); - ClearPrioritisation(tx->GetId()); + ClearPrioritisation(tx->GetHash()); } lastRollingFeeUpdate = GetTime(); blockSinceLastRollingFeeBump = true; @@ -703,7 +707,7 @@ // Check that every mempool transaction's inputs refer to available // coins, or other mempool tx's. indexed_transaction_set::const_iterator it2 = - mapTx.find(txin.prevout.hash); + findByunspentid(txin.prevout.unspentid); if (it2 != mapTx.end()) { const CTransaction &tx2 = it2->GetTx(); assert(tx2.vout.size() > txin.prevout.n && @@ -748,12 +752,13 @@ // Check children against mapNextTx CTxMemPool::setEntries setChildrenCheck; - auto iter = mapNextTx.lower_bound(COutPoint(it->GetTx().GetId(), 0)); + auto iter = + mapNextTx.lower_bound(COutPoint(it->GetTx().Getunspentid(), 0)); int64_t childSizes = 0; for (; iter != mapNextTx.end() && - iter->first->hash == it->GetTx().GetId(); + iter->first->unspentid == it->GetTx().Getunspentid(); ++iter) { - txiter childit = mapTx.find(iter->second->GetId()); + txiter childit = mapTx.find(iter->second->GetHash()); assert(childit != mapTx.end()); // mapNextTx points to in-mempool transactions if (setChildrenCheck.insert(childit).second) { @@ -797,8 +802,8 @@ } } for (auto it = mapNextTx.cbegin(); it != mapNextTx.cend(); it++) { - uint256 txid = it->second->GetId(); - indexed_transaction_set::const_iterator it2 = mapTx.find(txid); + txhash_t txhash = it->second->GetHash(); + indexed_transaction_set::const_iterator it2 = mapTx.find(txhash); const CTransaction &tx = it2->GetTx(); assert(it2 != mapTx.end()); assert(&tx == it->second); @@ -808,8 +813,8 @@ assert(innerUsage == cachedInnerUsage); } -bool CTxMemPool::CompareDepthAndScore(const uint256 &hasha, - const uint256 &hashb) { +bool CTxMemPool::CompareDepthAndScore(const txhash_t &hasha, + const txhash_t &hashb) { LOCK(cs); indexed_transaction_set::const_iterator i = mapTx.find(hasha); if (i == mapTx.end()) return false; @@ -854,15 +859,15 @@ return iters; } -void CTxMemPool::queryHashes(std::vector &vtxid) { +void CTxMemPool::queryHashes(std::vector &vtxhash) { LOCK(cs); auto iters = GetSortedDepthAndScore(); - vtxid.clear(); - vtxid.reserve(mapTx.size()); + vtxhash.clear(); + vtxhash.reserve(mapTx.size()); for (auto it : iters) { - vtxid.push_back(it->GetTx().GetId()); + vtxhash.push_back(it->GetTx().GetHash()); } } @@ -886,16 +891,23 @@ return ret; } -CTransactionRef CTxMemPool::get(const uint256 &txid) const { +CTransactionRef CTxMemPool::get(const unspentid_t &unspentid) const { + LOCK(cs); + indexed_transaction_set::const_iterator i = findByunspentid(unspentid); + if (i == mapTx.end()) return nullptr; + return i->GetSharedTx(); +} + +CTransactionRef CTxMemPool::get(const txhash_t &txhash) const { LOCK(cs); - indexed_transaction_set::const_iterator i = mapTx.find(txid); + indexed_transaction_set::const_iterator i = mapTx.find(txhash); if (i == mapTx.end()) return nullptr; return i->GetSharedTx(); } -TxMempoolInfo CTxMemPool::info(const uint256 &txid) const { +TxMempoolInfo CTxMemPool::info(const txhash_t &txhash) const { LOCK(cs); - indexed_transaction_set::const_iterator i = mapTx.find(txid); + indexed_transaction_set::const_iterator i = mapTx.find(txhash); if (i == mapTx.end()) return TxMempoolInfo(); return GetInfo(i); } @@ -955,16 +967,16 @@ return true; } -void CTxMemPool::PrioritiseTransaction(const uint256 hash, +void CTxMemPool::PrioritiseTransaction(const txhash_t txhash, const std::string strHash, double dPriorityDelta, const Amount nFeeDelta) { { LOCK(cs); - std::pair &deltas = mapDeltas[hash]; + std::pair &deltas = mapDeltas[txhash]; deltas.first += dPriorityDelta; deltas.second += nFeeDelta; - txiter it = mapTx.find(hash); + txiter it = mapTx.find(txhash); if (it != mapTx.end()) { mapTx.modify(it, update_fee_delta(deltas.second)); // Now update all ancestors' modified fees with descendants @@ -991,25 +1003,25 @@ dPriorityDelta, FormatMoney(nFeeDelta)); } -void CTxMemPool::ApplyDeltas(const uint256 hash, double &dPriorityDelta, +void CTxMemPool::ApplyDeltas(const txhash_t txhash, double &dPriorityDelta, Amount nFeeDelta) const { LOCK(cs); - std::map>::const_iterator pos = - mapDeltas.find(hash); + std::map>::const_iterator pos = + mapDeltas.find(txhash); if (pos == mapDeltas.end()) return; const std::pair &deltas = pos->second; dPriorityDelta += deltas.first; nFeeDelta += deltas.second; } -void CTxMemPool::ClearPrioritisation(const uint256 hash) { +void CTxMemPool::ClearPrioritisation(const txhash_t txhash) { LOCK(cs); - mapDeltas.erase(hash); + mapDeltas.erase(txhash); } bool CTxMemPool::HasNoInputsOf(const CTransaction &tx) const { for (unsigned int i = 0; i < tx.vin.size(); i++) - if (exists(tx.vin[i].prevout.hash)) return false; + if (exists(tx.vin[i].prevout.unspentid)) return false; return true; } @@ -1022,7 +1034,7 @@ // guaranteed to never conflict with the underlying cache, and it cannot // have pruned entries (as it contains full) transactions. First checking // the underlying cache risks returning a pruned entry instead. - CTransactionRef ptx = mempool.get(outpoint.hash); + CTransactionRef ptx = mempool.get(outpoint.unspentid); if (ptx) { if (outpoint.n < ptx->vout.size()) { coin = Coin(ptx->vout[outpoint.n], MEMPOOL_HEIGHT, false); @@ -1077,7 +1089,8 @@ return stage.size(); } -bool CTxMemPool::addUnchecked(const uint256 &hash, const CTxMemPoolEntry &entry, +bool CTxMemPool::addUnchecked(const txhash_t &txhash, + const CTxMemPoolEntry &entry, bool validFeeEstimate) { LOCK(cs); setEntries setAncestors; @@ -1085,7 +1098,7 @@ std::string dummy; CalculateMemPoolAncestors(entry, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy); - return addUnchecked(hash, entry, setAncestors, validFeeEstimate); + return addUnchecked(txhash, entry, setAncestors, validFeeEstimate); } void CTxMemPool::UpdateChild(txiter entry, txiter child, bool add) { @@ -1194,7 +1207,7 @@ if (pvNoSpendsRemaining) { for (const CTransaction &tx : txn) { for (const CTxIn &txin : tx.vin) { - if (exists(txin.prevout.hash)) { + if (exists(txin.prevout.unspentid)) { continue; } if (!mapNextTx.count(txin.prevout)) { @@ -1211,14 +1224,14 @@ nTxnRemoved, maxFeeRateRemoved.ToString()); } -bool CTxMemPool::TransactionWithinChainLimit(const uint256 &txid, +bool CTxMemPool::TransactionWithinChainLimit(const txhash_t &txhash, size_t chainLimit) const { LOCK(cs); - auto it = mapTx.find(txid); + auto it = mapTx.find(txhash); return it == mapTx.end() || (it->GetCountWithAncestors() < chainLimit && it->GetCountWithDescendants() < chainLimit); } -SaltedTxidHasher::SaltedTxidHasher() +SaltedTxHasher::SaltedTxHasher() : k0(GetRand(std::numeric_limits::max())), k1(GetRand(std::numeric_limits::max())) {} diff --git a/src/undo.h b/src/undo.h --- a/src/undo.h +++ b/src/undo.h @@ -72,6 +72,9 @@ static const size_t MAX_INPUTS_PER_TX = MAX_TX_SIZE / ::GetSerializeSize(CTxIn(), SER_NETWORK, PROTOCOL_VERSION); +static const size_t MAX_OUTPUTS_PER_TX = + MAX_TX_SIZE / ::GetSerializeSize(CTxOut(), SER_NETWORK, PROTOCOL_VERSION); + /** Restore the UTXO in a Coin at a given COutPoint */ class CTxUndo { public: diff --git a/src/validation.h b/src/validation.h --- a/src/validation.h +++ b/src/validation.h @@ -315,7 +315,7 @@ */ std::string GetWarnings(const std::string &strFor); /** Retrieve a transaction (from memory pool, or from disk, if possible) */ -bool GetTransaction(const Config &config, const uint256 &hash, +bool GetTransaction(const Config &config, const txhash_t &hash, CTransactionRef &tx, uint256 &hashBlock); /** Find the best known block, and make it the tip of the block chain */ bool ActivateBestChain( diff --git a/src/validation.cpp b/src/validation.cpp --- a/src/validation.cpp +++ b/src/validation.cpp @@ -649,9 +649,9 @@ return false; } - const CTransactionRef &txFrom = pool.get(txin.prevout.hash); + const CTransactionRef &txFrom = pool.get(txin.prevout.unspentid); if (txFrom) { - assert(txFrom->GetHash() == txin.prevout.hash); + assert(txFrom->GetUnspentid() == txin.prevout.unspentid); assert(txFrom->vout.size() > txin.prevout.n); assert(txFrom->vout[txin.prevout.n] == coin.GetTxOut()); } else { @@ -674,7 +674,9 @@ AssertLockHeld(cs_main); const CTransaction &tx = *ptx; - const uint256 txid = tx.GetId(); + const txhash_t txhash = tx.GetHash(); + const unspentid_t unspentid = tx.GetUnspentid(); + if (pfMissingInputs) { *pfMissingInputs = false; } @@ -706,7 +708,7 @@ } // Is it already in the memory pool? - if (pool.exists(txid)) { + if (pool.exists(txhash)) { return state.Invalid(false, REJECT_ALREADY_KNOWN, "txn-already-in-mempool"); } @@ -738,7 +740,7 @@ // Do we already have it? for (size_t out = 0; out < tx.vout.size(); out++) { - COutPoint outpoint(txid, out); + COutPoint outpoint(unspentid, out); bool had_coin_in_cache = pcoinsTip->HaveCoinInCache(outpoint); if (view.HaveCoin(outpoint)) { if (!had_coin_in_cache) { @@ -807,7 +809,7 @@ // nModifiedFees includes any fee deltas from PrioritiseTransaction CAmount nModifiedFees = nFees.GetSatoshis(); double nPriorityDummy = 0; - pool.ApplyDeltas(txid, nPriorityDummy, nModifiedFees); + pool.ApplyDeltas(txhash, nPriorityDummy, nModifiedFees); Amount inChainInputValue; double dPriority = @@ -955,7 +957,7 @@ return error( "%s: BUG! PLEASE REPORT THIS! ConnectInputs failed against " "MANDATORY but not STANDARD flags %s, %s", - __func__, txid.ToString(), FormatStateMessage(state)); + __func__, txhash.ToString(), FormatStateMessage(state)); } if (!CheckInputs(tx, state, view, true, @@ -964,7 +966,7 @@ return error( "%s: ConnectInputs failed against MANDATORY but not " "STANDARD flags due to promiscuous mempool %s, %s", - __func__, txid.ToString(), FormatStateMessage(state)); + __func__, txhash.ToString(), FormatStateMessage(state)); } LogPrintf("Warning: -promiscuousmempool flags set to not include " @@ -979,14 +981,14 @@ IsCurrentForFeeEstimation() && pool.HasNoInputsOf(tx); // Store transaction in memory. - pool.addUnchecked(txid, entry, setAncestors, validForFeeEstimation); + pool.addUnchecked(txhash, entry, setAncestors, validForFeeEstimation); // Trim mempool and check if tx was trimmed. if (!fOverrideMempoolLimit) { LimitMempoolSize( pool, GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60); - if (!pool.exists(txid)) { + if (!pool.exists(txhash)) { return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "mempool full"); } @@ -1033,12 +1035,12 @@ /** Return transaction in txOut, and if it was found inside a block, its hash is * placed in hashBlock */ -bool GetTransaction(const Config &config, const uint256 &txid, +bool GetTransaction(const Config &config, const txhash_t &txhash, CTransactionRef &txOut, uint256 &hashBlock) { LOCK(cs_main); - CTransactionRef ptx = mempool.get(txid); + CTransactionRef ptx = mempool.get(txhash); if (ptx) { txOut = ptx; return true; @@ -1046,7 +1048,7 @@ if (fTxIndex) { CDiskTxPos postx; - if (pblocktree->ReadTxIndex(txid, postx)) { + if (pblocktree->ReadTxIndex(txhash, postx)) { CAutoFile file(OpenBlockFile(postx, true), SER_DISK, CLIENT_VERSION); if (file.IsNull()) @@ -1061,8 +1063,8 @@ e.what()); } hashBlock = header.GetHash(); - if (txOut->GetId() != txid) - return error("%s: txid mismatch", __func__); + if (txOut->GetHash() != txhash) + return error("%s: txhash mismatch", __func__); return true; } } @@ -1576,17 +1578,28 @@ // this information only in undo records for the last spend of a // transactions' outputs. This implies that it must be present for some // other output of the same tx. - const Coin &alternate = AccessByTxid(view, out.hash); - if (alternate.IsSpent()) { + COutPoint iter(out.unspentid, 0); + while (iter.n < MAX_OUTPUTS_PER_TX) { + const Coin &alternate = view.AccessCoin(iter); + if (!alternate.IsSpent()) { + + // This is somewhat ugly, but hopefully utility is limited. This + // is only + // useful when working from legacy on disck data. In any case, + // putting + // the correct information in there doesn't hurt. + const_cast(undo) = + Coin(undo.GetTxOut(), alternate.GetHeight(), + alternate.IsCoinBase()); + break; + } + ++iter.n; + } + + if (iter.n == MAX_OUTPUTS_PER_TX) { // Adding output for transaction without known metadata return DISCONNECT_FAILED; } - - // This is somewhat ugly, but hopefully utility is limited. This is only - // useful when working from legacy on disck data. In any case, putting - // the correct information in there doesn't hurt. - const_cast(undo) = Coin(undo.GetTxOut(), alternate.GetHeight(), - alternate.IsCoinBase()); } view.AddCoin(out, undo, undo.IsCoinBase()); @@ -1632,7 +1645,7 @@ size_t i = block.vtx.size(); while (i-- > 0) { const CTransaction &tx = *(block.vtx[i]); - uint256 txid = tx.GetId(); + unspentid_t unspentid = tx.GetUnspentid(); // Check that all outputs are available and match the outputs in the // block itself exactly. @@ -1641,7 +1654,7 @@ continue; } - COutPoint out(txid, o); + COutPoint out(unspentid, o); Coin coin; bool is_spent = view.SpendCoin(out, &coin); if (!is_spent || tx.vout[o] != coin.GetTxOut()) { @@ -1935,7 +1948,7 @@ if (fEnforceBIP30) { for (const auto &tx : block.vtx) { for (size_t o = 0; o < tx->vout.size(); o++) { - if (view.HaveCoin(COutPoint(tx->GetHash(), o))) { + if (view.HaveCoin(COutPoint(tx->GetUnspentid(), o))) { return state.DoS( 100, error("ConnectBlock(): tried to overwrite transaction"), @@ -1977,7 +1990,7 @@ CDiskTxPos pos(pindex->GetBlockPos(), GetSizeOfCompactSize(block.vtx.size())); - std::vector> vPos; + std::vector> vPos; vPos.reserve(block.vtx.size()); blockundo.vtxundo.reserve(block.vtx.size() - 1); @@ -2036,7 +2049,8 @@ fCacheResults, fCacheResults, PrecomputedTransactionData(tx), &vChecks)) { return error("ConnectBlock(): CheckInputs on %s failed with %s", - tx.GetId().ToString(), FormatStateMessage(state)); + tx.GetHash().ToString(), + FormatStateMessage(state)); } control.Add(vChecks); @@ -2049,7 +2063,7 @@ UpdateCoins(tx, view, i == 0 ? undoDummy : blockundo.vtxundo.back(), pindex->nHeight); - vPos.push_back(std::make_pair(tx.GetId(), pos)); + vPos.push_back(std::make_pair(tx.GetHash(), pos)); pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION); } @@ -2125,9 +2139,9 @@ 0.001 * (nTime5 - nTime4), nTimeIndex * 0.000001); // Watch for changes to the previous coinbase transaction. - static uint256 hashPrevBestCoinBase; + static txhash_t hashPrevBestCoinBase; GetMainSignals().UpdatedTransaction(hashPrevBestCoinBase); - hashPrevBestCoinBase = block.vtx[0]->GetId(); + hashPrevBestCoinBase = block.vtx[0]->GetHash(); int64_t nTime6 = GetTimeMicros(); nTimeCallbacks += nTime6 - nTime5; @@ -2417,7 +2431,7 @@ if (!fBare) { // Resurrect mempool transactions from the disconnected block. - std::vector vHashUpdate; + std::vector vHashUpdate; for (const auto &it : block.vtx) { const CTransaction &tx = *it; // ignore validation errors in resurrected transactions @@ -2426,8 +2440,8 @@ !AcceptToMemoryPool(config, mempool, stateDummy, it, false, nullptr, nullptr, true)) { mempool.removeRecursive(tx, MemPoolRemovalReason::REORG); - } else if (mempool.exists(tx.GetId())) { - vHashUpdate.push_back(tx.GetId()); + } else if (mempool.exists(tx.GetHash())) { + vHashUpdate.push_back(tx.GetHash()); } } // AcceptToMemoryPool/addUnchecked all assume that new mempool entries @@ -3222,8 +3236,8 @@ if (!CheckCoinbase(*block.vtx[0], state, false)) { return state.Invalid(false, state.GetRejectCode(), state.GetRejectReason(), - strprintf("Coinbase check failed (txid %s) %s", - block.vtx[0]->GetId().ToString(), + strprintf("Coinbase check failed (txhash %s) %s", + block.vtx[0]->GetHash().ToString(), state.GetDebugMessage())); } @@ -3260,8 +3274,8 @@ if (!CheckRegularTransaction(*tx, state, false)) { return state.Invalid( false, state.GetRejectCode(), state.GetRejectReason(), - strprintf("Transaction check failed (txid %s) %s", - tx->GetId().ToString(), state.GetDebugMessage())); + strprintf("Transaction check failed (txhash %s) %s", + tx->GetHash().ToString(), state.GetDebugMessage())); } } @@ -4902,8 +4916,8 @@ CAmount amountdelta = nFeeDelta; if (amountdelta) { - mempool.PrioritiseTransaction(tx->GetId(), - tx->GetId().ToString(), + mempool.PrioritiseTransaction(tx->GetHash(), + tx->GetHash().ToString(), prioritydummy, amountdelta); } CValidationState state; @@ -4921,7 +4935,7 @@ } if (ShutdownRequested()) return false; } - std::map mapDeltas; + std::map mapDeltas; file >> mapDeltas; for (const auto &i : mapDeltas) { @@ -4974,7 +4988,7 @@ file << *(i.tx); file << (int64_t)i.nTime; file << (int64_t)i.nFeeDelta.GetSatoshis(); - mapDeltas.erase(i.tx->GetId()); + mapDeltas.erase(i.tx->GetHash()); } file << mapDeltas; diff --git a/src/validationinterface.h b/src/validationinterface.h --- a/src/validationinterface.h +++ b/src/validationinterface.h @@ -20,6 +20,7 @@ class CValidationInterface; class CValidationState; class uint256; +class txhash_t; // These functions dispatch to one or all registered wallets @@ -38,7 +39,7 @@ virtual void SyncTransaction(const CTransaction &tx, const CBlockIndex *pindex, int posInBlock) {} virtual void SetBestChain(const CBlockLocator &locator) {} - virtual void UpdatedTransaction(const uint256 &hash) {} + virtual void UpdatedTransaction(const txhash_t &hash) {} virtual void Inventory(const uint256 &hash) {} virtual void ResendWalletTransactions(int64_t nBestBlockTime, CConnman *connman) {} @@ -78,7 +79,7 @@ * Notifies listeners of an updated transaction without new data (for now: a * coinbase potentially becoming visible). */ - boost::signals2::signal UpdatedTransaction; + boost::signals2::signal UpdatedTransaction; /** Notifies listeners of a new active block chain. */ boost::signals2::signal SetBestChain; /** Notifies listeners about an inventory item being seen on the network. */ diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp --- a/src/validationinterface.cpp +++ b/src/validationinterface.cpp @@ -4,6 +4,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "validationinterface.h" +#include "primitives/transaction.h" static CMainSignals g_signals; diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -286,7 +286,7 @@ CMutableTransaction tx; if (!DecodeHexTx(tx, request.params[0].get_str())) throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); - uint256 txid = tx.GetId(); + const txhash_t txhash = tx.GetHash(); CWalletTx wtx(pwalletMain, MakeTransactionRef(std::move(tx))); CDataStream ssMB(ParseHexV(request.params[1], "proof"), SER_NETWORK, @@ -310,7 +310,7 @@ "Block not found in chain"); std::vector::const_iterator it; - if ((it = std::find(vMatch.begin(), vMatch.end(), txid)) == + if ((it = std::find(vMatch.begin(), vMatch.end(), txhash)) == vMatch.end()) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction given doesn't exist in proof"); @@ -345,12 +345,13 @@ if (request.fHelp || request.params.size() != 1) { throw std::runtime_error( - "removeprunedfunds \"txid\"\n" + "removeprunedfunds \"txhash\"\n" "\nDeletes the specified transaction from the wallet. Meant for " "use with pruned wallets and as a companion to importprunedfunds. " "This will effect wallet balances.\n" "\nArguments:\n" - "1. \"txid\" (string, required) The hex-encoded id of " + "1. \"txhash\" (string, required) The hex-encoded hash " + "of " "the transaction you are deleting\n" "\nExamples:\n" + HelpExampleCli("removeprunedfunds", "\"a8d0c0184dde994a09ec054286f1" @@ -364,11 +365,11 @@ LOCK2(cs_main, pwalletMain->cs_wallet); - uint256 hash; + txhash_t hash; hash.SetHex(request.params[0].get_str()); - std::vector vHash; + std::vector vHash; vHash.push_back(hash); - std::vector vHashOut; + std::vector vHashOut; if (pwalletMain->ZapSelectTx(vHash, vHashOut) != DB_LOAD_OK) { throw JSONRPCError(RPC_WALLET_ERROR, @@ -1236,7 +1237,7 @@ { "wallet", "importaddress", importaddress, true, {"address","label","rescan","p2sh"} }, { "wallet", "importprunedfunds", importprunedfunds, true, {"rawtransaction","txoutproof"} }, { "wallet", "importpubkey", importpubkey, true, {"pubkey","label","rescan"} }, - { "wallet", "removeprunedfunds", removeprunedfunds, true, {"txid"} }, + { "wallet", "removeprunedfunds", removeprunedfunds, true, {"txhash"} }, }; // clang-format on diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -69,10 +69,10 @@ } else { entry.push_back(Pair("trusted", wtx.IsTrusted())); } - uint256 hash = wtx.GetId(); - entry.push_back(Pair("txid", hash.GetHex())); + uint256 hash = wtx.GetHash(); + entry.push_back(Pair("txhash", hash.GetHex())); UniValue conflicts(UniValue::VARR); - for (const uint256 &conflict : wtx.GetConflicts()) { + for (const txhash_t &conflict : wtx.GetConflicts()) { conflicts.push_back(conflict.GetHex()); } entry.push_back(Pair("walletconflicts", conflicts)); @@ -460,7 +460,7 @@ " The recipient will receive less " "bitcoins than you enter in the amount field.\n" "\nResult:\n" - "\"txid\" (string) The transaction id.\n" + "\"txhash\" (string) The transaction hash.\n" "\nExamples:\n" + HelpExampleCli("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1") + @@ -508,7 +508,7 @@ SendMoney(dest, nAmount, fSubtractFeeFromAmount, wtx); - return wtx.GetId().GetHex(); + return wtx.GetHash().GetHex(); } static UniValue listaddressgroupings(const Config &config, @@ -698,7 +698,7 @@ // Tally CAmount nAmount = 0; - for (std::map::iterator it = + for (std::map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { const CWalletTx &wtx = (*it).second; @@ -771,7 +771,7 @@ // Tally CAmount nAmount = 0; - for (std::map::iterator it = + for (std::map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { const CWalletTx &wtx = (*it).second; @@ -876,7 +876,7 @@ // TxIns spending from the wallet. This also has fewer restrictions on // which unconfirmed transactions are considered trusted. CAmount nBalance = 0; - for (std::map::iterator it = + for (std::map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { const CWalletTx &wtx = (*it).second; @@ -1041,7 +1041,7 @@ " it is just kept in your " "wallet.\n" "\nResult:\n" - "\"txid\" (string) The transaction id.\n" + "\"txhash\" (string) The transaction hash.\n" "\nExamples:\n" "\nSend 0.01 " + CURRENCY_UNIT + " from the default account to the address, must " @@ -1101,7 +1101,7 @@ SendMoney(dest, nAmount, false, wtx); - return wtx.GetId().GetHex(); + return wtx.GetHash().GetHex(); } static UniValue sendmany(const Config &config, const JSONRPCRequest &request) { @@ -1148,7 +1148,7 @@ " ,...\n" " ]\n" "\nResult:\n" - "\"txid\" (string) The transaction id for the " + "\"txhash\" (string) The transaction hash for the " "send. Only 1 transaction is created regardless of \n" " the number of addresses.\n" "\nExamples:\n" @@ -1276,7 +1276,7 @@ throw JSONRPCError(RPC_WALLET_ERROR, strFailReason); } - return wtx.GetId().GetHex(); + return wtx.GetHash().GetHex(); } static UniValue addmultisigaddress(const Config &config, @@ -1344,7 +1344,7 @@ struct tallyitem { CAmount nAmount; int nConf; - std::vector txids; + std::vector txhashes; bool fIsWatchonly; tallyitem() { nAmount = 0; @@ -1373,7 +1373,7 @@ // Tally std::map mapTally; - for (std::map::iterator it = + for (std::map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { const CWalletTx &wtx = (*it).second; @@ -1405,7 +1405,7 @@ tallyitem &item = mapTally[address]; item.nAmount += txout.nValue.GetSatoshis(); item.nConf = std::min(item.nConf, nDepth); - item.txids.push_back(wtx.GetId()); + item.txhashes.push_back(wtx.GetHash()); if (mine & ISMINE_WATCH_ONLY) { item.fIsWatchonly = true; } @@ -1454,11 +1454,11 @@ } UniValue transactions(UniValue::VARR); if (it != mapTally.end()) { - for (const uint256 &_item : (*it).second.txids) { + for (const uint256 &_item : (*it).second.txhashes) { transactions.push_back(_item.GetHex()); } } - obj.push_back(Pair("txids", transactions)); + obj.push_back(Pair("txhashes", transactions)); ret.push_back(obj); } } @@ -1520,7 +1520,7 @@ "confirmations of the most recent transaction included\n" " \"label\" : \"label\", (string) A comment for " "the address/transaction, if any\n" - " \"txids\": [\n" + " \"txhashes\": [\n" " n, (numeric) The ids of " "transactions received with the address \n" " ...\n" @@ -1763,7 +1763,8 @@ "transactions.\n" " \"blocktime\": xxx, (numeric) The block time in " "seconds since epoch (1 Jan 1970 GMT).\n" - " \"txid\": \"transactionid\", (string) The transaction id. " + " \"txhash\": \"transactionhash\", (string) The transaction " + "hash. " "Available for 'send' and 'receive' category of transactions.\n" " \"time\": xxx, (numeric) The transaction time in " "seconds since epoch (midnight Jan 1 1970 GMT).\n" @@ -1932,7 +1933,7 @@ } } - for (std::map::iterator it = + for (std::map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { const CWalletTx &wtx = (*it).second; @@ -2034,7 +2035,8 @@ "and 'receive' category of transactions.\n" " \"blocktime\": xxx, (numeric) The block time in " "seconds since epoch (1 Jan 1970 GMT).\n" - " \"txid\": \"transactionid\", (string) The transaction id. " + " \"txhash\": \"transactionhash\", (string) The transaction " + "hash. " "Available for 'send' and 'receive' category of transactions.\n" " \"time\": xxx, (numeric) The transaction time in " "seconds since epoch (Jan 1 1970 GMT).\n" @@ -2102,10 +2104,10 @@ UniValue transactions(UniValue::VARR); - for (std::map::iterator it = + for (std::map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++) { - CWalletTx tx = (*it).second; + CWalletTx &tx = (*it).second; if (depth == -1 || tx.GetDepthInMainChain() < depth) { ListTransactions(tx, "*", 0, true, transactions, filter); @@ -2132,10 +2134,10 @@ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) { throw std::runtime_error( - "gettransaction \"txid\" ( include_watchonly )\n" - "\nGet detailed information about in-wallet transaction \n" + "gettransaction \"txhash\" ( include_watchonly )\n" + "\nGet detailed information about in-wallet transaction \n" "\nArguments:\n" - "1. \"txid\" (string, required) The transaction " + "1. \"txhash\" (string, required) The transaction " "id\n" "2. \"include_watchonly\" (bool, optional, default=false) " "Whether to include watch-only addresses in balance calculation " @@ -2157,7 +2159,8 @@ "transaction in the block that includes it\n" " \"blocktime\" : ttt, (numeric) The time in seconds since " "epoch (1 Jan 1970 GMT)\n" - " \"txid\" : \"transactionid\", (string) The transaction id.\n" + " \"txhash\" : \"transactionhhash\", (string) The transaction " + "hash.\n" " \"time\" : ttt, (numeric) The transaction time in " "seconds since epoch (1 Jan 1970 GMT)\n" " \"timereceived\" : ttt, (numeric) The time received in " @@ -2215,8 +2218,8 @@ LOCK2(cs_main, pwalletMain->cs_wallet); - uint256 hash; - hash.SetHex(request.params[0].get_str()); + txhash_t txhash; + txhash.SetHex(request.params[0].get_str()); isminefilter filter = ISMINE_SPENDABLE; if (request.params.size() > 1 && request.params[1].get_bool()) { @@ -2224,35 +2227,33 @@ } UniValue entry(UniValue::VOBJ); - if (!pwalletMain->mapWallet.count(hash)) { - { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, - "Invalid or non-wallet transaction id"); - } - } - const CWalletTx &wtx = pwalletMain->mapWallet[hash]; + const CWalletTx *wtx = pwalletMain->GetWalletTx(txhash); + if (!wtx) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, + "Invalid or non-wallet transaction id"); + } - CAmount nCredit = wtx.GetCredit(filter); - CAmount nDebit = wtx.GetDebit(filter); + CAmount nCredit = wtx->GetCredit(filter); + CAmount nDebit = wtx->GetDebit(filter); CAmount nNet = nCredit - nDebit; CAmount nFee = - (wtx.IsFromMe(filter) ? wtx.tx->GetValueOut() - nDebit : Amount(0)) + (wtx->IsFromMe(filter) ? wtx->tx->GetValueOut() - nDebit : Amount(0)) .GetSatoshis(); entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee))); - if (wtx.IsFromMe(filter)) { + if (wtx->IsFromMe(filter)) { entry.push_back(Pair("fee", ValueFromAmount(nFee))); } - WalletTxToJSON(wtx, entry); + WalletTxToJSON(*wtx, entry); UniValue details(UniValue::VARR); - ListTransactions(wtx, "*", 0, false, details, filter); + ListTransactions(*wtx, "*", 0, false, details, filter); entry.push_back(Pair("details", details)); std::string strHex = - EncodeHexTx(static_cast(wtx), RPCSerializationFlags()); + EncodeHexTx(static_cast(*wtx), RPCSerializationFlags()); entry.push_back(Pair("hex", strHex)); return entry; @@ -2266,8 +2267,8 @@ if (request.fHelp || request.params.size() != 1) { throw std::runtime_error( - "abandontransaction \"txid\"\n" - "\nMark in-wallet transaction as abandoned\n" + "abandontransaction \"txhash\"\n" + "\nMark in-wallet transaction as abandoned\n" "This will mark this transaction and all its in-wallet descendants " "as abandoned which will allow\n" "for their inputs to be respent. It can be used to replace " @@ -2277,7 +2278,7 @@ "It has no effect on transactions which are already conflicted or " "abandoned.\n" "\nArguments:\n" - "1. \"txid\" (string, required) The transaction id\n" + "1. \"txhash\" (string, required) The transaction hash\n" "\nResult:\n" "\nExamples:\n" + HelpExampleCli("abandontransaction", "\"1075db55d416d3ca199f55b6084" @@ -2290,15 +2291,14 @@ LOCK2(cs_main, pwalletMain->cs_wallet); - uint256 hash; - hash.SetHex(request.params[0].get_str()); + txhash_t txhash; + txhash.SetHex(request.params[0].get_str()); - if (!pwalletMain->mapWallet.count(hash)) { + if (!pwalletMain->GetWalletTx(txhash)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id"); } - - if (!pwalletMain->AbandonTransaction(hash)) { + if (!pwalletMain->AbandonTransaction(txhash)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not eligible for abandonment"); } @@ -2653,7 +2653,8 @@ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) { throw std::runtime_error( - "lockunspent unlock ([{\"txid\":\"txid\",\"vout\":n},...])\n" + "lockunspent unlock " + "([{\"unspentid\":\"unspentid\",\"vout\":n},...])\n" "\nUpdates list of temporarily unspendable outputs.\n" "Temporarily lock (unlock=false) or unlock (unlock=true) specified " "transaction outputs.\n" @@ -2670,10 +2671,11 @@ "1. unlock (boolean, required) Whether to unlock (true) " "or lock (false) the specified transactions\n" "2. \"transactions\" (string, optional) A json array of objects. " - "Each object the txid (string) vout (numeric)\n" + "Each object the unspentid (string) vout (numeric)\n" " [ (json array of json objects)\n" " {\n" - " \"txid\":\"id\", (string) The transaction id\n" + " \"unspentid\":\"id\", (string) The unpent transaction " + "id\n" " \"vout\": n (numeric) The output number\n" " }\n" " ,...\n" @@ -2688,7 +2690,7 @@ HelpExampleCli("listunspent", "") + "\nLock an unspent transaction\n" + HelpExampleCli("lockunspent", "false " - "\"[{\\\"txid\\\":" + "\"[{\\\"unspentid\\\":" "\\\"a08e6907dbbd3d809776dbfc5d82e371" "b764ed838b5655e72f463568df1aadf0\\\"" ",\\\"vout\\\":1}]\"") + @@ -2696,13 +2698,13 @@ HelpExampleCli("listlockunspent", "") + "\nUnlock the transaction again\n" + HelpExampleCli("lockunspent", "true " - "\"[{\\\"txid\\\":" + "\"[{\\\"unspentid\\\":" "\\\"a08e6907dbbd3d809776dbfc5d82e371" "b764ed838b5655e72f463568df1aadf0\\\"" ",\\\"vout\\\":1}]\"") + "\nAs a json rpc call\n" + HelpExampleRpc("lockunspent", "false, " - "\"[{\\\"txid\\\":" + "\"[{\\\"unspentid\\\":" "\\\"a08e6907dbbd3d809776dbfc5d82e371" "b764ed838b5655e72f463568df1aadf0\\\"" ",\\\"vout\\\":1}]\"")); @@ -2735,14 +2737,14 @@ const UniValue &o = output.get_obj(); RPCTypeCheckObj(o, { - {"txid", UniValueType(UniValue::VSTR)}, + {"unspentid", UniValueType(UniValue::VSTR)}, {"vout", UniValueType(UniValue::VNUM)}, }); - std::string txid = find_value(o, "txid").get_str(); - if (!IsHex(txid)) { + std::string unspentid = find_value(o, "unspentid").get_str(); + if (!IsHex(unspentid)) { throw JSONRPCError(RPC_INVALID_PARAMETER, - "Invalid parameter, expected hex txid"); + "Invalid parameter, expected hex unspentid"); } int nOutput = find_value(o, "vout").get_int(); @@ -2751,7 +2753,14 @@ "Invalid parameter, vout must be positive"); } - COutPoint outpt(uint256S(txid), nOutput); + const CWalletTx *wtx = + pwalletMain->GetWalletTx(unspentid_t(uint256S(unspentid))); + + if (!wtx) + throw JSONRPCError(RPC_INVALID_PARAMETER, + "Invalid parameter, unspentid unknown"); + + COutPoint outpt(wtx->tx->Getunspentid(), nOutput); if (fUnlock) { pwalletMain->UnlockCoin(outpt); @@ -2778,8 +2787,9 @@ "\nResult:\n" "[\n" " {\n" - " \"txid\" : \"transactionid\", (string) The transaction id " - "locked\n" + " \"unspentid\" : \"transactionid\", (string) The unpend " + "transaction " + "id locked\n" " \"vout\" : n (numeric) The vout value\n" " }\n" " ,...\n" @@ -2789,7 +2799,7 @@ HelpExampleCli("listunspent", "") + "\nLock an unspent transaction\n" + HelpExampleCli("lockunspent", "false " - "\"[{\\\"txid\\\":" + "\"[{\\\"unspentid\\\":" "\\\"a08e6907dbbd3d809776dbfc5d82e371" "b764ed838b5655e72f463568df1aadf0\\\"" ",\\\"vout\\\":1}]\"") + @@ -2797,7 +2807,7 @@ HelpExampleCli("listlockunspent", "") + "\nUnlock the transaction again\n" + HelpExampleCli("lockunspent", "true " - "\"[{\\\"txid\\\":" + "\"[{\\\"unspentid\\\":" "\\\"a08e6907dbbd3d809776dbfc5d82e371" "b764ed838b5655e72f463568df1aadf0\\\"" ",\\\"vout\\\":1}]\"") + @@ -2814,7 +2824,7 @@ for (COutPoint &outpt : vOutpts) { UniValue o(UniValue::VOBJ); - o.push_back(Pair("txid", outpt.hash.GetHex())); + o.push_back(Pair("unspentid", outpt.unspentid.GetHex())); o.push_back(Pair("vout", (int)outpt.n)); ret.push_back(o); } @@ -2946,11 +2956,11 @@ LOCK2(cs_main, pwalletMain->cs_wallet); - std::vector txids = + std::vector txhashes = pwalletMain->ResendWalletTransactionsBefore(GetTime(), g_connman.get()); UniValue result(UniValue::VARR); - for (const uint256 &txid : txids) { - result.push_back(txid.ToString()); + for (const txhash_t &txhash : txhashes) { + result.push_back(txhash.ToString()); } return result; @@ -2991,7 +3001,8 @@ "\nResult\n" "[ (array of json object)\n" " {\n" - " \"txid\" : \"txid\", (string) the transaction id \n" + " \"unspentid\" : \"unspentid\", (string) the unpent " + "transaction id \n" " \"vout\" : n, (numeric) the vout value\n" " \"address\" : \"address\", (string) the bitcoin address\n" " \"account\" : \"account\", (string) DEPRECATED. The " @@ -3083,7 +3094,7 @@ continue; UniValue entry(UniValue::VOBJ); - entry.push_back(Pair("txid", out.tx->GetId().GetHex())); + entry.push_back(Pair("unspentid", out.tx->tx->Getunspentid().GetHex())); entry.push_back(Pair("vout", out.i)); if (fValidAddress) { @@ -3339,7 +3350,7 @@ // ------------------- ------------------------ ---------------------- ---------- { "rawtransactions", "fundrawtransaction", fundrawtransaction, false, {"hexstring","options"} }, { "hidden", "resendwallettransactions", resendwallettransactions, true, {} }, - { "wallet", "abandontransaction", abandontransaction, false, {"txid"} }, + { "wallet", "abandontransaction", abandontransaction, false, {"txhash"} }, { "wallet", "addmultisigaddress", addmultisigaddress, true, {"nrequired","keys","account"} }, { "wallet", "backupwallet", backupwallet, true, {"destination"} }, { "wallet", "encryptwallet", encryptwallet, true, {"passphrase"} }, @@ -3351,7 +3362,7 @@ { "wallet", "getrawchangeaddress", getrawchangeaddress, true, {} }, { "wallet", "getreceivedbyaccount", getreceivedbyaccount, false, {"account","minconf"} }, { "wallet", "getreceivedbyaddress", getreceivedbyaddress, false, {"address","minconf"} }, - { "wallet", "gettransaction", gettransaction, false, {"txid","include_watchonly"} }, + { "wallet", "gettransaction", gettransaction, false, {"txhash","include_watchonly"} }, { "wallet", "getunconfirmedbalance", getunconfirmedbalance, false, {} }, { "wallet", "getwalletinfo", getwalletinfo, false, {} }, { "wallet", "keypoolrefill", keypoolrefill, true, {"newsize"} }, diff --git a/src/wallet/test/accounting_tests.cpp b/src/wallet/test/accounting_tests.cpp --- a/src/wallet/test/accounting_tests.cpp +++ b/src/wallet/test/accounting_tests.cpp @@ -42,7 +42,7 @@ wtx.mapValue["comment"] = "z"; pwalletMain->AddToWallet(wtx); - vpwtx.push_back(&pwalletMain->mapWallet[wtx.GetId()]); + vpwtx.push_back(&pwalletMain->mapWallet[wtx.GetHash()]); vpwtx[0]->nTimeReceived = (unsigned int)1333333335; vpwtx[0]->nOrderPos = -1; @@ -83,7 +83,7 @@ wtx.SetTx(MakeTransactionRef(std::move(tx))); } pwalletMain->AddToWallet(wtx); - vpwtx.push_back(&pwalletMain->mapWallet[wtx.GetId()]); + vpwtx.push_back(&pwalletMain->mapWallet[wtx.GetHash()]); vpwtx[1]->nTimeReceived = (unsigned int)1333333336; wtx.mapValue["comment"] = "x"; @@ -94,7 +94,7 @@ wtx.SetTx(MakeTransactionRef(std::move(tx))); } pwalletMain->AddToWallet(wtx); - vpwtx.push_back(&pwalletMain->mapWallet[wtx.GetId()]); + vpwtx.push_back(&pwalletMain->mapWallet[wtx.GetHash()]); vpwtx[2]->nTimeReceived = (unsigned int)1333333329; vpwtx[2]->nOrderPos = -1; diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -244,7 +244,7 @@ bool isAbandoned() const { return (hashBlock == ABANDON_HASH); } void setAbandoned() { hashBlock = ABANDON_HASH; } - const uint256 &GetId() const { return tx->GetId(); } + const txhash_t &GetHash() const { return tx->GetHash(); } bool IsCoinBase() const { return tx->IsCoinBase(); } }; @@ -425,7 +425,7 @@ bool RelayWalletTransaction(CConnman *connman); - std::set GetConflicts() const; + std::set GetConflicts() const; }; class COutput { @@ -586,14 +586,14 @@ * Used to keep track of spent outpoints, and detect and report conflicts * (double-spends or mutated transactions where the mutant gets mined). */ - typedef std::multimap TxSpends; + typedef std::multimap TxSpends; TxSpends mapTxSpends; - void AddToSpends(const COutPoint &outpoint, const uint256 &wtxid); - void AddToSpends(const uint256 &wtxid); + void AddToSpends(const COutPoint &outpoint, const txhash_t &wtxhash); + void AddToSpends(const txhash_t &wtxhash); /* Mark a transaction (and its in-wallet descendants) as conflicting with a * particular block. */ - void MarkConflicted(const uint256 &hashBlock, const uint256 &hashTx); + void MarkConflicted(const uint256 &hashBlock, const txhash_t &hashTx); void SyncMetaData(std::pair); @@ -674,7 +674,7 @@ fBroadcastTransactions = false; } - std::map mapWallet; + std::map mapWallet; std::list laccentries; typedef std::pair TxPair; @@ -690,7 +690,8 @@ std::set setLockedCoins; - const CWalletTx *GetWalletTx(const uint256 &hash) const; + const CWalletTx *GetWalletTx(const txhash_t &txhash) const; + const CWalletTx *GetWalletTx(const unspentid_t &unspentid) const; //! check whether we are allowed to upgrade (or already support) to the //! named feature @@ -719,9 +720,9 @@ std::set> &setCoinsRet, CAmount &nValueRet) const; - bool IsSpent(const uint256 &hash, unsigned int n) const; + bool IsSpent(const COutPoint &output) const; - bool IsLockedCoin(uint256 hash, unsigned int n) const; + bool IsLockedCoin(const COutPoint &outpoint) const; void LockCoin(const COutPoint &output); void UnlockCoin(const COutPoint &output); void UnlockAllCoins(); @@ -801,6 +802,8 @@ bool bForceNew = false); void MarkDirty(); + void MarkDirty(const COutPoint &outpoint); + bool AddToWallet(const CWalletTx &wtxIn, bool fFlushOnClose = true); bool LoadToWallet(const CWalletTx &wtxIn); void SyncTransaction(const CTransaction &tx, const CBlockIndex *pindex, @@ -813,8 +816,8 @@ void ReacceptWalletTransactions(); void ResendWalletTransactions(int64_t nBestBlockTime, CConnman *connman) override; - std::vector ResendWalletTransactionsBefore(int64_t nTime, - CConnman *connman); + std::vector ResendWalletTransactionsBefore(int64_t nTime, + CConnman *connman); CAmount GetBalance() const; CAmount GetUnconfirmedBalance() const; CAmount GetImmatureBalance() const; @@ -921,15 +924,15 @@ DBErrors LoadWallet(bool &fFirstRunRet); DBErrors ZapWalletTx(std::vector &vWtx); - DBErrors ZapSelectTx(std::vector &vHashIn, - std::vector &vHashOut); + DBErrors ZapSelectTx(std::vector &vHashIn, + std::vector &vHashOut); bool SetAddressBook(const CTxDestination &address, const std::string &strName, const std::string &purpose); bool DelAddressBook(const CTxDestination &address); - void UpdatedTransaction(const uint256 &hashTx) override; + void UpdatedTransaction(const txhash_t &hashTx) override; void Inventory(const uint256 &hash) override { LOCK(cs_wallet); @@ -971,11 +974,7 @@ //! Get wallet transactions that conflict with given transaction (spend same //! outputs) - std::set GetConflicts(const uint256 &txid) const; - - //! Check if a given transaction has any of its outputs spent by another - //! transaction in the wallet - bool HasWalletSpend(const uint256 &txid) const; + std::set GetConflicts(const txhash_t &txhash) const; //! Flush wallet (bitdb flush) void Flush(bool shutdown = false); @@ -996,7 +995,7 @@ * Wallet transaction added, removed or updated. * @note called with lock cs_wallet held. */ - boost::signals2::signal NotifyTransactionChanged; @@ -1018,12 +1017,7 @@ * Mark a transaction (and it in-wallet descendants) as abandoned so its * inputs may be respent. */ - bool AbandonTransaction(const uint256 &hashTx); - - /** - * Mark a transaction as replaced by another transaction (e.g., BIP 125). - */ - bool MarkReplaced(const uint256 &originalHash, const uint256 &newHash); + bool AbandonTransaction(const txhash_t &hashTx); /* Returns the wallets help message */ static std::string GetWalletHelpString(bool showDebug); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -78,13 +78,28 @@ }; std::string COutput::ToString() const { - return strprintf("COutput(%s, %d, %d) [%s]", tx->GetId().ToString(), i, + return strprintf("COutput(%s, %d, %d) [%s]", tx->GetHash().ToString(), i, nDepth, FormatMoney(tx->tx->vout[i].nValue.GetSatoshis())); } -const CWalletTx *CWallet::GetWalletTx(const uint256 &hash) const { +const CWalletTx *CWallet::GetWalletTx(const unspentid_t &unspentid) const { LOCK(cs_wallet); - std::map::const_iterator it = mapWallet.find(hash); + auto wtx_iter = std::find_if( + mapWallet.begin(), mapWallet.end(), + [&unspentid](const std::pair &t) -> bool { + return t.second.tx->Getunspentid() == unspentid; + }); + + if (wtx_iter == mapWallet.end()) { + return nullptr; + } + return &(wtx_iter->second); +} + +const CWalletTx *CWallet::GetWalletTx(const txhash_t &txhash) const { + LOCK(cs_wallet); + + std::map::const_iterator it = mapWallet.find(txhash); if (it == mapWallet.end()) { return nullptr; } @@ -487,11 +502,11 @@ return true; } -std::set CWallet::GetConflicts(const uint256 &txid) const { - std::set result; +std::set CWallet::GetConflicts(const txhash_t &txhash) const { + std::set result; AssertLockHeld(cs_wallet); - std::map::const_iterator it = mapWallet.find(txid); + std::map::const_iterator it = mapWallet.find(txhash); if (it == mapWallet.end()) { return result; } @@ -516,12 +531,6 @@ return result; } -bool CWallet::HasWalletSpend(const uint256 &txid) const { - AssertLockHeld(cs_wallet); - auto iter = mapTxSpends.lower_bound(COutPoint(txid, 0)); - return (iter != mapTxSpends.end() && iter->first.hash == txid); -} - void CWallet::Flush(bool shutdown) { bitdb.Flush(shutdown); } @@ -604,7 +613,7 @@ int nMinOrderPos = std::numeric_limits::max(); const CWalletTx *copyFrom = nullptr; for (TxSpends::iterator it = range.first; it != range.second; ++it) { - const uint256 &hash = it->second; + const txhash_t &hash = it->second; int n = mapWallet[hash].nOrderPos; if (n < nMinOrderPos) { nMinOrderPos = n; @@ -614,7 +623,7 @@ // Now copy data from copyFrom to rest: for (TxSpends::iterator it = range.first; it != range.second; ++it) { - const uint256 &hash = it->second; + const txhash_t &hash = it->second; CWalletTx *copyTo = &mapWallet[hash]; if (copyFrom == copyTo) { continue; @@ -638,15 +647,15 @@ /** * Outpoint is spent if any non-conflicted transaction, spends it: */ -bool CWallet::IsSpent(const uint256 &hash, unsigned int n) const { - const COutPoint outpoint(hash, n); +bool CWallet::IsSpent(const COutPoint &outpoint) const { + std::pair range; range = mapTxSpends.equal_range(outpoint); for (TxSpends::const_iterator it = range.first; it != range.second; ++it) { - const uint256 &wtxid = it->second; - std::map::const_iterator mit = - mapWallet.find(wtxid); + const txhash_t &txhash = it->second; + std::map::const_iterator mit = + mapWallet.find(txhash); if (mit != mapWallet.end()) { int depth = mit->second.GetDepthInMainChain(); if (depth > 0 || (depth == 0 && !mit->second.isAbandoned())) { @@ -659,24 +668,24 @@ return false; } -void CWallet::AddToSpends(const COutPoint &outpoint, const uint256 &wtxid) { - mapTxSpends.insert(std::make_pair(outpoint, wtxid)); +void CWallet::AddToSpends(const COutPoint &outpoint, const txhash_t &wtxhash) { + mapTxSpends.insert(std::make_pair(outpoint, wtxhash)); std::pair range; range = mapTxSpends.equal_range(outpoint); SyncMetaData(range); } -void CWallet::AddToSpends(const uint256 &wtxid) { - assert(mapWallet.count(wtxid)); - CWalletTx &thisTx = mapWallet[wtxid]; +void CWallet::AddToSpends(const txhash_t &wtxhash) { + assert(mapWallet.count(wtxhash)); + CWalletTx &thisTx = mapWallet[wtxhash]; // Coinbases don't spend anything! if (thisTx.IsCoinBase()) { return; } for (const CTxIn &txin : thisTx.tx->vin) { - AddToSpends(txin.prevout, wtxid); + AddToSpends(txin.prevout, wtxhash); } } @@ -809,7 +818,7 @@ typedef std::multimap TxItems; TxItems txByTime; - for (std::map::iterator it = mapWallet.begin(); + for (std::map::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { CWalletTx *wtx = &((*it).second); txByTime.insert( @@ -877,7 +886,7 @@ int64_t CWallet::IncOrderPosNext(CWalletDB *pwalletdb) { // nOrderPosNext AssertLockHeld(cs_wallet); - int64_t nRet = nOrderPosNext++; + const int64_t nRet = nOrderPosNext++; if (pwalletdb) { pwalletdb->WriteOrderPosNext(nOrderPosNext); } else { @@ -894,7 +903,7 @@ return false; } - int64_t nNow = GetAdjustedTime(); + const int64_t nNow = GetAdjustedTime(); // Debit CAccountingEntry debit; @@ -937,7 +946,7 @@ // Check if the current key has been used. CScript scriptPubKey = GetScriptForDestination(account.vchPubKey.GetID()); - for (std::map::iterator it = mapWallet.begin(); + for (std::map::iterator it = mapWallet.begin(); it != mapWallet.end() && account.vchPubKey.IsValid(); ++it) { for (const CTxOut &txout : (*it).second.tx->vout) { if (txout.scriptPubKey == scriptPubKey) { @@ -966,40 +975,19 @@ void CWallet::MarkDirty() { LOCK(cs_wallet); - for (std::pair &item : mapWallet) { + for (std::pair &item : mapWallet) { item.second.MarkDirty(); } } -bool CWallet::MarkReplaced(const uint256 &originalHash, - const uint256 &newHash) { +void CWallet::MarkDirty(const COutPoint &outpoint) { LOCK(cs_wallet); - - auto mi = mapWallet.find(originalHash); - - // There is a bug if MarkReplaced is not called on an existing wallet - // transaction. - assert(mi != mapWallet.end()); - - CWalletTx &wtx = (*mi).second; - - // Ensure for now that we're not overwriting data. - assert(wtx.mapValue.count("replaced_by_txid") == 0); - - wtx.mapValue["replaced_by_txid"] = newHash.ToString(); - - CWalletDB walletdb(strWalletFile, "r+"); - - bool success = true; - if (!walletdb.WriteTx(wtx)) { - LogPrintf("%s: Updating walletdb tx %s failed", __func__, - wtx.GetId().ToString()); - success = false; + const CWalletTx *pwtx = GetWalletTx(outpoint.unspentid); + if (pwtx) { + // Get non-const + CWalletTx &wtx = mapWallet[pwtx->GetHash()]; + wtx.MarkDirty(); } - - NotifyTransactionChanged(this, originalHash, CT_UPDATED); - - return success; } bool CWallet::AddToWallet(const CWalletTx &wtxIn, bool fFlushOnClose) { @@ -1007,10 +995,10 @@ CWalletDB walletdb(strWalletFile, "r+", fFlushOnClose); - uint256 hash = wtxIn.GetId(); + const txhash_t hash = wtxIn.GetHash(); // Inserts only if not already there, returns tx inserted or tx found. - std::pair::iterator, bool> ret = + std::pair::iterator, bool> ret = mapWallet.insert(std::make_pair(hash, wtxIn)); CWalletTx &wtx = (*ret.first).second; wtx.BindWallet(this); @@ -1066,7 +1054,8 @@ std::max(latestEntry, std::min(blocktime, latestNow)); } else { LogPrintf("AddToWallet(): found %s in block %s not in index\n", - wtxIn.GetId().ToString(), wtxIn.hashBlock.ToString()); + wtxIn.GetHash().ToString(), + wtxIn.hashBlock.ToString()); } } @@ -1099,7 +1088,7 @@ } //// debug print - LogPrintf("AddToWallet %s %s%s\n", wtxIn.GetId().ToString(), + LogPrintf("AddToWallet %s %s%s\n", wtxIn.GetHash().ToString(), (fInsertedNew ? "new" : ""), (fUpdated ? "update" : "")); // Write to disk @@ -1111,14 +1100,15 @@ wtx.MarkDirty(); // Notify UI of new or updated transaction. - NotifyTransactionChanged(this, hash, fInsertedNew ? CT_NEW : CT_UPDATED); + NotifyTransactionChanged(this, wtx.GetHash(), + fInsertedNew ? CT_NEW : CT_UPDATED); // Notify an external script when a wallet transaction comes in or is // updated. std::string strCmd = GetArg("-walletnotify", ""); if (!strCmd.empty()) { - boost::replace_all(strCmd, "%s", wtxIn.GetId().GetHex()); + boost::replace_all(strCmd, "%s", wtxIn.GetHash().GetHex()); // Thread runs free. boost::thread t(runCommand, strCmd); } @@ -1127,19 +1117,17 @@ } bool CWallet::LoadToWallet(const CWalletTx &wtxIn) { - uint256 txid = wtxIn.GetId(); + const txhash_t txhash = wtxIn.GetHash(); - mapWallet[txid] = wtxIn; - CWalletTx &wtx = mapWallet[txid]; + mapWallet[txhash] = wtxIn; + CWalletTx &wtx = mapWallet[txhash]; wtx.BindWallet(this); wtxOrdered.insert(std::make_pair(wtx.nOrderPos, TxPair(&wtx, nullptr))); - AddToSpends(txid); + AddToSpends(txhash); for (const CTxIn &txin : wtx.tx->vin) { - if (mapWallet.count(txin.prevout.hash)) { - CWalletTx &prevtx = mapWallet[txin.prevout.hash]; - if (prevtx.nIndex == -1 && !prevtx.hashUnset()) { - MarkConflicted(prevtx.hashBlock, wtx.GetId()); - } + const CWalletTx *prevtx = GetWalletTx(txin.prevout.unspentid); + if (prevtx && prevtx->nIndex == -1 && !prevtx->hashUnset()) { + MarkConflicted(prevtx->hashBlock, wtx.GetHash()); } } @@ -1169,13 +1157,13 @@ std::pair range = mapTxSpends.equal_range(txin.prevout); while (range.first != range.second) { - if (range.first->second != tx.GetId()) { + if (range.first->second != tx.Getunspentid()) { LogPrintf("Transaction %s (in block %s) conflicts with " "wallet transaction %s (both spend %s:%i)\n", - tx.GetId().ToString(), + tx.GetHash().ToString(), pIndex->GetBlockHash().ToString(), range.first->second.ToString(), - range.first->first.hash.ToString(), + range.first->first.unspentid.ToString(), range.first->first.n); MarkConflicted(pIndex->GetBlockHash(), range.first->second); } @@ -1184,7 +1172,7 @@ } } - bool fExisted = mapWallet.count(tx.GetId()) != 0; + bool fExisted = mapWallet.count(tx.GetHash()) != 0; if (fExisted && !fUpdate) { return false; } @@ -1203,29 +1191,32 @@ return false; } -bool CWallet::AbandonTransaction(const uint256 &hashTx) { +bool CWallet::AbandonTransaction(const txhash_t &hashTx) { LOCK2(cs_main, cs_wallet); CWalletDB walletdb(strWalletFile, "r+"); - std::set todo; - std::set done; + std::set todo; + std::set done; // Can't mark abandoned if confirmed or in mempool. - assert(mapWallet.count(hashTx)); - CWalletTx &origtx = mapWallet[hashTx]; - if (origtx.GetDepthInMainChain() > 0 || origtx.InMempool()) { + const CWalletTx *origtx = GetWalletTx(hashTx); + const unspentid_t origunspentid = origtx->tx->Getunspentid(); + assert(origtx); + if (origtx->GetDepthInMainChain() > 0 || origtx->InMempool()) { return false; } todo.insert(hashTx); while (!todo.empty()) { - uint256 now = *todo.begin(); + txhash_t now = *todo.begin(); todo.erase(now); done.insert(now); assert(mapWallet.count(now)); CWalletTx &wtx = mapWallet[now]; + unspentid_t unspentid = wtx.tx->Getunspentid(); + int currentconfirm = wtx.GetDepthInMainChain(); // If the orig tx was not in block, none of its spends can be. assert(currentconfirm <= 0); @@ -1239,12 +1230,13 @@ wtx.setAbandoned(); wtx.MarkDirty(); walletdb.WriteTx(wtx); - NotifyTransactionChanged(this, wtx.GetId(), CT_UPDATED); + NotifyTransactionChanged(this, now, CT_UPDATED); // Iterate over all its outputs, and mark transactions in the wallet // that spend them abandoned too. TxSpends::const_iterator iter = - mapTxSpends.lower_bound(COutPoint(hashTx, 0)); - while (iter != mapTxSpends.end() && iter->first.hash == now) { + mapTxSpends.lower_bound(COutPoint(origunspentid, 0)); + while (iter != mapTxSpends.end() && + iter->first.unspentid == unspentid) { if (!done.count(iter->second)) { todo.insert(iter->second); } @@ -1255,8 +1247,7 @@ // balance available of the outputs it spends. So force those to be // recomputed. for (const CTxIn &txin : wtx.tx->vin) { - if (mapWallet.count(txin.prevout.hash)) - mapWallet[txin.prevout.hash].MarkDirty(); + MarkDirty(txin.prevout); } } } @@ -1264,7 +1255,7 @@ return true; } -void CWallet::MarkConflicted(const uint256 &hashBlock, const uint256 &hashTx) { +void CWallet::MarkConflicted(const uint256 &hashBlock, const txhash_t &hashTx) { LOCK2(cs_main, cs_wallet); int conflictconfirms = 0; @@ -1285,13 +1276,13 @@ // Do not flush the wallet here for performance reasons CWalletDB walletdb(strWalletFile, "r+", false); - std::set todo; - std::set done; + std::set todo; + std::set done; todo.insert(hashTx); while (!todo.empty()) { - uint256 now = *todo.begin(); + txhash_t now = *todo.begin(); todo.erase(now); done.insert(now); assert(mapWallet.count(now)); @@ -1304,11 +1295,13 @@ wtx.hashBlock = hashBlock; wtx.MarkDirty(); walletdb.WriteTx(wtx); + unspentid_t unspentid = wtx.tx->Getunspentid(); // Iterate over all its outputs, and mark transactions in the wallet // that spend them conflicted too. TxSpends::const_iterator iter = - mapTxSpends.lower_bound(COutPoint(now, 0)); - while (iter != mapTxSpends.end() && iter->first.hash == now) { + mapTxSpends.lower_bound(COutPoint(unspentid, 0)); + while (iter != mapTxSpends.end() && + iter->first.unspentid == unspentid) { if (!done.count(iter->second)) { todo.insert(iter->second); } @@ -1319,9 +1312,7 @@ // balance available of the outputs it spends. So force those to be // recomputed. for (const CTxIn &txin : wtx.tx->vin) { - if (mapWallet.count(txin.prevout.hash)) { - mapWallet[txin.prevout.hash].MarkDirty(); - } + MarkDirty(txin.prevout); } } } @@ -1340,19 +1331,16 @@ // available of the outputs it spends. So force those to be recomputed, // also: for (const CTxIn &txin : tx.vin) { - if (mapWallet.count(txin.prevout.hash)) - mapWallet[txin.prevout.hash].MarkDirty(); + MarkDirty(txin.prevout); } } isminetype CWallet::IsMine(const CTxIn &txin) const { LOCK(cs_wallet); - std::map::const_iterator mi = - mapWallet.find(txin.prevout.hash); - if (mi != mapWallet.end()) { - const CWalletTx &prev = (*mi).second; - if (txin.prevout.n < prev.tx->vout.size()) { - return IsMine(prev.tx->vout[txin.prevout.n]); + const CWalletTx *wtx = GetWalletTx(txin.prevout.unspentid); + if (wtx) { + if (txin.prevout.n < wtx->tx->vout.size()) { + return IsMine(wtx->tx->vout[txin.prevout.n]); } } @@ -1363,13 +1351,11 @@ // not-"is mine" (according to the filter) input. CAmount CWallet::GetDebit(const CTxIn &txin, const isminefilter &filter) const { LOCK(cs_wallet); - std::map::const_iterator mi = - mapWallet.find(txin.prevout.hash); - if (mi != mapWallet.end()) { - const CWalletTx &prev = (*mi).second; - if (txin.prevout.n < prev.tx->vout.size()) { - if (IsMine(prev.tx->vout[txin.prevout.n]) & filter) { - return prev.tx->vout[txin.prevout.n].nValue.GetSatoshis(); + const CWalletTx *wtx = GetWalletTx(txin.prevout.unspentid); + if (wtx) { + if (txin.prevout.n < wtx->tx->vout.size()) { + if (IsMine(wtx->tx->vout[txin.prevout.n]) & filter) { + return wtx->tx->vout[txin.prevout.n].nValue.GetSatoshis(); } } } @@ -1457,20 +1443,19 @@ LOCK(cs_wallet); for (const CTxIn &txin : tx.vin) { - auto mi = mapWallet.find(txin.prevout.hash); - if (mi == mapWallet.end()) { + + const CWalletTx *prev = GetWalletTx(txin.prevout.unspentid); + if (!prev) { // Any unknown inputs can't be from us. return false; } - const CWalletTx &prev = (*mi).second; - - if (txin.prevout.n >= prev.tx->vout.size()) { + if (txin.prevout.n >= prev->tx->vout.size()) { // Invalid input! return false; } - if (!(IsMine(prev.tx->vout[txin.prevout.n]) & filter)) { + if (!(IsMine(prev->tx->vout[txin.prevout.n]) & filter)) { return false; } } @@ -1587,7 +1572,7 @@ } else { // Did anyone request this transaction? std::map::const_iterator mi = - pwallet->mapRequestCount.find(GetId()); + pwallet->mapRequestCount.find(GetHash()); if (mi != pwallet->mapRequestCount.end()) { nRequests = (*mi).second; @@ -1647,8 +1632,8 @@ if (!ExtractDestination(txout.scriptPubKey, address) && !txout.scriptPubKey.IsUnspendable()) { LogPrintf("CWalletTx::GetAmounts: Unknown transaction type found, " - "txid %s\n", - this->GetId().ToString()); + "txhash %s\n", + this->GetHash().ToString()); address = CNoDestination(); } @@ -1787,10 +1772,10 @@ // Sort pending wallet transactions based on their initial wallet insertion // order. - for (std::pair &item : mapWallet) { - const uint256 &wtxid = item.first; + for (std::pair &item : mapWallet) { + const uint256 &wtxhash = item.first; CWalletTx &wtx = item.second; - assert(wtx.GetId() == wtxid); + assert(wtx.GetHash() == wtxhash); int nDepth = wtx.GetDepthInMainChain(); @@ -1818,9 +1803,9 @@ CValidationState state; // GetDepthInMainChain already catches known conflicts. if (InMempool() || AcceptToMemoryPool(maxTxFee, state)) { - LogPrintf("Relaying wtx %s\n", GetId().ToString()); + LogPrintf("Relaying wtx %s\n", GetHash().ToString()); if (connman) { - CInv inv(MSG_TX, GetId()); + CInv inv(MSG_TX, GetHash()); connman->ForEachNode( [&inv](CNode *pnode) { pnode->PushInventory(inv); }); return true; @@ -1830,10 +1815,10 @@ return false; } -std::set CWalletTx::GetConflicts() const { - std::set result; +std::set CWalletTx::GetConflicts() const { + std::set result; if (pwallet != nullptr) { - uint256 myHash = GetId(); + txhash_t myHash = tx->GetHash(); result = pwallet->GetConflicts(myHash); result.erase(myHash); } @@ -1927,9 +1912,9 @@ } CAmount nCredit = 0; - uint256 hashTx = GetId(); + unspentid_t unspentid = tx->Getunspentid(); for (unsigned int i = 0; i < tx->vout.size(); i++) { - if (!pwallet->IsSpent(hashTx, i)) { + if (!pwallet->IsSpent(COutPoint(unspentid, i))) { const CTxOut &txout = tx->vout[i]; nCredit += pwallet->GetCredit(txout, ISMINE_SPENDABLE); if (!MoneyRange(nCredit)) { @@ -1975,8 +1960,9 @@ } CAmount nCredit = 0; + unspentid_t unspentid = tx->Getunspentid(); for (unsigned int i = 0; i < tx->vout.size(); i++) { - if (!pwallet->IsSpent(GetId(), i)) { + if (!pwallet->IsSpent(COutPoint(unspentid, i))) { const CTxOut &txout = tx->vout[i]; nCredit += pwallet->GetCredit(txout, ISMINE_WATCH_ONLY); if (!MoneyRange(nCredit)) { @@ -2003,7 +1989,7 @@ bool CWalletTx::InMempool() const { LOCK(mempool.cs); - if (mempool.exists(GetId())) { + if (mempool.exists(GetHash())) { return true; } @@ -2039,7 +2025,7 @@ // Trusted if all inputs are from us and are in the mempool: for (const CTxIn &txin : tx->vin) { // Transactions not sent by us: not trusted - const CWalletTx *parent = pwallet->GetWalletTx(txin.prevout.hash); + const CWalletTx *parent = pwallet->GetWalletTx(txin.prevout.unspentid); if (parent == nullptr) { return false; } @@ -2067,14 +2053,14 @@ return CTransaction(tx1) == CTransaction(tx2); } -std::vector +std::vector CWallet::ResendWalletTransactionsBefore(int64_t nTime, CConnman *connman) { - std::vector result; + std::vector result; LOCK(cs_wallet); // Sort them in chronological order std::multimap mapSorted; - for (std::pair &item : mapWallet) { + for (std::pair &item : mapWallet) { CWalletTx &wtx = item.second; // Don't rebroadcast if newer than nTime: if (wtx.nTimeReceived > nTime) { @@ -2087,7 +2073,7 @@ for (std::pair &item : mapSorted) { CWalletTx &wtx = *item.second; if (wtx.RelayWalletTransaction(connman)) { - result.push_back(wtx.GetId()); + result.push_back(wtx.GetHash()); } } @@ -2117,7 +2103,7 @@ // Rebroadcast unconfirmed txes older than 5 minutes before the last block // was found: - std::vector relayed = + std::vector relayed = ResendWalletTransactionsBefore(nBestBlockTime - 5 * 60, connman); if (!relayed.empty()) { LogPrintf("%s: rebroadcast %u unconfirmed transactions\n", __func__, @@ -2136,7 +2122,7 @@ LOCK2(cs_main, cs_wallet); CAmount nTotal = 0; - for (std::map::const_iterator it = mapWallet.begin(); + for (std::map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx *pcoin = &(*it).second; if (pcoin->IsTrusted()) { @@ -2151,7 +2137,7 @@ LOCK2(cs_main, cs_wallet); CAmount nTotal = 0; - for (std::map::const_iterator it = mapWallet.begin(); + for (std::map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx *pcoin = &(*it).second; if (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0 && @@ -2167,7 +2153,7 @@ LOCK2(cs_main, cs_wallet); CAmount nTotal = 0; - for (std::map::const_iterator it = mapWallet.begin(); + for (std::map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx *pcoin = &(*it).second; nTotal += pcoin->GetImmatureCredit(); @@ -2180,7 +2166,7 @@ LOCK2(cs_main, cs_wallet); CAmount nTotal = 0; - for (std::map::const_iterator it = mapWallet.begin(); + for (std::map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx *pcoin = &(*it).second; if (pcoin->IsTrusted()) { @@ -2195,7 +2181,7 @@ LOCK2(cs_main, cs_wallet); CAmount nTotal = 0; - for (std::map::const_iterator it = mapWallet.begin(); + for (std::map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx *pcoin = &(*it).second; if (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0 && @@ -2211,7 +2197,7 @@ LOCK2(cs_main, cs_wallet); CAmount nTotal = 0; - for (std::map::const_iterator it = mapWallet.begin(); + for (std::map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx *pcoin = &(*it).second; nTotal += pcoin->GetImmatureWatchOnlyCredit(); @@ -2226,10 +2212,11 @@ vCoins.clear(); LOCK2(cs_main, cs_wallet); - for (std::map::const_iterator it = mapWallet.begin(); + for (std::map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { - const uint256 &wtxid = it->first; + const CWalletTx *pcoin = &(*it).second; + const unspentid_t &unspentid = pcoin->tx->Getunspentid(); if (!CheckFinalTx(*pcoin)) { continue; @@ -2257,7 +2244,7 @@ // Bitcoin-ABC: Removed check that prevents consideration of coins from // transactions that are replacing other transactions. This check based - // on pcoin->mapValue.count("replaces_txid") which was not being set + // on pcoin->mapValue.count("replaces_txhash") which was not being set // anywhere. // Similarly, we should not consider coins from transactions that have @@ -2269,21 +2256,21 @@ // D could all be accepted (instead of just B and D, or just A and A' // like the user would want). - // Bitcoin-ABC: retained this check as 'replaced_by_txid' is still set + // Bitcoin-ABC: retained this check as 'replaced_by_txhash' is still set // in the wallet code. if (nDepth == 0 && fOnlyConfirmed && - pcoin->mapValue.count("replaced_by_txid")) { + pcoin->mapValue.count("replaced_by_txhash")) { continue; } for (unsigned int i = 0; i < pcoin->tx->vout.size(); i++) { isminetype mine = IsMine(pcoin->tx->vout[i]); - if (!(IsSpent(wtxid, i)) && mine != ISMINE_NO && - !IsLockedCoin((*it).first, i) && + if (!(IsSpent(COutPoint(unspentid, i))) && mine != ISMINE_NO && + !IsLockedCoin(COutPoint(unspentid, i)) && (pcoin->tx->vout[i].nValue > 0 || fIncludeZeroValue) && (!coinControl || !coinControl->HasSelected() || coinControl->fAllowOtherInputs || - coinControl->IsSelected(COutPoint((*it).first, i)))) { + coinControl->IsSelected(COutPoint(unspentid, i)))) { vCoins.push_back(COutput( pcoin, i, nDepth, ((mine & ISMINE_SPENDABLE) != ISMINE_NO) || @@ -2369,7 +2356,7 @@ continue; } - if (!mempool.TransactionWithinChainLimit(pcoin->GetId(), + if (!mempool.TransactionWithinChainLimit(pcoin->GetHash(), nMaxAncestors)) { continue; } @@ -2484,14 +2471,13 @@ } for (const COutPoint &outpoint : vPresetInputs) { - std::map::const_iterator it = - mapWallet.find(outpoint.hash); - if (it == mapWallet.end()) { + + const CWalletTx *pcoin = GetWalletTx(outpoint.unspentid); + if (!pcoin) { // TODO: Allow non-wallet inputs return false; } - const CWalletTx *pcoin = &it->second; // Clearly invalid input, fail. if (pcoin->tx->vout.size() <= outpoint.n) { return false; @@ -2859,9 +2845,9 @@ // Note how the sequence number is set to non-maxint so that the // nLockTime set above actually works. for (const auto &coin : setCoins) { - txNew.vin.push_back( - CTxIn(coin.first->GetId(), coin.second, CScript(), - std::numeric_limits::max() - 1)); + txNew.vin.push_back(CTxIn( + coin.first->tx->Getunspentid(), coin.second, CScript(), + std::numeric_limits::max() - 1)); } // Fill in dummy signatures for fee calculation. @@ -3043,13 +3029,15 @@ // Notify that old coins are spent. for (const CTxIn &txin : wtxNew.tx->vin) { - CWalletTx &coin = mapWallet[txin.prevout.hash]; + const CWalletTx *prev = GetWalletTx(txin.prevout.unspentid); + assert(prev); + CWalletTx &coin = mapWallet[prev->GetHash()]; coin.BindWallet(this); - NotifyTransactionChanged(this, coin.GetId(), CT_UPDATED); + NotifyTransactionChanged(this, coin.GetHash(), CT_UPDATED); } // Track how many getdata requests our transaction gets. - mapRequestCount[wtxNew.GetId()] = 0; + mapRequestCount[wtxNew.GetHash()] = 0; if (fBroadcastTransactions) { // Broadcast @@ -3161,8 +3149,8 @@ return DB_LOAD_OK; } -DBErrors CWallet::ZapSelectTx(std::vector &vHashIn, - std::vector &vHashOut) { +DBErrors CWallet::ZapSelectTx(std::vector &vHashIn, + std::vector &vHashOut) { if (!fFileBacked) { return DB_LOAD_OK; } @@ -3445,9 +3433,9 @@ std::map balances; LOCK(cs_wallet); - for (std::pair walletEntry : mapWallet) { + for (std::pair walletEntry : mapWallet) { CWalletTx *pcoin = &walletEntry.second; - + const unspentid_t &unspentid = pcoin->tx->Getunspentid(); if (!pcoin->IsTrusted()) { continue; } @@ -3471,8 +3459,9 @@ continue; } - Amount n = - IsSpent(walletEntry.first, i) ? 0 : pcoin->tx->vout[i].nValue; + Amount n = IsSpent(COutPoint(unspentid, i)) + ? 0 + : pcoin->tx->vout[i].nValue; if (!balances.count(addr)) balances[addr] = 0; balances[addr] += n.GetSatoshis(); @@ -3501,10 +3490,10 @@ continue; } - if (!ExtractDestination(mapWallet[txin.prevout.hash] - .tx->vout[txin.prevout.n] - .scriptPubKey, - address)) { + const CWalletTx *wtx = GetWalletTx(txin.prevout.unspentid); + assert(wtx); + if (!ExtractDestination( + wtx->tx->vout[txin.prevout.n].scriptPubKey, address)) { continue; } @@ -3598,7 +3587,7 @@ CAmount nBalance = 0; // Tally wallet transactions. - for (std::map::iterator it = mapWallet.begin(); + for (std::map::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx &wtx = (*it).second; if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || @@ -3695,11 +3684,11 @@ } } -void CWallet::UpdatedTransaction(const uint256 &hashTx) { +void CWallet::UpdatedTransaction(const txhash_t &hashTx) { LOCK(cs_wallet); // Only notify UI if this transaction is in this wallet. - std::map::const_iterator mi = mapWallet.find(hashTx); - if (mi != mapWallet.end()) { + const CWalletTx *wtx = GetWalletTx(hashTx); + if (wtx) { NotifyTransactionChanged(this, hashTx, CT_UPDATED); } } @@ -3733,12 +3722,11 @@ setLockedCoins.clear(); } -bool CWallet::IsLockedCoin(uint256 hash, unsigned int n) const { +bool CWallet::IsLockedCoin(const COutPoint &outpoint) const { // setLockedCoins AssertLockHeld(cs_wallet); - COutPoint outpt(hash, n); - return setLockedCoins.count(outpt) > 0; + return setLockedCoins.count(outpoint) > 0; } void CWallet::ListLockedCoins(std::vector &vOutpts) { @@ -3824,7 +3812,7 @@ // Find first block that affects those keys, if there are any left. std::vector vAffected; - for (std::map::const_iterator it = mapWallet.begin(); + for (std::map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); it++) { // Iterate over all wallet transactions... const CWalletTx &wtx = (*it).second; @@ -3977,7 +3965,7 @@ strprintf(_("(default: %u)"), DEFAULT_WALLETBROADCAST)); strUsage += HelpMessageOpt("-walletnotify=", _("Execute command when a wallet transaction " - "changes (%s in cmd is replaced by TxID)")); + "changes (%s in cmd is replaced by txhash)")); strUsage += HelpMessageOpt( "-zapwallettxes=", _("Delete all wallet transactions and only recover those parts of the " @@ -4179,9 +4167,9 @@ CWalletDB walletdb(walletFile); for (const CWalletTx &wtxOld : vWtx) { - uint256 txid = wtxOld.GetId(); - std::map::iterator mi = - walletInstance->mapWallet.find(txid); + txhash_t txhash = wtxOld.GetHash(); + std::map::iterator mi = + walletInstance->mapWallet.find(txhash); if (mi != walletInstance->mapWallet.end()) { const CWalletTx *copyFrom = &wtxOld; CWalletTx *copyTo = &mi->second; diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -167,11 +167,11 @@ std::list &acentries); DBErrors LoadWallet(CWallet *pwallet); - DBErrors FindWalletTx(CWallet *pwallet, std::vector &vTxHash, + DBErrors FindWalletTx(CWallet *pwallet, std::vector &vTxHash, std::vector &vWtx); DBErrors ZapWalletTx(CWallet *pwallet, std::vector &vWtx); - DBErrors ZapSelectTx(CWallet *pwallet, std::vector &vHashIn, - std::vector &vHashOut); + DBErrors ZapSelectTx(CWallet *pwallet, std::vector &vHashIn, + std::vector &vHashOut); static bool Recover(CDBEnv &dbenv, const std::string &filename, bool fOnlyKeys); static bool Recover(CDBEnv &dbenv, const std::string &filename); diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -57,7 +57,7 @@ bool CWalletDB::WriteTx(const CWalletTx &wtx) { nWalletDBUpdateCounter++; - return Write(std::make_pair(std::string("tx"), wtx.GetId()), wtx); + return Write(std::make_pair(std::string("tx"), wtx.GetHash()), wtx); } bool CWalletDB::EraseTx(uint256 hash) { @@ -264,7 +264,7 @@ bool fIsEncrypted; bool fAnyUnordered; int nFileVersion; - std::vector vWalletUpgrade; + std::vector vWalletUpgrade; CWalletScanState() { nKeys = nCKeys = nWatchKeys = nKeyMeta = 0; @@ -301,7 +301,7 @@ bool isValid = wtx.IsCoinBase() ? CheckCoinbase(wtx, state) : CheckRegularTransaction(wtx, state); - if (wtx.GetId() != hash || !isValid) return false; + if (wtx.GetHash() != hash || !isValid) return false; // Undo serialize changes in 31600 if (31404 <= wtx.fTimeReceivedIsTxTime && @@ -321,7 +321,7 @@ wtx.fTimeReceivedIsTxTime, hash.ToString()); wtx.fTimeReceivedIsTxTime = 0; } - wss.vWalletUpgrade.push_back(hash); + wss.vWalletUpgrade.push_back(wtx.GetHash()); } if (wtx.nOrderPos == -1) wss.fAnyUnordered = true; @@ -577,7 +577,7 @@ if ((wss.nKeys + wss.nCKeys + wss.nWatchKeys) != wss.nKeyMeta) pwallet->UpdateTimeFirstKey(1); - for (uint256 hash : wss.vWalletUpgrade) { + for (txhash_t hash : wss.vWalletUpgrade) { WriteTx(pwallet->mapWallet[hash]); } @@ -602,7 +602,7 @@ } DBErrors CWalletDB::FindWalletTx(CWallet *pwallet, - std::vector &vTxHash, + std::vector &vTxHash, std::vector &vWtx) { pwallet->vchDefaultKey = CPubKey(); bool fNoncriticalErrors = false; @@ -638,7 +638,7 @@ std::string strType; ssKey >> strType; if (strType == "tx") { - uint256 hash; + txhash_t hash; ssKey >> hash; CWalletTx wtx; @@ -662,10 +662,10 @@ } DBErrors CWalletDB::ZapSelectTx(CWallet *pwallet, - std::vector &vTxHashIn, - std::vector &vTxHashOut) { + std::vector &vTxHashIn, + std::vector &vTxHashOut) { // Build list of wallet TXs and hashes. - std::vector vTxHash; + std::vector vTxHash; std::vector vWtx; DBErrors err = FindWalletTx(pwallet, vTxHash, vWtx); if (err != DB_LOAD_OK) { @@ -677,8 +677,8 @@ // Erase each matching wallet TX. bool delerror = false; - std::vector::iterator it = vTxHashIn.begin(); - for (uint256 hash : vTxHash) { + std::vector::iterator it = vTxHashIn.begin(); + for (txhash_t hash : vTxHash) { while (it < vTxHashIn.end() && (*it) < hash) { it++; } @@ -705,12 +705,12 @@ DBErrors CWalletDB::ZapWalletTx(CWallet *pwallet, std::vector &vWtx) { // Build list of wallet TXs. - std::vector vTxHash; + std::vector vTxHash; DBErrors err = FindWalletTx(pwallet, vTxHash, vWtx); if (err != DB_LOAD_OK) return err; // Erase each wallet TX. - for (uint256 &hash : vTxHash) { + for (txhash_t &hash : vTxHash) { if (!EraseTx(hash)) return DB_CORRUPT; } diff --git a/src/zmq/zmqpublishnotifier.cpp b/src/zmq/zmqpublishnotifier.cpp --- a/src/zmq/zmqpublishnotifier.cpp +++ b/src/zmq/zmqpublishnotifier.cpp @@ -145,11 +145,11 @@ bool CZMQPublishHashTransactionNotifier::NotifyTransaction( const CTransaction &transaction) { - uint256 txid = transaction.GetId(); - LogPrint("zmq", "zmq: Publish hashtx %s\n", txid.GetHex()); + txhash_t txhash = transaction.GetHash(); + LogPrint("zmq", "zmq: Publish hashtx %s\n", txhash.GetHex()); char data[32]; for (unsigned int i = 0; i < 32; i++) - data[31 - i] = txid.begin()[i]; + data[31 - i] = txhash.begin()[i]; return SendMessage(MSG_HASHTX, data, 32); } @@ -175,8 +175,8 @@ bool CZMQPublishRawTransactionNotifier::NotifyTransaction( const CTransaction &transaction) { - uint256 txid = transaction.GetId(); - LogPrint("zmq", "zmq: Publish rawtx %s\n", txid.GetHex()); + txhash_t txhash = transaction.GetHash(); + LogPrint("zmq", "zmq: Publish rawtx %s\n", txhash.GetHex()); CDataStream ss(SER_NETWORK, PROTOCOL_VERSION | RPCSerializationFlags()); ss << transaction; return SendMessage(MSG_RAWTX, &(*ss.begin()), ss.size());