Changeset View
Changeset View
Standalone View
Standalone View
src/validationinterface.cpp
// Copyright (c) 2009-2010 Satoshi Nakamoto | // Copyright (c) 2009-2010 Satoshi Nakamoto | ||||
// Copyright (c) 2009-2016 The Bitcoin Core developers | // Copyright (c) 2009-2016 The Bitcoin Core developers | ||||
// Distributed under the MIT software license, see the accompanying | // Distributed under the MIT software license, see the accompanying | ||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
#include <validationinterface.h> | #include <validationinterface.h> | ||||
#include <chain.h> | |||||
#include <consensus/validation.h> | |||||
#include <logging.h> | |||||
#include <primitives/block.h> | #include <primitives/block.h> | ||||
#include <primitives/transaction.h> | |||||
#include <scheduler.h> | #include <scheduler.h> | ||||
#include <util/validation.h> | |||||
#include <future> | #include <future> | ||||
#include <tuple> | #include <tuple> | ||||
#include <unordered_map> | #include <unordered_map> | ||||
#include <utility> | #include <utility> | ||||
#include <boost/signals2/signal.hpp> | #include <boost/signals2/signal.hpp> | ||||
▲ Show 20 Lines • Show All 136 Lines • ▼ Show 20 Lines | |||||
void SyncWithValidationInterfaceQueue() { | void SyncWithValidationInterfaceQueue() { | ||||
AssertLockNotHeld(cs_main); | AssertLockNotHeld(cs_main); | ||||
// Block until the validation queue drains | // Block until the validation queue drains | ||||
std::promise<void> promise; | std::promise<void> promise; | ||||
CallFunctionInValidationInterfaceQueue([&promise] { promise.set_value(); }); | CallFunctionInValidationInterfaceQueue([&promise] { promise.set_value(); }); | ||||
promise.get_future().wait(); | 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::VALIDATION, fmt "\n", __VA_ARGS__) | |||||
void CMainSignals::UpdatedBlockTip(const CBlockIndex *pindexNew, | void CMainSignals::UpdatedBlockTip(const CBlockIndex *pindexNew, | ||||
const CBlockIndex *pindexFork, | const CBlockIndex *pindexFork, | ||||
bool fInitialDownload) { | bool fInitialDownload) { | ||||
// Dependencies exist that require UpdatedBlockTip events to be delivered in | // Dependencies exist that require UpdatedBlockTip events to be delivered in | ||||
// the order in which the chain actually updates. One way to ensure this is | // 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 | // for the caller to invoke this signal in the same critical section where | ||||
// the chain is updated | // the chain is updated | ||||
m_internals->m_schedulerClient.AddToProcessQueue([pindexNew, pindexFork, | auto event = [pindexNew, pindexFork, fInitialDownload, this] { | ||||
fInitialDownload, this] { | |||||
m_internals->UpdatedBlockTip(pindexNew, pindexFork, fInitialDownload); | 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) { | void CMainSignals::TransactionAddedToMempool(const CTransactionRef &ptx) { | ||||
m_internals->m_schedulerClient.AddToProcessQueue( | auto event = [ptx, this] { m_internals->TransactionAddedToMempool(ptx); }; | ||||
[ptx, this] { m_internals->TransactionAddedToMempool(ptx); }); | ENQUEUE_AND_LOG_EVENT(event, "%s: txid=%s", __func__, | ||||
ptx->GetHash().ToString()); | |||||
} | } | ||||
void CMainSignals::TransactionRemovedFromMempool(const CTransactionRef &ptx) { | void CMainSignals::TransactionRemovedFromMempool(const CTransactionRef &ptx) { | ||||
m_internals->m_schedulerClient.AddToProcessQueue( | auto event = [ptx, this] { | ||||
[ptx, this] { m_internals->TransactionRemovedFromMempool(ptx); }); | m_internals->TransactionRemovedFromMempool(ptx); | ||||
}; | |||||
ENQUEUE_AND_LOG_EVENT(event, "%s: txid=%s", __func__, | |||||
ptx->GetHash().ToString()); | |||||
} | } | ||||
void CMainSignals::BlockConnected( | void CMainSignals::BlockConnected( | ||||
const std::shared_ptr<const CBlock> &pblock, const CBlockIndex *pindex, | const std::shared_ptr<const CBlock> &pblock, const CBlockIndex *pindex, | ||||
const std::shared_ptr<const std::vector<CTransactionRef>> &pvtxConflicted) { | const std::shared_ptr<const std::vector<CTransactionRef>> &pvtxConflicted) { | ||||
m_internals->m_schedulerClient.AddToProcessQueue( | auto event = [pblock, pindex, pvtxConflicted, this] { | ||||
[pblock, pindex, pvtxConflicted, this] { | |||||
m_internals->BlockConnected(pblock, pindex, *pvtxConflicted); | 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( | void CMainSignals::BlockDisconnected( | ||||
const std::shared_ptr<const CBlock> &pblock) { | const std::shared_ptr<const CBlock> &pblock) { | ||||
m_internals->m_schedulerClient.AddToProcessQueue( | // TODO: This function was refactored as part of an out-of-order backport | ||||
[pblock, this] { m_internals->BlockDisconnected(pblock); }); | // of https://github.com/bitcoin/bitcoin/pull/16688 | ||||
auto event = [pblock, this] { m_internals->BlockDisconnected(pblock); }; | |||||
ENQUEUE_AND_LOG_EVENT(event, "%s: block hash=%s", __func__, | |||||
pblock->GetHash().ToString()); | |||||
} | } | ||||
void CMainSignals::ChainStateFlushed(const CBlockLocator &locator) { | void CMainSignals::ChainStateFlushed(const CBlockLocator &locator) { | ||||
m_internals->m_schedulerClient.AddToProcessQueue( | auto event = [locator, this] { m_internals->ChainStateFlushed(locator); }; | ||||
[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, | void CMainSignals::BlockChecked(const CBlock &block, | ||||
const CValidationState &state) { | const CValidationState &state) { | ||||
LOG_EVENT("%s: block hash=%s state=%s", __func__, | |||||
block.GetHash().ToString(), FormatStateMessage(state)); | |||||
m_internals->BlockChecked(block, state); | m_internals->BlockChecked(block, state); | ||||
} | } | ||||
void CMainSignals::NewPoWValidBlock( | void CMainSignals::NewPoWValidBlock( | ||||
const CBlockIndex *pindex, const std::shared_ptr<const CBlock> &block) { | 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); | m_internals->NewPoWValidBlock(pindex, block); | ||||
} | } |