Skip to content

Commit

Permalink
Add logging for CValidationInterface events
Browse files Browse the repository at this point in the history
This could help debug issues where there may be race conditions at play,
such as bitcoin#12978.

Fixes bitcoin#12994.
  • Loading branch information
jkczyz committed Nov 22, 2019
1 parent ee4d66a commit 0cadb12
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 14 deletions.
68 changes: 54 additions & 14 deletions src/validationinterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@

#include <validationinterface.h>

#include <chain.h>
#include <logging.h>
#include <primitives/block.h>
#include <primitives/transaction.h>
#include <scheduler.h>
#include <util/validation.h>

#include <future>
#include <unordered_map>
Expand Down Expand Up @@ -110,52 +114,88 @@ void SyncWithValidationInterfaceQueue() {
promise.get_future().wait();
}

// Use a macro instead of a function for conditional logging to prevent
// evaluating arguments when logging is not enabled.
//
// NOTE: The lambda captures all local variables by value.
#define ENQUEUE_AND_LOG_EVENT(event, fmt, name, ...) \
do { \
auto local_name = (name); \
LOG_EVENT("Enqueuing " fmt, local_name, __VA_ARGS__); \
m_internals->m_schedulerClient.AddToProcessQueue([=] { \
LOG_EVENT(fmt, local_name, __VA_ARGS__); \
event(); \
}); \
} while (0)

#define LOG_EVENT(fmt, ...) \
LogPrint(BCLog::VALIDATIONINTERFACE, fmt "\n", __VA_ARGS__)

void CMainSignals::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) {
// Dependencies exist that require UpdatedBlockTip events to be delivered in the order in which
// the chain actually updates. One way to ensure this is for the caller to invoke this signal
// in the same critical section where the chain is updated

m_internals->m_schedulerClient.AddToProcessQueue([pindexNew, pindexFork, fInitialDownload, this] {
auto event = [pindexNew, pindexFork, fInitialDownload, this] {
m_internals->UpdatedBlockTip(pindexNew, pindexFork, fInitialDownload);
});
};
ENQUEUE_AND_LOG_EVENT(event, "%s: new block hash=%s fork block hash=%s (in IBD=%s)", __func__,
pindexNew->GetBlockHash().ToString(),
pindexFork ? pindexFork->GetBlockHash().ToString() : "null",
fInitialDownload);
}

void CMainSignals::TransactionAddedToMempool(const CTransactionRef &ptx) {
m_internals->m_schedulerClient.AddToProcessQueue([ptx, this] {
auto event = [ptx, this] {
m_internals->TransactionAddedToMempool(ptx);
});
};
ENQUEUE_AND_LOG_EVENT(event, "%s: txid=%s wtxid=%s", __func__,
ptx->GetHash().ToString(),
ptx->GetWitnessHash().ToString());
}

void CMainSignals::TransactionRemovedFromMempool(const CTransactionRef &ptx) {
m_internals->m_schedulerClient.AddToProcessQueue([ptx, this] {
auto event = [ptx, this] {
m_internals->TransactionRemovedFromMempool(ptx);
});
};
ENQUEUE_AND_LOG_EVENT(event, "%s: txid=%s wtxid=%s", __func__,
ptx->GetHash().ToString(),
ptx->GetWitnessHash().ToString());
}

void CMainSignals::BlockConnected(const std::shared_ptr<const CBlock> &pblock, const CBlockIndex *pindex, const std::shared_ptr<const std::vector<CTransactionRef>>& pvtxConflicted) {
m_internals->m_schedulerClient.AddToProcessQueue([pblock, pindex, pvtxConflicted, this] {
auto event = [pblock, pindex, pvtxConflicted, this] {
m_internals->BlockConnected(pblock, pindex, *pvtxConflicted);
});
};
ENQUEUE_AND_LOG_EVENT(event, "%s: block hash=%s block height=%d", __func__,
pblock->GetHash().ToString(),
pindex->nHeight);
}

void CMainSignals::BlockDisconnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindex)
{
m_internals->m_schedulerClient.AddToProcessQueue([pblock, pindex, this] {
void CMainSignals::BlockDisconnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindex) {
auto event = [pblock, pindex, this] {
m_internals->BlockDisconnected(pblock, pindex);
});
};
ENQUEUE_AND_LOG_EVENT(event, "%s: block hash=%s block height=%d", __func__,
pblock->GetHash().ToString(),
pindex->nHeight);
}

void CMainSignals::ChainStateFlushed(const CBlockLocator &locator) {
m_internals->m_schedulerClient.AddToProcessQueue([locator, this] {
auto event = [locator, this] {
m_internals->ChainStateFlushed(locator);
});
};
ENQUEUE_AND_LOG_EVENT(event, "%s: block hash=%s", __func__,
locator.IsNull() ? "null" : locator.vHave.front().ToString());
}

void CMainSignals::BlockChecked(const CBlock& block, const BlockValidationState& state) {
LOG_EVENT("%s: block hash=%s state=%s", __func__,
block.GetHash().ToString(), FormatStateMessage(state));
m_internals->BlockChecked(block, state);
}

void CMainSignals::NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock> &block) {
LOG_EVENT("%s: block hash=%s", __func__, block->GetHash().ToString());
m_internals->NewPoWValidBlock(pindex, block);
}
1 change: 1 addition & 0 deletions test/lint/lint-format-strings.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
("src/index/base.cpp", "FatalError(const char* fmt, const Args&... args)"),
("src/netbase.cpp", "LogConnectFailure(bool manual_connection, const char* fmt, const Args&... args)"),
("src/util/system.cpp", "strprintf(_(COPYRIGHT_HOLDERS).translated, COPYRIGHT_HOLDERS_SUBSTITUTION)"),
("src/validationinterface.cpp", "LogPrint(BCLog::VALIDATIONINTERFACE, fmt \"\\n\", __VA_ARGS__)"),
("src/wallet/wallet.h", "WalletLogPrintf(std::string fmt, Params... parameters)"),
("src/wallet/wallet.h", "LogPrintf((\"%s \" + fmt).c_str(), GetDisplayName(), parameters...)"),
("src/logging.h", "LogPrintf(const char* fmt, const Args&... args)"),
Expand Down

0 comments on commit 0cadb12

Please sign in to comment.