validation: pass ChainstateRole for validationinterface calls

This allows consumers to decide how to handle events from background or
assumedvalid chainstates.
This commit is contained in:
James O'Beirne 2019-09-23 13:54:21 -04:00 committed by James O'Beirne
parent 1e59acdf17
commit 4d8f4dcb45
19 changed files with 66 additions and 42 deletions

View File

@ -70,7 +70,7 @@ void generateFakeBlock(const CChainParams& params,
// notify wallet
const auto& pindex = WITH_LOCK(::cs_main, return context.chainman->ActiveChain().Tip());
wallet.blockConnected(kernel::MakeBlockInfo(pindex, &block));
wallet.blockConnected(ChainstateRole::NORMAL, kernel::MakeBlockInfo(pindex, &block));
}
struct PreSelectInputs {

View File

@ -250,7 +250,7 @@ bool BaseIndex::Rewind(const CBlockIndex* current_tip, const CBlockIndex* new_ti
return true;
}
void BaseIndex::BlockConnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* pindex)
void BaseIndex::BlockConnected(ChainstateRole role, const std::shared_ptr<const CBlock>& block, const CBlockIndex* pindex)
{
if (!m_synced) {
return;
@ -296,7 +296,7 @@ void BaseIndex::BlockConnected(const std::shared_ptr<const CBlock>& block, const
}
}
void BaseIndex::ChainStateFlushed(const CBlockLocator& locator)
void BaseIndex::ChainStateFlushed(ChainstateRole role, const CBlockLocator& locator)
{
if (!m_synced) {
return;

View File

@ -102,9 +102,9 @@ protected:
Chainstate* m_chainstate{nullptr};
const std::string m_name;
void BlockConnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* pindex) override;
void BlockConnected(ChainstateRole role, const std::shared_ptr<const CBlock>& block, const CBlockIndex* pindex) override;
void ChainStateFlushed(const CBlockLocator& locator) override;
void ChainStateFlushed(ChainstateRole role, const CBlockLocator& locator) override;
/// Initialize internal state from the database and block index.
[[nodiscard]] virtual bool CustomInit(const std::optional<interfaces::BlockKey>& block) { return true; }

View File

@ -27,6 +27,7 @@ class Coin;
class uint256;
enum class MemPoolRemovalReason;
enum class RBFTransactionState;
enum class ChainstateRole;
struct bilingual_str;
struct CBlockLocator;
struct FeeCalculation;
@ -310,10 +311,10 @@ public:
virtual ~Notifications() {}
virtual void transactionAddedToMempool(const CTransactionRef& tx) {}
virtual void transactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason) {}
virtual void blockConnected(const BlockInfo& block) {}
virtual void blockConnected(ChainstateRole role, const BlockInfo& block) {}
virtual void blockDisconnected(const BlockInfo& block) {}
virtual void updatedBlockTip() {}
virtual void chainStateFlushed(const CBlockLocator& locator) {}
virtual void chainStateFlushed(ChainstateRole role, const CBlockLocator& locator) {}
};
//! Register handler for notifications.

View File

@ -18,6 +18,7 @@
#include <index/blockfilterindex.h>
#include <kernel/mempool_entry.h>
#include <logging.h>
#include <kernel/chain.h>
#include <merkleblock.h>
#include <netbase.h>
#include <netmessagemaker.h>
@ -483,7 +484,7 @@ public:
CTxMemPool& pool, Options opts);
/** Overridden from CValidationInterface. */
void BlockConnected(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_recent_confirmed_transactions_mutex);
void BlockDisconnected(const std::shared_ptr<const CBlock> &block, const CBlockIndex* pindex) override
EXCLUSIVE_LOCKS_REQUIRED(!m_recent_confirmed_transactions_mutex);
@ -1911,7 +1912,10 @@ void PeerManagerImpl::StartScheduledTasks(CScheduler& scheduler)
* announcements for them. Also save the time of the last tip update and
* possibly reduce dynamic block stalling timeout.
*/
void PeerManagerImpl::BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindex)
void PeerManagerImpl::BlockConnected(
ChainstateRole role,
const std::shared_ptr<const CBlock>& pblock,
const CBlockIndex* pindex)
{
m_orphanage.EraseForBlock(*pblock);
m_last_tip_update = GetTime<std::chrono::seconds>();

View File

@ -434,9 +434,9 @@ public:
{
m_notifications->transactionRemovedFromMempool(tx, reason);
}
void BlockConnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* index) override
void BlockConnected(ChainstateRole role, const std::shared_ptr<const CBlock>& block, const CBlockIndex* index) override
{
m_notifications->blockConnected(kernel::MakeBlockInfo(index, block.get()));
m_notifications->blockConnected(role, kernel::MakeBlockInfo(index, block.get()));
}
void BlockDisconnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* index) override
{
@ -446,7 +446,9 @@ public:
{
m_notifications->updatedBlockTip();
}
void ChainStateFlushed(const CBlockLocator& locator) override { m_notifications->chainStateFlushed(locator); }
void ChainStateFlushed(ChainstateRole role, const CBlockLocator& locator) override {
m_notifications->chainStateFlushed(role, locator);
}
std::shared_ptr<Chain::Notifications> m_notifications;
};

View File

@ -105,7 +105,7 @@ BOOST_FIXTURE_TEST_CASE(coinstatsindex_unclean_shutdown, TestChain100Setup)
// Send block connected notification, then stop the index without
// sending a chainstate flushed notification. Prior to #24138, this
// would cause the index to be corrupted and fail to reload.
ValidationInterfaceTest::BlockConnected(index, new_block, new_block_index);
ValidationInterfaceTest::BlockConnected(ChainstateRole::NORMAL, index, new_block, new_block_index);
index.Stop();
}

View File

@ -22,7 +22,11 @@ void TestChainstateManager::JumpOutOfIbd()
Assert(!IsInitialBlockDownload());
}
void ValidationInterfaceTest::BlockConnected(CValidationInterface& obj, const std::shared_ptr<const CBlock>& block, const CBlockIndex* pindex)
void ValidationInterfaceTest::BlockConnected(
ChainstateRole role,
CValidationInterface& obj,
const std::shared_ptr<const CBlock>& block,
const CBlockIndex* pindex)
{
obj.BlockConnected(block, pindex);
obj.BlockConnected(role, block, pindex);
}

View File

@ -19,7 +19,11 @@ struct TestChainstateManager : public ChainstateManager {
class ValidationInterfaceTest
{
public:
static void BlockConnected(CValidationInterface& obj, const std::shared_ptr<const CBlock>& block, const CBlockIndex* pindex);
static void BlockConnected(
ChainstateRole role,
CValidationInterface& obj,
const std::shared_ptr<const CBlock>& block,
const CBlockIndex* pindex);
};
#endif // BITCOIN_TEST_UTIL_VALIDATION_H

View File

@ -43,7 +43,7 @@ struct TestSubscriber final : public CValidationInterface {
BOOST_CHECK_EQUAL(m_expected_tip, pindexNew->GetBlockHash());
}
void BlockConnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* pindex) override
void BlockConnected(ChainstateRole role, const std::shared_ptr<const CBlock>& block, const CBlockIndex* pindex) override
{
BOOST_CHECK_EQUAL(m_expected_tip, block->hashPrevBlock);
BOOST_CHECK_EQUAL(m_expected_tip, pindex->pprev->GetBlockHash());

View File

@ -8,6 +8,7 @@
#include <scheduler.h>
#include <test/util/setup_common.h>
#include <util/check.h>
#include <kernel/chain.h>
#include <validationinterface.h>
#include <atomic>

View File

@ -5,6 +5,7 @@
#include <validation.h>
#include <kernel/chain.h>
#include <kernel/coinstats.h>
#include <kernel/mempool_persist.h>
@ -2645,7 +2646,7 @@ bool Chainstate::FlushStateToDisk(
}
if (full_flush_completed) {
// Update best block in wallet (so we can detect restored wallets).
GetMainSignals().ChainStateFlushed(m_chain.GetLocator());
GetMainSignals().ChainStateFlushed(this->GetRole(), m_chain.GetLocator());
}
} catch (const std::runtime_error& e) {
return FatalError(m_chainman.GetNotifications(), state, std::string("System error while flushing: ") + e.what());
@ -3239,7 +3240,7 @@ bool Chainstate::ActivateBestChain(BlockValidationState& state, std::shared_ptr<
for (const PerBlockConnectTrace& trace : connectTrace.GetBlocksConnected()) {
assert(trace.pblock && trace.pindex);
GetMainSignals().BlockConnected(trace.pblock, trace.pindex);
GetMainSignals().BlockConnected(this->GetRole(), trace.pblock, trace.pindex);
}
// This will have been toggled in

View File

@ -8,6 +8,7 @@
#include <attributes.h>
#include <chain.h>
#include <consensus/validation.h>
#include <kernel/chain.h>
#include <logging.h>
#include <primitives/block.h>
#include <primitives/transaction.h>
@ -223,9 +224,9 @@ void CMainSignals::TransactionRemovedFromMempool(const CTransactionRef& tx, MemP
RemovalReasonToString(reason));
}
void CMainSignals::BlockConnected(const std::shared_ptr<const CBlock> &pblock, const CBlockIndex *pindex) {
auto event = [pblock, pindex, this] {
m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.BlockConnected(pblock, pindex); });
void CMainSignals::BlockConnected(ChainstateRole role, const std::shared_ptr<const CBlock> &pblock, const CBlockIndex *pindex) {
auto event = [role, pblock, pindex, this] {
m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.BlockConnected(role, pblock, pindex); });
};
ENQUEUE_AND_LOG_EVENT(event, "%s: block hash=%s block height=%d", __func__,
pblock->GetHash().ToString(),
@ -242,9 +243,9 @@ void CMainSignals::BlockDisconnected(const std::shared_ptr<const CBlock>& pblock
pindex->nHeight);
}
void CMainSignals::ChainStateFlushed(const CBlockLocator &locator) {
auto event = [locator, this] {
m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.ChainStateFlushed(locator); });
void CMainSignals::ChainStateFlushed(ChainstateRole role, const CBlockLocator &locator) {
auto event = [role, locator, this] {
m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.ChainStateFlushed(role, locator); });
};
ENQUEUE_AND_LOG_EVENT(event, "%s: block hash=%s", __func__,
locator.IsNull() ? "null" : locator.vHave.front().ToString());

View File

@ -7,6 +7,7 @@
#define BITCOIN_VALIDATIONINTERFACE_H
#include <kernel/cs_main.h>
#include <kernel/chain.h>
#include <primitives/transaction.h> // CTransaction(Ref)
#include <sync.h>
@ -136,11 +137,12 @@ protected:
*
* Called on a background thread.
*/
virtual void BlockConnected(const std::shared_ptr<const CBlock> &block, const CBlockIndex *pindex) {}
virtual void BlockConnected(ChainstateRole role, const std::shared_ptr<const CBlock> &block, const CBlockIndex *pindex) {}
/**
* Notifies listeners of a block being disconnected
*
* Called on a background thread.
* Called on a background thread. Only called for the active chainstate, since
* background chainstates should never disconnect blocks.
*/
virtual void BlockDisconnected(const std::shared_ptr<const CBlock> &block, const CBlockIndex* pindex) {}
/**
@ -159,17 +161,18 @@ protected:
*
* Called on a background thread.
*/
virtual void ChainStateFlushed(const CBlockLocator &locator) {}
virtual void ChainStateFlushed(ChainstateRole role, const CBlockLocator &locator) {}
/**
* Notifies listeners of a block validation result.
* If the provided BlockValidationState IsValid, the provided block
* is guaranteed to be the current best block at the time the
* callback was generated (not necessarily now)
* callback was generated (not necessarily now).
*/
virtual void BlockChecked(const CBlock&, const BlockValidationState&) {}
/**
* Notifies listeners that a block which builds directly on our current tip
* has been received and connected to the headers tree, though not validated yet */
* has been received and connected to the headers tree, though not validated yet.
*/
virtual void NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock>& block) {};
friend class CMainSignals;
friend class ValidationInterfaceTest;
@ -199,9 +202,9 @@ public:
void UpdatedBlockTip(const CBlockIndex *, const CBlockIndex *, bool fInitialDownload);
void TransactionAddedToMempool(const CTransactionRef&, uint64_t mempool_sequence);
void TransactionRemovedFromMempool(const CTransactionRef&, MemPoolRemovalReason, uint64_t mempool_sequence);
void BlockConnected(const std::shared_ptr<const CBlock> &, const CBlockIndex *pindex);
void BlockConnected(ChainstateRole, const std::shared_ptr<const CBlock> &, const CBlockIndex *pindex);
void BlockDisconnected(const std::shared_ptr<const CBlock> &, const CBlockIndex* pindex);
void ChainStateFlushed(const CBlockLocator &);
void ChainStateFlushed(ChainstateRole, const CBlockLocator &);
void BlockChecked(const CBlock&, const BlockValidationState&);
void NewPoWValidBlock(const CBlockIndex *, const std::shared_ptr<const CBlock>&);
};

View File

@ -2,6 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <kernel/chain.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
@ -145,8 +146,8 @@ FUZZ_TARGET(wallet_notifications, .init = initialize_setup)
// time to the maximum value. This ensures that the wallet's birth time is always
// earlier than this maximum time.
info.chain_time_max = std::numeric_limits<unsigned int>::max();
a.wallet->blockConnected(info);
b.wallet->blockConnected(info);
a.wallet->blockConnected(ChainstateRole::NORMAL, info);
b.wallet->blockConnected(ChainstateRole::NORMAL, info);
// Store the coins for the next block
Coins coins_new;
for (const auto& tx : block.vtx) {

View File

@ -22,6 +22,7 @@
#include <interfaces/chain.h>
#include <interfaces/handler.h>
#include <interfaces/wallet.h>
#include <kernel/chain.h>
#include <kernel/mempool_removal_reason.h>
#include <key.h>
#include <key_io.h>
@ -626,7 +627,7 @@ bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase,
return false;
}
void CWallet::chainStateFlushed(const CBlockLocator& loc)
void CWallet::chainStateFlushed(ChainstateRole role, const CBlockLocator& loc)
{
// Don't update the best block until the chain is attached so that in case of a shutdown,
// the rescan will be restarted at next startup.
@ -1462,7 +1463,7 @@ void CWallet::transactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRe
}
}
void CWallet::blockConnected(const interfaces::BlockInfo& block)
void CWallet::blockConnected(ChainstateRole role, const interfaces::BlockInfo& block)
{
assert(block.data);
LOCK(cs_wallet);
@ -2941,7 +2942,7 @@ std::shared_ptr<CWallet> CWallet::Create(WalletContext& context, const std::stri
}
if (chain) {
walletInstance->chainStateFlushed(chain->getTipLocator());
walletInstance->chainStateFlushed(ChainstateRole::NORMAL, chain->getTipLocator());
}
} else if (wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS) {
// Make it impossible to disable private keys after creation
@ -3227,7 +3228,7 @@ bool CWallet::AttachChain(const std::shared_ptr<CWallet>& walletInstance, interf
}
}
walletInstance->m_attaching_chain = false;
walletInstance->chainStateFlushed(chain.getTipLocator());
walletInstance->chainStateFlushed(ChainstateRole::NORMAL, chain.getTipLocator());
walletInstance->GetDatabase().IncrementUpdateCounter();
}
walletInstance->m_attaching_chain = false;

View File

@ -599,7 +599,7 @@ public:
CWalletTx* AddToWallet(CTransactionRef tx, const TxState& state, const UpdateWalletTxFn& update_wtx=nullptr, bool fFlushOnClose=true, bool rescanning_old_block = false);
bool LoadToWallet(const uint256& hash, const UpdateWalletTxFn& fill_wtx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
void transactionAddedToMempool(const CTransactionRef& tx) override;
void blockConnected(const interfaces::BlockInfo& block) override;
void blockConnected(ChainstateRole role, const interfaces::BlockInfo& block) override;
void blockDisconnected(const interfaces::BlockInfo& block) override;
void updatedBlockTip() override;
int64_t RescanFromTime(int64_t startTime, const WalletRescanReserver& reserver, bool update);
@ -777,7 +777,7 @@ public:
/** should probably be renamed to IsRelevantToMe */
bool IsFromMe(const CTransaction& tx) const;
CAmount GetDebit(const CTransaction& tx, const isminefilter& filter) const;
void chainStateFlushed(const CBlockLocator& loc) override;
void chainStateFlushed(ChainstateRole role, const CBlockLocator& loc) override;
DBErrors LoadWallet();
DBErrors ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256>& vHashOut) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);

View File

@ -5,6 +5,7 @@
#include <zmq/zmqnotificationinterface.h>
#include <common/args.h>
#include <kernel/chain.h>
#include <logging.h>
#include <primitives/block.h>
#include <primitives/transaction.h>
@ -170,7 +171,7 @@ void CZMQNotificationInterface::TransactionRemovedFromMempool(const CTransaction
});
}
void CZMQNotificationInterface::BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindexConnected)
void CZMQNotificationInterface::BlockConnected(ChainstateRole role, const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindexConnected)
{
for (const CTransactionRef& ptx : pblock->vtx) {
const CTransaction& tx = *ptx;

View File

@ -33,7 +33,7 @@ protected:
// CValidationInterface
void TransactionAddedToMempool(const CTransactionRef& tx, uint64_t mempool_sequence) override;
void TransactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason, uint64_t mempool_sequence) override;
void BlockConnected(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;
void BlockDisconnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindexDisconnected) override;
void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) override;