mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-04-29 23:09:44 -04:00
Merge bitcoin/bitcoin#28107: util: Type-safe transaction identifiers
940a49978c
Use type-safe txid types in orphanage (dergoegge)ed70e65016
Introduce types for txids & wtxids (dergoegge)cdb14d79e8
[net processing] Use HasWitness over comparing (w)txids (dergoegge) Pull request description: We currently have two different identifiers for transactions: `txid` (refering to the hash of a transaction without witness data) and `wtxid` (referring to the hash of a transaction including witness data). Both are typed as `uint256` which could lead to type-safety bugs in which one transaction identifier type is passed where the other would be expected. This PR introduces explicit `Txid` and `Wtxid` types that (if used) would cause compilation errors for such type confusion bugs. (Only the orphanage is converted to use these types in this PR) ACKs for top commit: achow101: ACK940a49978c
stickies-v: ACK940a49978c
hebasto: ACK940a49978c
, I have reviewed the code and it looks OK. instagibbs: re-ACK940a49978c
BrandonOdiwuor: re-ACK940a49978c
glozow: reACK940a49978c
Tree-SHA512: 55298d1c2bb82b7a6995e96e554571c22eaf4a89fb2a4d7a236d70e0f625e8cca62ff2490e1c179c47bd93153fe6527b56870198f026f5ee7753d64d7a424c92
This commit is contained in:
commit
5572f98f05
12 changed files with 139 additions and 61 deletions
|
@ -328,6 +328,7 @@ BITCOIN_CORE_H = \
|
||||||
util/time.h \
|
util/time.h \
|
||||||
util/tokenpipe.h \
|
util/tokenpipe.h \
|
||||||
util/trace.h \
|
util/trace.h \
|
||||||
|
util/transaction_identifier.h \
|
||||||
util/translation.h \
|
util/translation.h \
|
||||||
util/types.h \
|
util/types.h \
|
||||||
util/ui_change_type.h \
|
util/ui_change_type.h \
|
||||||
|
|
|
@ -1947,9 +1947,9 @@ void PeerManagerImpl::BlockConnected(
|
||||||
{
|
{
|
||||||
LOCK(m_recent_confirmed_transactions_mutex);
|
LOCK(m_recent_confirmed_transactions_mutex);
|
||||||
for (const auto& ptx : pblock->vtx) {
|
for (const auto& ptx : pblock->vtx) {
|
||||||
m_recent_confirmed_transactions.insert(ptx->GetHash());
|
m_recent_confirmed_transactions.insert(ptx->GetHash().ToUint256());
|
||||||
if (ptx->GetHash() != ptx->GetWitnessHash()) {
|
if (ptx->HasWitness()) {
|
||||||
m_recent_confirmed_transactions.insert(ptx->GetWitnessHash());
|
m_recent_confirmed_transactions.insert(ptx->GetWitnessHash().ToUint256());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3003,8 +3003,8 @@ bool PeerManagerImpl::ProcessOrphanTx(Peer& peer)
|
||||||
while (CTransactionRef porphanTx = m_orphanage.GetTxToReconsider(peer.m_id)) {
|
while (CTransactionRef porphanTx = m_orphanage.GetTxToReconsider(peer.m_id)) {
|
||||||
const MempoolAcceptResult result = m_chainman.ProcessTransaction(porphanTx);
|
const MempoolAcceptResult result = m_chainman.ProcessTransaction(porphanTx);
|
||||||
const TxValidationState& state = result.m_state;
|
const TxValidationState& state = result.m_state;
|
||||||
const uint256& orphanHash = porphanTx->GetHash();
|
const Txid& orphanHash = porphanTx->GetHash();
|
||||||
const uint256& orphan_wtxid = porphanTx->GetWitnessHash();
|
const Wtxid& orphan_wtxid = porphanTx->GetWitnessHash();
|
||||||
|
|
||||||
if (result.m_result_type == MempoolAcceptResult::ResultType::VALID) {
|
if (result.m_result_type == MempoolAcceptResult::ResultType::VALID) {
|
||||||
LogPrint(BCLog::TXPACKAGES, " accepted orphan tx %s (wtxid=%s)\n", orphanHash.ToString(), orphan_wtxid.ToString());
|
LogPrint(BCLog::TXPACKAGES, " accepted orphan tx %s (wtxid=%s)\n", orphanHash.ToString(), orphan_wtxid.ToString());
|
||||||
|
@ -3052,7 +3052,7 @@ bool PeerManagerImpl::ProcessOrphanTx(Peer& peer)
|
||||||
// See also comments in https://github.com/bitcoin/bitcoin/pull/18044#discussion_r443419034
|
// See also comments in https://github.com/bitcoin/bitcoin/pull/18044#discussion_r443419034
|
||||||
// for concerns around weakening security of unupgraded nodes
|
// for concerns around weakening security of unupgraded nodes
|
||||||
// if we start doing this too early.
|
// if we start doing this too early.
|
||||||
m_recent_rejects.insert(porphanTx->GetWitnessHash());
|
m_recent_rejects.insert(porphanTx->GetWitnessHash().ToUint256());
|
||||||
// If the transaction failed for TX_INPUTS_NOT_STANDARD,
|
// If the transaction failed for TX_INPUTS_NOT_STANDARD,
|
||||||
// then we know that the witness was irrelevant to the policy
|
// then we know that the witness was irrelevant to the policy
|
||||||
// failure, since this check depends only on the txid
|
// failure, since this check depends only on the txid
|
||||||
|
@ -3061,10 +3061,10 @@ bool PeerManagerImpl::ProcessOrphanTx(Peer& peer)
|
||||||
// processing of this transaction in the event that child
|
// processing of this transaction in the event that child
|
||||||
// transactions are later received (resulting in
|
// transactions are later received (resulting in
|
||||||
// parent-fetching by txid via the orphan-handling logic).
|
// parent-fetching by txid via the orphan-handling logic).
|
||||||
if (state.GetResult() == TxValidationResult::TX_INPUTS_NOT_STANDARD && porphanTx->GetWitnessHash() != porphanTx->GetHash()) {
|
if (state.GetResult() == TxValidationResult::TX_INPUTS_NOT_STANDARD && porphanTx->HasWitness()) {
|
||||||
// We only add the txid if it differs from the wtxid, to
|
// We only add the txid if it differs from the wtxid, to
|
||||||
// avoid wasting entries in the rolling bloom filter.
|
// avoid wasting entries in the rolling bloom filter.
|
||||||
m_recent_rejects.insert(porphanTx->GetHash());
|
m_recent_rejects.insert(porphanTx->GetHash().ToUint256());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_orphanage.EraseTx(orphanHash);
|
m_orphanage.EraseTx(orphanHash);
|
||||||
|
@ -4319,8 +4319,8 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
|
||||||
// regardless of what witness is provided, we will not accept
|
// regardless of what witness is provided, we will not accept
|
||||||
// this, so we don't need to allow for redownload of this txid
|
// this, so we don't need to allow for redownload of this txid
|
||||||
// from any of our non-wtxidrelay peers.
|
// from any of our non-wtxidrelay peers.
|
||||||
m_recent_rejects.insert(tx.GetHash());
|
m_recent_rejects.insert(tx.GetHash().ToUint256());
|
||||||
m_recent_rejects.insert(tx.GetWitnessHash());
|
m_recent_rejects.insert(tx.GetWitnessHash().ToUint256());
|
||||||
m_txrequest.ForgetTxHash(tx.GetHash());
|
m_txrequest.ForgetTxHash(tx.GetHash());
|
||||||
m_txrequest.ForgetTxHash(tx.GetWitnessHash());
|
m_txrequest.ForgetTxHash(tx.GetWitnessHash());
|
||||||
}
|
}
|
||||||
|
@ -4339,7 +4339,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
|
||||||
// See also comments in https://github.com/bitcoin/bitcoin/pull/18044#discussion_r443419034
|
// See also comments in https://github.com/bitcoin/bitcoin/pull/18044#discussion_r443419034
|
||||||
// for concerns around weakening security of unupgraded nodes
|
// for concerns around weakening security of unupgraded nodes
|
||||||
// if we start doing this too early.
|
// if we start doing this too early.
|
||||||
m_recent_rejects.insert(tx.GetWitnessHash());
|
m_recent_rejects.insert(tx.GetWitnessHash().ToUint256());
|
||||||
m_txrequest.ForgetTxHash(tx.GetWitnessHash());
|
m_txrequest.ForgetTxHash(tx.GetWitnessHash());
|
||||||
// If the transaction failed for TX_INPUTS_NOT_STANDARD,
|
// If the transaction failed for TX_INPUTS_NOT_STANDARD,
|
||||||
// then we know that the witness was irrelevant to the policy
|
// then we know that the witness was irrelevant to the policy
|
||||||
|
@ -4349,8 +4349,8 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
|
||||||
// processing of this transaction in the event that child
|
// processing of this transaction in the event that child
|
||||||
// transactions are later received (resulting in
|
// transactions are later received (resulting in
|
||||||
// parent-fetching by txid via the orphan-handling logic).
|
// parent-fetching by txid via the orphan-handling logic).
|
||||||
if (state.GetResult() == TxValidationResult::TX_INPUTS_NOT_STANDARD && tx.GetWitnessHash() != tx.GetHash()) {
|
if (state.GetResult() == TxValidationResult::TX_INPUTS_NOT_STANDARD && tx.HasWitness()) {
|
||||||
m_recent_rejects.insert(tx.GetHash());
|
m_recent_rejects.insert(tx.GetHash().ToUint256());
|
||||||
m_txrequest.ForgetTxHash(tx.GetHash());
|
m_txrequest.ForgetTxHash(tx.GetHash());
|
||||||
}
|
}
|
||||||
if (RecursiveDynamicUsage(*ptx) < 100000) {
|
if (RecursiveDynamicUsage(*ptx) < 100000) {
|
||||||
|
@ -5780,9 +5780,14 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
|
||||||
LOCK(tx_relay->m_bloom_filter_mutex);
|
LOCK(tx_relay->m_bloom_filter_mutex);
|
||||||
|
|
||||||
for (const auto& txinfo : vtxinfo) {
|
for (const auto& txinfo : vtxinfo) {
|
||||||
const uint256& hash = peer->m_wtxid_relay ? txinfo.tx->GetWitnessHash() : txinfo.tx->GetHash();
|
CInv inv{
|
||||||
CInv inv(peer->m_wtxid_relay ? MSG_WTX : MSG_TX, hash);
|
peer->m_wtxid_relay ? MSG_WTX : MSG_TX,
|
||||||
tx_relay->m_tx_inventory_to_send.erase(hash);
|
peer->m_wtxid_relay ?
|
||||||
|
txinfo.tx->GetWitnessHash().ToUint256() :
|
||||||
|
txinfo.tx->GetHash().ToUint256(),
|
||||||
|
};
|
||||||
|
tx_relay->m_tx_inventory_to_send.erase(inv.hash);
|
||||||
|
|
||||||
// Don't send transactions that peers will not put into their mempool
|
// Don't send transactions that peers will not put into their mempool
|
||||||
if (txinfo.fee < filterrate.GetFee(txinfo.vsize)) {
|
if (txinfo.fee < filterrate.GetFee(txinfo.vsize)) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -5790,7 +5795,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
|
||||||
if (tx_relay->m_bloom_filter) {
|
if (tx_relay->m_bloom_filter) {
|
||||||
if (!tx_relay->m_bloom_filter->IsRelevantAndUpdate(*txinfo.tx)) continue;
|
if (!tx_relay->m_bloom_filter->IsRelevantAndUpdate(*txinfo.tx)) continue;
|
||||||
}
|
}
|
||||||
tx_relay->m_tx_inventory_known_filter.insert(hash);
|
tx_relay->m_tx_inventory_known_filter.insert(inv.hash);
|
||||||
vInv.push_back(inv);
|
vInv.push_back(inv);
|
||||||
if (vInv.size() == MAX_INV_SZ) {
|
if (vInv.size() == MAX_INV_SZ) {
|
||||||
m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv));
|
m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv));
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include <tinyformat.h>
|
#include <tinyformat.h>
|
||||||
#include <uint256.h>
|
#include <uint256.h>
|
||||||
#include <util/strencodings.h>
|
#include <util/strencodings.h>
|
||||||
|
#include <util/transaction_identifier.h>
|
||||||
#include <version.h>
|
#include <version.h>
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
@ -65,22 +66,23 @@ std::string CTxOut::ToString() const
|
||||||
CMutableTransaction::CMutableTransaction() : nVersion(CTransaction::CURRENT_VERSION), nLockTime(0) {}
|
CMutableTransaction::CMutableTransaction() : nVersion(CTransaction::CURRENT_VERSION), nLockTime(0) {}
|
||||||
CMutableTransaction::CMutableTransaction(const CTransaction& tx) : vin(tx.vin), vout(tx.vout), nVersion(tx.nVersion), nLockTime(tx.nLockTime) {}
|
CMutableTransaction::CMutableTransaction(const CTransaction& tx) : vin(tx.vin), vout(tx.vout), nVersion(tx.nVersion), nLockTime(tx.nLockTime) {}
|
||||||
|
|
||||||
uint256 CMutableTransaction::GetHash() const
|
Txid CMutableTransaction::GetHash() const
|
||||||
{
|
{
|
||||||
return (CHashWriter{SERIALIZE_TRANSACTION_NO_WITNESS} << *this).GetHash();
|
return Txid::FromUint256((CHashWriter{SERIALIZE_TRANSACTION_NO_WITNESS} << *this).GetHash());
|
||||||
}
|
}
|
||||||
|
|
||||||
uint256 CTransaction::ComputeHash() const
|
Txid CTransaction::ComputeHash() const
|
||||||
{
|
{
|
||||||
return (CHashWriter{SERIALIZE_TRANSACTION_NO_WITNESS} << *this).GetHash();
|
return Txid::FromUint256((CHashWriter{SERIALIZE_TRANSACTION_NO_WITNESS} << *this).GetHash());
|
||||||
}
|
}
|
||||||
|
|
||||||
uint256 CTransaction::ComputeWitnessHash() const
|
Wtxid CTransaction::ComputeWitnessHash() const
|
||||||
{
|
{
|
||||||
if (!HasWitness()) {
|
if (!HasWitness()) {
|
||||||
return hash;
|
return Wtxid::FromUint256(hash.ToUint256());
|
||||||
}
|
}
|
||||||
return (CHashWriter{0} << *this).GetHash();
|
|
||||||
|
return Wtxid::FromUint256((CHashWriter{0} << *this).GetHash());
|
||||||
}
|
}
|
||||||
|
|
||||||
CTransaction::CTransaction(const CMutableTransaction& tx) : vin(tx.vin), vout(tx.vout), nVersion(tx.nVersion), nLockTime(tx.nLockTime), hash{ComputeHash()}, m_witness_hash{ComputeWitnessHash()} {}
|
CTransaction::CTransaction(const CMutableTransaction& tx) : vin(tx.vin), vout(tx.vout), nVersion(tx.nVersion), nLockTime(tx.nLockTime), hash{ComputeHash()}, m_witness_hash{ComputeWitnessHash()} {}
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <script/script.h>
|
#include <script/script.h>
|
||||||
#include <serialize.h>
|
#include <serialize.h>
|
||||||
#include <uint256.h>
|
#include <uint256.h>
|
||||||
|
#include <util/transaction_identifier.h> // IWYU pragma: export
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
@ -309,11 +310,11 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/** Memory only. */
|
/** Memory only. */
|
||||||
const uint256 hash;
|
const Txid hash;
|
||||||
const uint256 m_witness_hash;
|
const Wtxid m_witness_hash;
|
||||||
|
|
||||||
uint256 ComputeHash() const;
|
Txid ComputeHash() const;
|
||||||
uint256 ComputeWitnessHash() const;
|
Wtxid ComputeWitnessHash() const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/** Convert a CMutableTransaction into a CTransaction. */
|
/** Convert a CMutableTransaction into a CTransaction. */
|
||||||
|
@ -334,8 +335,8 @@ public:
|
||||||
return vin.empty() && vout.empty();
|
return vin.empty() && vout.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint256& GetHash() const { return hash; }
|
const Txid& GetHash() const { return hash; }
|
||||||
const uint256& GetWitnessHash() const { return m_witness_hash; };
|
const Wtxid& GetWitnessHash() const { return m_witness_hash; };
|
||||||
|
|
||||||
// Return sum of txouts.
|
// Return sum of txouts.
|
||||||
CAmount GetValueOut() const;
|
CAmount GetValueOut() const;
|
||||||
|
@ -405,7 +406,7 @@ struct CMutableTransaction
|
||||||
/** Compute the hash of this CMutableTransaction. This is computed on the
|
/** Compute the hash of this CMutableTransaction. This is computed on the
|
||||||
* fly, as opposed to GetHash() in CTransaction, which uses a cached result.
|
* fly, as opposed to GetHash() in CTransaction, which uses a cached result.
|
||||||
*/
|
*/
|
||||||
uint256 GetHash() const;
|
Txid GetHash() const;
|
||||||
|
|
||||||
bool HasWitness() const
|
bool HasWitness() const
|
||||||
{
|
{
|
||||||
|
|
|
@ -238,7 +238,7 @@ FUZZ_TARGET(tx_package_eval, .init = initialize_tx_pool)
|
||||||
}
|
}
|
||||||
if (fuzzed_data_provider.ConsumeBool()) {
|
if (fuzzed_data_provider.ConsumeBool()) {
|
||||||
const auto& txid = fuzzed_data_provider.ConsumeBool() ?
|
const auto& txid = fuzzed_data_provider.ConsumeBool() ?
|
||||||
txs.back()->GetHash() :
|
txs.back()->GetHash().ToUint256() :
|
||||||
PickValue(fuzzed_data_provider, mempool_outpoints).hash;
|
PickValue(fuzzed_data_provider, mempool_outpoints).hash;
|
||||||
const auto delta = fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(-50 * COIN, +50 * COIN);
|
const auto delta = fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(-50 * COIN, +50 * COIN);
|
||||||
tx_pool.PrioritiseTransaction(txid, delta);
|
tx_pool.PrioritiseTransaction(txid, delta);
|
||||||
|
|
|
@ -227,7 +227,7 @@ FUZZ_TARGET(tx_pool_standard, .init = initialize_tx_pool)
|
||||||
}
|
}
|
||||||
if (fuzzed_data_provider.ConsumeBool()) {
|
if (fuzzed_data_provider.ConsumeBool()) {
|
||||||
const auto& txid = fuzzed_data_provider.ConsumeBool() ?
|
const auto& txid = fuzzed_data_provider.ConsumeBool() ?
|
||||||
tx->GetHash() :
|
tx->GetHash().ToUint256() :
|
||||||
PickValue(fuzzed_data_provider, outpoints_rbf).hash;
|
PickValue(fuzzed_data_provider, outpoints_rbf).hash;
|
||||||
const auto delta = fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(-50 * COIN, +50 * COIN);
|
const auto delta = fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(-50 * COIN, +50 * COIN);
|
||||||
tx_pool.PrioritiseTransaction(txid, delta);
|
tx_pool.PrioritiseTransaction(txid, delta);
|
||||||
|
@ -344,7 +344,7 @@ FUZZ_TARGET(tx_pool, .init = initialize_tx_pool)
|
||||||
}
|
}
|
||||||
if (fuzzed_data_provider.ConsumeBool()) {
|
if (fuzzed_data_provider.ConsumeBool()) {
|
||||||
const auto& txid = fuzzed_data_provider.ConsumeBool() ?
|
const auto& txid = fuzzed_data_provider.ConsumeBool() ?
|
||||||
mut_tx.GetHash() :
|
mut_tx.GetHash().ToUint256() :
|
||||||
PickValue(fuzzed_data_provider, txids);
|
PickValue(fuzzed_data_provider, txids);
|
||||||
const auto delta = fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(-50 * COIN, +50 * COIN);
|
const auto delta = fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(-50 * COIN, +50 * COIN);
|
||||||
tx_pool.PrioritiseTransaction(txid, delta);
|
tx_pool.PrioritiseTransaction(txid, delta);
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
#include <arith_uint256.h>
|
#include <arith_uint256.h>
|
||||||
|
#include <primitives/transaction.h>
|
||||||
#include <pubkey.h>
|
#include <pubkey.h>
|
||||||
#include <script/sign.h>
|
#include <script/sign.h>
|
||||||
#include <script/signingprovider.h>
|
#include <script/signingprovider.h>
|
||||||
|
@ -29,8 +30,8 @@ public:
|
||||||
CTransactionRef RandomOrphan() EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
|
CTransactionRef RandomOrphan() EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
|
||||||
{
|
{
|
||||||
LOCK(m_mutex);
|
LOCK(m_mutex);
|
||||||
std::map<uint256, OrphanTx>::iterator it;
|
std::map<Txid, OrphanTx>::iterator it;
|
||||||
it = m_orphans.lower_bound(InsecureRand256());
|
it = m_orphans.lower_bound(Txid::FromUint256(InsecureRand256()));
|
||||||
if (it == m_orphans.end())
|
if (it == m_orphans.end())
|
||||||
it = m_orphans.begin();
|
it = m_orphans.begin();
|
||||||
return it->second.tx;
|
return it->second.tx;
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include <consensus/validation.h>
|
#include <consensus/validation.h>
|
||||||
#include <logging.h>
|
#include <logging.h>
|
||||||
#include <policy/policy.h>
|
#include <policy/policy.h>
|
||||||
|
#include <primitives/transaction.h>
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
|
@ -20,8 +21,8 @@ bool TxOrphanage::AddTx(const CTransactionRef& tx, NodeId peer)
|
||||||
{
|
{
|
||||||
LOCK(m_mutex);
|
LOCK(m_mutex);
|
||||||
|
|
||||||
const uint256& hash = tx->GetHash();
|
const Txid& hash = tx->GetHash();
|
||||||
const uint256& wtxid = tx->GetWitnessHash();
|
const Wtxid& wtxid = tx->GetWitnessHash();
|
||||||
if (m_orphans.count(hash))
|
if (m_orphans.count(hash))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -53,16 +54,16 @@ bool TxOrphanage::AddTx(const CTransactionRef& tx, NodeId peer)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int TxOrphanage::EraseTx(const uint256& txid)
|
int TxOrphanage::EraseTx(const Txid& txid)
|
||||||
{
|
{
|
||||||
LOCK(m_mutex);
|
LOCK(m_mutex);
|
||||||
return EraseTxNoLock(txid);
|
return EraseTxNoLock(txid);
|
||||||
}
|
}
|
||||||
|
|
||||||
int TxOrphanage::EraseTxNoLock(const uint256& txid)
|
int TxOrphanage::EraseTxNoLock(const Txid& txid)
|
||||||
{
|
{
|
||||||
AssertLockHeld(m_mutex);
|
AssertLockHeld(m_mutex);
|
||||||
std::map<uint256, OrphanTx>::iterator it = m_orphans.find(txid);
|
std::map<Txid, OrphanTx>::iterator it = m_orphans.find(txid);
|
||||||
if (it == m_orphans.end())
|
if (it == m_orphans.end())
|
||||||
return 0;
|
return 0;
|
||||||
for (const CTxIn& txin : it->second.tx->vin)
|
for (const CTxIn& txin : it->second.tx->vin)
|
||||||
|
@ -100,10 +101,10 @@ void TxOrphanage::EraseForPeer(NodeId peer)
|
||||||
m_peer_work_set.erase(peer);
|
m_peer_work_set.erase(peer);
|
||||||
|
|
||||||
int nErased = 0;
|
int nErased = 0;
|
||||||
std::map<uint256, OrphanTx>::iterator iter = m_orphans.begin();
|
std::map<Txid, OrphanTx>::iterator iter = m_orphans.begin();
|
||||||
while (iter != m_orphans.end())
|
while (iter != m_orphans.end())
|
||||||
{
|
{
|
||||||
std::map<uint256, OrphanTx>::iterator maybeErase = iter++; // increment to avoid iterator becoming invalid
|
std::map<Txid, OrphanTx>::iterator maybeErase = iter++; // increment to avoid iterator becoming invalid
|
||||||
if (maybeErase->second.fromPeer == peer)
|
if (maybeErase->second.fromPeer == peer)
|
||||||
{
|
{
|
||||||
nErased += EraseTxNoLock(maybeErase->second.tx->GetHash());
|
nErased += EraseTxNoLock(maybeErase->second.tx->GetHash());
|
||||||
|
@ -123,10 +124,10 @@ void TxOrphanage::LimitOrphans(unsigned int max_orphans)
|
||||||
// Sweep out expired orphan pool entries:
|
// Sweep out expired orphan pool entries:
|
||||||
int nErased = 0;
|
int nErased = 0;
|
||||||
int64_t nMinExpTime = nNow + ORPHAN_TX_EXPIRE_TIME - ORPHAN_TX_EXPIRE_INTERVAL;
|
int64_t nMinExpTime = nNow + ORPHAN_TX_EXPIRE_TIME - ORPHAN_TX_EXPIRE_INTERVAL;
|
||||||
std::map<uint256, OrphanTx>::iterator iter = m_orphans.begin();
|
std::map<Txid, OrphanTx>::iterator iter = m_orphans.begin();
|
||||||
while (iter != m_orphans.end())
|
while (iter != m_orphans.end())
|
||||||
{
|
{
|
||||||
std::map<uint256, OrphanTx>::iterator maybeErase = iter++;
|
std::map<Txid, OrphanTx>::iterator maybeErase = iter++;
|
||||||
if (maybeErase->second.nTimeExpire <= nNow) {
|
if (maybeErase->second.nTimeExpire <= nNow) {
|
||||||
nErased += EraseTxNoLock(maybeErase->second.tx->GetHash());
|
nErased += EraseTxNoLock(maybeErase->second.tx->GetHash());
|
||||||
} else {
|
} else {
|
||||||
|
@ -159,7 +160,7 @@ void TxOrphanage::AddChildrenToWorkSet(const CTransaction& tx)
|
||||||
for (const auto& elem : it_by_prev->second) {
|
for (const auto& elem : it_by_prev->second) {
|
||||||
// Get this source peer's work set, emplacing an empty set if it didn't exist
|
// Get this source peer's work set, emplacing an empty set if it didn't exist
|
||||||
// (note: if this peer wasn't still connected, we would have removed the orphan tx already)
|
// (note: if this peer wasn't still connected, we would have removed the orphan tx already)
|
||||||
std::set<uint256>& orphan_work_set = m_peer_work_set.try_emplace(elem->second.fromPeer).first->second;
|
std::set<Txid>& orphan_work_set = m_peer_work_set.try_emplace(elem->second.fromPeer).first->second;
|
||||||
// Add this tx to the work set
|
// Add this tx to the work set
|
||||||
orphan_work_set.insert(elem->first);
|
orphan_work_set.insert(elem->first);
|
||||||
LogPrint(BCLog::TXPACKAGES, "added %s (wtxid=%s) to peer %d workset\n",
|
LogPrint(BCLog::TXPACKAGES, "added %s (wtxid=%s) to peer %d workset\n",
|
||||||
|
@ -173,9 +174,9 @@ bool TxOrphanage::HaveTx(const GenTxid& gtxid) const
|
||||||
{
|
{
|
||||||
LOCK(m_mutex);
|
LOCK(m_mutex);
|
||||||
if (gtxid.IsWtxid()) {
|
if (gtxid.IsWtxid()) {
|
||||||
return m_wtxid_to_orphan_it.count(gtxid.GetHash());
|
return m_wtxid_to_orphan_it.count(Wtxid::FromUint256(gtxid.GetHash()));
|
||||||
} else {
|
} else {
|
||||||
return m_orphans.count(gtxid.GetHash());
|
return m_orphans.count(Txid::FromUint256(gtxid.GetHash()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,7 +188,7 @@ CTransactionRef TxOrphanage::GetTxToReconsider(NodeId peer)
|
||||||
if (work_set_it != m_peer_work_set.end()) {
|
if (work_set_it != m_peer_work_set.end()) {
|
||||||
auto& work_set = work_set_it->second;
|
auto& work_set = work_set_it->second;
|
||||||
while (!work_set.empty()) {
|
while (!work_set.empty()) {
|
||||||
uint256 txid = *work_set.begin();
|
Txid txid = *work_set.begin();
|
||||||
work_set.erase(work_set.begin());
|
work_set.erase(work_set.begin());
|
||||||
|
|
||||||
const auto orphan_it = m_orphans.find(txid);
|
const auto orphan_it = m_orphans.find(txid);
|
||||||
|
@ -215,7 +216,7 @@ void TxOrphanage::EraseForBlock(const CBlock& block)
|
||||||
{
|
{
|
||||||
LOCK(m_mutex);
|
LOCK(m_mutex);
|
||||||
|
|
||||||
std::vector<uint256> vOrphanErase;
|
std::vector<Txid> vOrphanErase;
|
||||||
|
|
||||||
for (const CTransactionRef& ptx : block.vtx) {
|
for (const CTransactionRef& ptx : block.vtx) {
|
||||||
const CTransaction& tx = *ptx;
|
const CTransaction& tx = *ptx;
|
||||||
|
@ -226,7 +227,7 @@ void TxOrphanage::EraseForBlock(const CBlock& block)
|
||||||
if (itByPrev == m_outpoint_to_orphan_it.end()) continue;
|
if (itByPrev == m_outpoint_to_orphan_it.end()) continue;
|
||||||
for (auto mi = itByPrev->second.begin(); mi != itByPrev->second.end(); ++mi) {
|
for (auto mi = itByPrev->second.begin(); mi != itByPrev->second.end(); ++mi) {
|
||||||
const CTransaction& orphanTx = *(*mi)->second.tx;
|
const CTransaction& orphanTx = *(*mi)->second.tx;
|
||||||
const uint256& orphanHash = orphanTx.GetHash();
|
const auto& orphanHash = orphanTx.GetHash();
|
||||||
vOrphanErase.push_back(orphanHash);
|
vOrphanErase.push_back(orphanHash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -235,7 +236,7 @@ void TxOrphanage::EraseForBlock(const CBlock& block)
|
||||||
// Erase orphan transactions included or precluded by this block
|
// Erase orphan transactions included or precluded by this block
|
||||||
if (vOrphanErase.size()) {
|
if (vOrphanErase.size()) {
|
||||||
int nErased = 0;
|
int nErased = 0;
|
||||||
for (const uint256& orphanHash : vOrphanErase) {
|
for (const auto& orphanHash : vOrphanErase) {
|
||||||
nErased += EraseTxNoLock(orphanHash);
|
nErased += EraseTxNoLock(orphanHash);
|
||||||
}
|
}
|
||||||
LogPrint(BCLog::TXPACKAGES, "Erased %d orphan tx included or conflicted by block\n", nErased);
|
LogPrint(BCLog::TXPACKAGES, "Erased %d orphan tx included or conflicted by block\n", nErased);
|
||||||
|
|
|
@ -34,7 +34,7 @@ public:
|
||||||
CTransactionRef GetTxToReconsider(NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);
|
CTransactionRef GetTxToReconsider(NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);
|
||||||
|
|
||||||
/** Erase an orphan by txid */
|
/** Erase an orphan by txid */
|
||||||
int EraseTx(const uint256& txid) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);
|
int EraseTx(const Txid& txid) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);
|
||||||
|
|
||||||
/** Erase all orphans announced by a peer (eg, after that peer disconnects) */
|
/** Erase all orphans announced by a peer (eg, after that peer disconnects) */
|
||||||
void EraseForPeer(NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);
|
void EraseForPeer(NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);
|
||||||
|
@ -71,10 +71,10 @@ protected:
|
||||||
|
|
||||||
/** Map from txid to orphan transaction record. Limited by
|
/** Map from txid to orphan transaction record. Limited by
|
||||||
* -maxorphantx/DEFAULT_MAX_ORPHAN_TRANSACTIONS */
|
* -maxorphantx/DEFAULT_MAX_ORPHAN_TRANSACTIONS */
|
||||||
std::map<uint256, OrphanTx> m_orphans GUARDED_BY(m_mutex);
|
std::map<Txid, OrphanTx> m_orphans GUARDED_BY(m_mutex);
|
||||||
|
|
||||||
/** Which peer provided the orphans that need to be reconsidered */
|
/** Which peer provided the orphans that need to be reconsidered */
|
||||||
std::map<NodeId, std::set<uint256>> m_peer_work_set GUARDED_BY(m_mutex);
|
std::map<NodeId, std::set<Txid>> m_peer_work_set GUARDED_BY(m_mutex);
|
||||||
|
|
||||||
using OrphanMap = decltype(m_orphans);
|
using OrphanMap = decltype(m_orphans);
|
||||||
|
|
||||||
|
@ -96,10 +96,10 @@ protected:
|
||||||
|
|
||||||
/** Index from wtxid into the m_orphans to lookup orphan
|
/** Index from wtxid into the m_orphans to lookup orphan
|
||||||
* transactions using their witness ids. */
|
* transactions using their witness ids. */
|
||||||
std::map<uint256, OrphanMap::iterator> m_wtxid_to_orphan_it GUARDED_BY(m_mutex);
|
std::map<Wtxid, OrphanMap::iterator> m_wtxid_to_orphan_it GUARDED_BY(m_mutex);
|
||||||
|
|
||||||
/** Erase an orphan by txid */
|
/** Erase an orphan by txid */
|
||||||
int EraseTxNoLock(const uint256& txid) EXCLUSIVE_LOCKS_REQUIRED(m_mutex);
|
int EraseTxNoLock(const Txid& txid) EXCLUSIVE_LOCKS_REQUIRED(m_mutex);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // BITCOIN_TXORPHANAGE_H
|
#endif // BITCOIN_TXORPHANAGE_H
|
||||||
|
|
67
src/util/transaction_identifier.h
Normal file
67
src/util/transaction_identifier.h
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
#ifndef BITCOIN_UTIL_TRANSACTION_IDENTIFIER_H
|
||||||
|
#define BITCOIN_UTIL_TRANSACTION_IDENTIFIER_H
|
||||||
|
|
||||||
|
#include <uint256.h>
|
||||||
|
#include <util/types.h>
|
||||||
|
|
||||||
|
/** transaction_identifier represents the two canonical transaction identifier
|
||||||
|
* types (txid, wtxid).*/
|
||||||
|
template <bool has_witness>
|
||||||
|
class transaction_identifier
|
||||||
|
{
|
||||||
|
uint256 m_wrapped;
|
||||||
|
|
||||||
|
// Note: Use FromUint256 externally instead.
|
||||||
|
transaction_identifier(const uint256& wrapped) : m_wrapped{wrapped} {}
|
||||||
|
|
||||||
|
// TODO: Comparisons with uint256 should be disallowed once we have
|
||||||
|
// converted most of the code to using the new txid types.
|
||||||
|
constexpr int Compare(const uint256& other) const { return m_wrapped.Compare(other); }
|
||||||
|
constexpr int Compare(const transaction_identifier<has_witness>& other) const { return m_wrapped.Compare(other.m_wrapped); }
|
||||||
|
template <typename Other>
|
||||||
|
constexpr int Compare(const Other& other) const
|
||||||
|
{
|
||||||
|
static_assert(ALWAYS_FALSE<Other>, "Forbidden comparison type");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
transaction_identifier() : m_wrapped{} {}
|
||||||
|
|
||||||
|
template <typename Other>
|
||||||
|
bool operator==(const Other& other) const { return Compare(other) == 0; }
|
||||||
|
template <typename Other>
|
||||||
|
bool operator!=(const Other& other) const { return Compare(other) != 0; }
|
||||||
|
template <typename Other>
|
||||||
|
bool operator<(const Other& other) const { return Compare(other) < 0; }
|
||||||
|
|
||||||
|
uint256 ToUint256() const { return m_wrapped; }
|
||||||
|
static transaction_identifier FromUint256(const uint256& id) { return {id}; }
|
||||||
|
|
||||||
|
/** Wrapped `uint256` methods. */
|
||||||
|
constexpr bool IsNull() const { return m_wrapped.IsNull(); }
|
||||||
|
constexpr void SetNull() { m_wrapped.SetNull(); }
|
||||||
|
std::string GetHex() const { return m_wrapped.GetHex(); }
|
||||||
|
std::string ToString() const { return m_wrapped.ToString(); }
|
||||||
|
constexpr const std::byte* data() const { return reinterpret_cast<const std::byte*>(m_wrapped.data()); }
|
||||||
|
constexpr const std::byte* begin() const { return reinterpret_cast<const std::byte*>(m_wrapped.begin()); }
|
||||||
|
constexpr const std::byte* end() const { return reinterpret_cast<const std::byte*>(m_wrapped.end()); }
|
||||||
|
template <typename Stream> void Serialize(Stream& s) const { m_wrapped.Serialize(s); }
|
||||||
|
template <typename Stream> void Unserialize(Stream& s) { m_wrapped.Unserialize(s); }
|
||||||
|
|
||||||
|
/** Conversion function to `uint256`.
|
||||||
|
*
|
||||||
|
* Note: new code should use `ToUint256`.
|
||||||
|
*
|
||||||
|
* TODO: This should be removed once the majority of the code has switched
|
||||||
|
* to using the Txid and Wtxid types. Until then it makes for a smoother
|
||||||
|
* transition to allow this conversion. */
|
||||||
|
operator uint256() const { return m_wrapped; }
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Txid commits to all transaction fields except the witness. */
|
||||||
|
using Txid = transaction_identifier<false>;
|
||||||
|
/** Wtxid commits to all transaction fields including the witness. */
|
||||||
|
using Wtxid = transaction_identifier<true>;
|
||||||
|
|
||||||
|
#endif // BITCOIN_UTIL_TRANSACTION_IDENTIFIER_H
|
|
@ -618,7 +618,7 @@ private:
|
||||||
|
|
||||||
const CTransactionRef& m_ptx;
|
const CTransactionRef& m_ptx;
|
||||||
/** Txid. */
|
/** Txid. */
|
||||||
const uint256& m_hash;
|
const Txid& m_hash;
|
||||||
TxValidationState m_state;
|
TxValidationState m_state;
|
||||||
/** A temporary cache containing serialized transaction data for signature verification.
|
/** A temporary cache containing serialized transaction data for signature verification.
|
||||||
* Reused across PolicyScriptChecks and ConsensusScriptChecks. */
|
* Reused across PolicyScriptChecks and ConsensusScriptChecks. */
|
||||||
|
@ -1870,7 +1870,7 @@ bool CheckInputScripts(const CTransaction& tx, TxValidationState& state,
|
||||||
// transaction).
|
// transaction).
|
||||||
uint256 hashCacheEntry;
|
uint256 hashCacheEntry;
|
||||||
CSHA256 hasher = g_scriptExecutionCacheHasher;
|
CSHA256 hasher = g_scriptExecutionCacheHasher;
|
||||||
hasher.Write(tx.GetWitnessHash().begin(), 32).Write((unsigned char*)&flags, sizeof(flags)).Finalize(hashCacheEntry.begin());
|
hasher.Write(UCharCast(tx.GetWitnessHash().begin()), 32).Write((unsigned char*)&flags, sizeof(flags)).Finalize(hashCacheEntry.begin());
|
||||||
AssertLockHeld(cs_main); //TODO: Remove this requirement by making CuckooCache not require external locks
|
AssertLockHeld(cs_main); //TODO: Remove this requirement by making CuckooCache not require external locks
|
||||||
if (g_scriptExecutionCache.contains(hashCacheEntry, !cacheFullScriptStore)) {
|
if (g_scriptExecutionCache.contains(hashCacheEntry, !cacheFullScriptStore)) {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -330,8 +330,8 @@ public:
|
||||||
bool isInactive() const { return state<TxStateInactive>(); }
|
bool isInactive() const { return state<TxStateInactive>(); }
|
||||||
bool isUnconfirmed() const { return !isAbandoned() && !isConflicted() && !isConfirmed(); }
|
bool isUnconfirmed() const { return !isAbandoned() && !isConflicted() && !isConfirmed(); }
|
||||||
bool isConfirmed() const { return state<TxStateConfirmed>(); }
|
bool isConfirmed() const { return state<TxStateConfirmed>(); }
|
||||||
const uint256& GetHash() const { return tx->GetHash(); }
|
const Txid& GetHash() const { return tx->GetHash(); }
|
||||||
const uint256& GetWitnessHash() const { return tx->GetWitnessHash(); }
|
const Wtxid& GetWitnessHash() const { return tx->GetWitnessHash(); }
|
||||||
bool IsCoinBase() const { return tx->IsCoinBase(); }
|
bool IsCoinBase() const { return tx->IsCoinBase(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
Loading…
Add table
Reference in a new issue