mirror of
https://github.com/Retropex/bitcoin.git
synced 2025-08-05 06:24:49 +02:00
Merge bitcoin/bitcoin#30507: m_tx_download_mutex followups
7c29e556c5
m_tx_download_mutex followups (glozow)e543c657da
release m_tx_download_mutex before MakeAndPushMessage GETDATA (glozow)bce5f37c7b
[refactor] change ActiveTipChange to use CBlockIndex ref instead of ptr (glozow)7cc5ac5a67
[doc] TxOrphanage is no longer thread-safe (glozow)6f49548670
[refactor] combine block vtx loops in BlockConnected (glozow) Pull request description: Followup to #30111. Includes suggestions: - https://github.com/bitcoin/bitcoin/pull/30111#discussion_r1686303768 - https://github.com/bitcoin/bitcoin/pull/30111#discussion_r1686314984 - https://github.com/bitcoin/bitcoin/pull/30111#discussion_r1683186792 - https://github.com/bitcoin/bitcoin/pull/30111#issuecomment-2242819514 - https://github.com/bitcoin/bitcoin/pull/30111#discussion_r1686372826 ACKs for top commit: instagibbs: reACK7c29e556c5
theStack: re-ACK7c29e556c5
dergoegge: reACK7c29e556c5
Tree-SHA512: 79a9002d74739367789bbc64bb1d431f4d43a25a7934231e55814c2cb6981c15ef2d8465544ae2a4fbd734d9bed6cc41b37a923938a88cb8fea139523c1e98da
This commit is contained in:
commit
5d28013044
@ -489,7 +489,7 @@ public:
|
|||||||
CTxMemPool& pool, node::Warnings& warnings, Options opts);
|
CTxMemPool& pool, node::Warnings& warnings, Options opts);
|
||||||
|
|
||||||
/** Overridden from CValidationInterface. */
|
/** Overridden from CValidationInterface. */
|
||||||
void ActiveTipChange(const CBlockIndex* new_tip, bool) override
|
void ActiveTipChange(const CBlockIndex& new_tip, bool) override
|
||||||
EXCLUSIVE_LOCKS_REQUIRED(!m_tx_download_mutex);
|
EXCLUSIVE_LOCKS_REQUIRED(!m_tx_download_mutex);
|
||||||
void BlockConnected(ChainstateRole role, const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindexConnected) override
|
void BlockConnected(ChainstateRole role, const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindexConnected) override
|
||||||
EXCLUSIVE_LOCKS_REQUIRED(!m_tx_download_mutex);
|
EXCLUSIVE_LOCKS_REQUIRED(!m_tx_download_mutex);
|
||||||
@ -780,10 +780,8 @@ private:
|
|||||||
* - A txhash (txid or wtxid) in m_txrequest is not also in m_recent_rejects_reconsiderable.
|
* - A txhash (txid or wtxid) in m_txrequest is not also in m_recent_rejects_reconsiderable.
|
||||||
* - A txhash (txid or wtxid) in m_txrequest is not also in m_recent_confirmed_transactions.
|
* - A txhash (txid or wtxid) in m_txrequest is not also in m_recent_confirmed_transactions.
|
||||||
* - Each data structure's limits hold (m_orphanage max size, m_txrequest per-peer limits, etc).
|
* - Each data structure's limits hold (m_orphanage max size, m_txrequest per-peer limits, etc).
|
||||||
*
|
|
||||||
* m_tx_download_mutex must be acquired before mempool.cs
|
|
||||||
*/
|
*/
|
||||||
Mutex m_tx_download_mutex;
|
Mutex m_tx_download_mutex ACQUIRED_BEFORE(m_mempool.cs);
|
||||||
TxRequestTracker m_txrequest GUARDED_BY(m_tx_download_mutex);
|
TxRequestTracker m_txrequest GUARDED_BY(m_tx_download_mutex);
|
||||||
std::unique_ptr<TxReconciliationTracker> m_txreconciliation;
|
std::unique_ptr<TxReconciliationTracker> m_txreconciliation;
|
||||||
|
|
||||||
@ -2070,8 +2068,10 @@ void PeerManagerImpl::StartScheduledTasks(CScheduler& scheduler)
|
|||||||
scheduler.scheduleFromNow([&] { ReattemptInitialBroadcast(scheduler); }, delta);
|
scheduler.scheduleFromNow([&] { ReattemptInitialBroadcast(scheduler); }, delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PeerManagerImpl::ActiveTipChange(const CBlockIndex* new_tip, bool is_ibd)
|
void PeerManagerImpl::ActiveTipChange(const CBlockIndex& new_tip, bool is_ibd)
|
||||||
{
|
{
|
||||||
|
// Ensure mempool mutex was released, otherwise deadlock may occur if another thread holding
|
||||||
|
// m_tx_download_mutex waits on the mempool mutex.
|
||||||
AssertLockNotHeld(m_mempool.cs);
|
AssertLockNotHeld(m_mempool.cs);
|
||||||
AssertLockNotHeld(m_tx_download_mutex);
|
AssertLockNotHeld(m_tx_download_mutex);
|
||||||
|
|
||||||
@ -2123,8 +2123,6 @@ void PeerManagerImpl::BlockConnected(
|
|||||||
if (ptx->HasWitness()) {
|
if (ptx->HasWitness()) {
|
||||||
m_recent_confirmed_transactions.insert(ptx->GetWitnessHash().ToUint256());
|
m_recent_confirmed_transactions.insert(ptx->GetWitnessHash().ToUint256());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
for (const auto& ptx : pblock->vtx) {
|
|
||||||
m_txrequest.ForgetTxHash(ptx->GetHash());
|
m_txrequest.ForgetTxHash(ptx->GetHash());
|
||||||
m_txrequest.ForgetTxHash(ptx->GetWitnessHash());
|
m_txrequest.ForgetTxHash(ptx->GetWitnessHash());
|
||||||
}
|
}
|
||||||
@ -5336,6 +5334,7 @@ bool PeerManagerImpl::MaybeDiscourageAndDisconnect(CNode& pnode, Peer& peer)
|
|||||||
|
|
||||||
bool PeerManagerImpl::ProcessMessages(CNode* pfrom, std::atomic<bool>& interruptMsgProc)
|
bool PeerManagerImpl::ProcessMessages(CNode* pfrom, std::atomic<bool>& interruptMsgProc)
|
||||||
{
|
{
|
||||||
|
AssertLockNotHeld(m_tx_download_mutex);
|
||||||
AssertLockHeld(g_msgproc_mutex);
|
AssertLockHeld(g_msgproc_mutex);
|
||||||
|
|
||||||
PeerRef peer = GetPeerRef(pfrom->GetId());
|
PeerRef peer = GetPeerRef(pfrom->GetId());
|
||||||
@ -5827,6 +5826,7 @@ bool PeerManagerImpl::SetupAddressRelay(const CNode& node, Peer& peer)
|
|||||||
|
|
||||||
bool PeerManagerImpl::SendMessages(CNode* pto)
|
bool PeerManagerImpl::SendMessages(CNode* pto)
|
||||||
{
|
{
|
||||||
|
AssertLockNotHeld(m_tx_download_mutex);
|
||||||
AssertLockHeld(g_msgproc_mutex);
|
AssertLockHeld(g_msgproc_mutex);
|
||||||
|
|
||||||
PeerRef peer = GetPeerRef(pto->GetId());
|
PeerRef peer = GetPeerRef(pto->GetId());
|
||||||
@ -6297,32 +6297,33 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
|
|||||||
//
|
//
|
||||||
// Message: getdata (transactions)
|
// Message: getdata (transactions)
|
||||||
//
|
//
|
||||||
LOCK(m_tx_download_mutex);
|
{
|
||||||
std::vector<std::pair<NodeId, GenTxid>> expired;
|
LOCK(m_tx_download_mutex);
|
||||||
auto requestable = m_txrequest.GetRequestable(pto->GetId(), current_time, &expired);
|
std::vector<std::pair<NodeId, GenTxid>> expired;
|
||||||
for (const auto& entry : expired) {
|
auto requestable = m_txrequest.GetRequestable(pto->GetId(), current_time, &expired);
|
||||||
LogPrint(BCLog::NET, "timeout of inflight %s %s from peer=%d\n", entry.second.IsWtxid() ? "wtx" : "tx",
|
for (const auto& entry : expired) {
|
||||||
entry.second.GetHash().ToString(), entry.first);
|
LogPrint(BCLog::NET, "timeout of inflight %s %s from peer=%d\n", entry.second.IsWtxid() ? "wtx" : "tx",
|
||||||
}
|
entry.second.GetHash().ToString(), entry.first);
|
||||||
for (const GenTxid& gtxid : requestable) {
|
|
||||||
// Exclude m_recent_rejects_reconsiderable: we may be requesting a missing parent
|
|
||||||
// that was previously rejected for being too low feerate.
|
|
||||||
if (!AlreadyHaveTx(gtxid, /*include_reconsiderable=*/false)) {
|
|
||||||
LogPrint(BCLog::NET, "Requesting %s %s peer=%d\n", gtxid.IsWtxid() ? "wtx" : "tx",
|
|
||||||
gtxid.GetHash().ToString(), pto->GetId());
|
|
||||||
vGetData.emplace_back(gtxid.IsWtxid() ? MSG_WTX : (MSG_TX | GetFetchFlags(*peer)), gtxid.GetHash());
|
|
||||||
if (vGetData.size() >= MAX_GETDATA_SZ) {
|
|
||||||
MakeAndPushMessage(*pto, NetMsgType::GETDATA, vGetData);
|
|
||||||
vGetData.clear();
|
|
||||||
}
|
|
||||||
m_txrequest.RequestedTx(pto->GetId(), gtxid.GetHash(), current_time + GETDATA_TX_INTERVAL);
|
|
||||||
} else {
|
|
||||||
// We have already seen this transaction, no need to download. This is just a belt-and-suspenders, as
|
|
||||||
// this should already be called whenever a transaction becomes AlreadyHaveTx().
|
|
||||||
m_txrequest.ForgetTxHash(gtxid.GetHash());
|
|
||||||
}
|
}
|
||||||
}
|
for (const GenTxid& gtxid : requestable) {
|
||||||
|
// Exclude m_recent_rejects_reconsiderable: we may be requesting a missing parent
|
||||||
|
// that was previously rejected for being too low feerate.
|
||||||
|
if (!AlreadyHaveTx(gtxid, /*include_reconsiderable=*/false)) {
|
||||||
|
LogPrint(BCLog::NET, "Requesting %s %s peer=%d\n", gtxid.IsWtxid() ? "wtx" : "tx",
|
||||||
|
gtxid.GetHash().ToString(), pto->GetId());
|
||||||
|
vGetData.emplace_back(gtxid.IsWtxid() ? MSG_WTX : (MSG_TX | GetFetchFlags(*peer)), gtxid.GetHash());
|
||||||
|
if (vGetData.size() >= MAX_GETDATA_SZ) {
|
||||||
|
MakeAndPushMessage(*pto, NetMsgType::GETDATA, vGetData);
|
||||||
|
vGetData.clear();
|
||||||
|
}
|
||||||
|
m_txrequest.RequestedTx(pto->GetId(), gtxid.GetHash(), current_time + GETDATA_TX_INTERVAL);
|
||||||
|
} else {
|
||||||
|
// We have already seen this transaction, no need to download. This is just a belt-and-suspenders, as
|
||||||
|
// this should already be called whenever a transaction becomes AlreadyHaveTx().
|
||||||
|
m_txrequest.ForgetTxHash(gtxid.GetHash());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // release m_tx_download_mutex
|
||||||
|
|
||||||
if (!vGetData.empty())
|
if (!vGetData.empty())
|
||||||
MakeAndPushMessage(*pto, NetMsgType::GETDATA, vGetData);
|
MakeAndPushMessage(*pto, NetMsgType::GETDATA, vGetData);
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
* Since we cannot distinguish orphans from bad transactions with
|
* Since we cannot distinguish orphans from bad transactions with
|
||||||
* non-existent inputs, we heavily limit the number of orphans
|
* non-existent inputs, we heavily limit the number of orphans
|
||||||
* we keep and the duration we keep them for.
|
* we keep and the duration we keep them for.
|
||||||
|
* Not thread-safe. Requires external synchronization.
|
||||||
*/
|
*/
|
||||||
class TxOrphanage {
|
class TxOrphanage {
|
||||||
public:
|
public:
|
||||||
|
@ -3553,7 +3553,7 @@ bool Chainstate::ActivateBestChain(BlockValidationState& state, std::shared_ptr<
|
|||||||
} // release MempoolMutex
|
} // release MempoolMutex
|
||||||
// Notify external listeners about the new tip, even if pindexFork == pindexNewTip.
|
// Notify external listeners about the new tip, even if pindexFork == pindexNewTip.
|
||||||
if (m_chainman.m_options.signals && this == &m_chainman.ActiveChainstate()) {
|
if (m_chainman.m_options.signals && this == &m_chainman.ActiveChainstate()) {
|
||||||
m_chainman.m_options.signals->ActiveTipChange(pindexNewTip, m_chainman.IsInitialBlockDownload());
|
m_chainman.m_options.signals->ActiveTipChange(*Assert(pindexNewTip), m_chainman.IsInitialBlockDownload());
|
||||||
}
|
}
|
||||||
} // release cs_main
|
} // release cs_main
|
||||||
// When we reach this point, we switched to a new tip (stored in pindexNewTip).
|
// When we reach this point, we switched to a new tip (stored in pindexNewTip).
|
||||||
@ -3778,7 +3778,7 @@ bool Chainstate::InvalidateBlock(BlockValidationState& state, CBlockIndex* pinde
|
|||||||
// Fire ActiveTipChange now for the current chain tip to make sure clients are notified.
|
// Fire ActiveTipChange now for the current chain tip to make sure clients are notified.
|
||||||
// ActivateBestChain may call this as well, but not necessarily.
|
// ActivateBestChain may call this as well, but not necessarily.
|
||||||
if (m_chainman.m_options.signals) {
|
if (m_chainman.m_options.signals) {
|
||||||
m_chainman.m_options.signals->ActiveTipChange(m_chain.Tip(), m_chainman.IsInitialBlockDownload());
|
m_chainman.m_options.signals->ActiveTipChange(*Assert(m_chain.Tip()), m_chainman.IsInitialBlockDownload());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -183,9 +183,9 @@ void ValidationSignals::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlo
|
|||||||
fInitialDownload);
|
fInitialDownload);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ValidationSignals::ActiveTipChange(const CBlockIndex *new_tip, bool is_ibd)
|
void ValidationSignals::ActiveTipChange(const CBlockIndex& new_tip, bool is_ibd)
|
||||||
{
|
{
|
||||||
LOG_EVENT("%s: new block hash=%s block height=%d", __func__, new_tip->GetBlockHash().ToString(), new_tip->nHeight);
|
LOG_EVENT("%s: new block hash=%s block height=%d", __func__, new_tip.GetBlockHash().ToString(), new_tip.nHeight);
|
||||||
m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.ActiveTipChange(new_tip, is_ibd); });
|
m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.ActiveTipChange(new_tip, is_ibd); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ protected:
|
|||||||
/**
|
/**
|
||||||
* Notifies listeners any time the block chain tip changes, synchronously.
|
* Notifies listeners any time the block chain tip changes, synchronously.
|
||||||
*/
|
*/
|
||||||
virtual void ActiveTipChange(const CBlockIndex* new_tip, bool is_ibd) {};
|
virtual void ActiveTipChange(const CBlockIndex& new_tip, bool is_ibd) {};
|
||||||
/**
|
/**
|
||||||
* Notifies listeners of a transaction having been added to mempool.
|
* Notifies listeners of a transaction having been added to mempool.
|
||||||
*
|
*
|
||||||
@ -218,7 +218,7 @@ public:
|
|||||||
void SyncWithValidationInterfaceQueue() LOCKS_EXCLUDED(cs_main);
|
void SyncWithValidationInterfaceQueue() LOCKS_EXCLUDED(cs_main);
|
||||||
|
|
||||||
void UpdatedBlockTip(const CBlockIndex *, const CBlockIndex *, bool fInitialDownload);
|
void UpdatedBlockTip(const CBlockIndex *, const CBlockIndex *, bool fInitialDownload);
|
||||||
void ActiveTipChange(const CBlockIndex*, bool);
|
void ActiveTipChange(const CBlockIndex&, bool);
|
||||||
void TransactionAddedToMempool(const NewMempoolTransactionInfo&, uint64_t mempool_sequence);
|
void TransactionAddedToMempool(const NewMempoolTransactionInfo&, uint64_t mempool_sequence);
|
||||||
void TransactionRemovedFromMempool(const CTransactionRef&, MemPoolRemovalReason, uint64_t mempool_sequence);
|
void TransactionRemovedFromMempool(const CTransactionRef&, MemPoolRemovalReason, uint64_t mempool_sequence);
|
||||||
void MempoolTransactionsRemovedForBlock(const std::vector<RemovedMempoolTransactionInfo>&, unsigned int nBlockHeight);
|
void MempoolTransactionsRemovedForBlock(const std::vector<RemovedMempoolTransactionInfo>&, unsigned int nBlockHeight);
|
||||||
|
Loading…
Reference in New Issue
Block a user