Coverage Report

Created: 2025-09-08 17:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/root/bitcoin/src/validationinterface.cpp
Line
Count
Source
1
// Copyright (c) 2009-2010 Satoshi Nakamoto
2
// Copyright (c) 2009-2022 The Bitcoin Core developers
3
// Distributed under the MIT software license, see the accompanying
4
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
6
#include <validationinterface.h>
7
8
#include <chain.h>
9
#include <consensus/validation.h>
10
#include <kernel/chain.h>
11
#include <kernel/mempool_entry.h>
12
#include <kernel/mempool_removal_reason.h>
13
#include <logging.h>
14
#include <primitives/block.h>
15
#include <primitives/transaction.h>
16
#include <util/check.h>
17
#include <util/task_runner.h>
18
19
#include <future>
20
#include <memory>
21
#include <unordered_map>
22
#include <utility>
23
24
/**
25
 * ValidationSignalsImpl manages a list of shared_ptr<CValidationInterface> callbacks.
26
 *
27
 * A std::unordered_map is used to track what callbacks are currently
28
 * registered, and a std::list is used to store the callbacks that are
29
 * currently registered as well as any callbacks that are just unregistered
30
 * and about to be deleted when they are done executing.
31
 */
32
class ValidationSignalsImpl
33
{
34
private:
35
    Mutex m_mutex;
36
    //! List entries consist of a callback pointer and reference count. The
37
    //! count is equal to the number of current executions of that entry, plus 1
38
    //! if it's registered. It cannot be 0 because that would imply it is
39
    //! unregistered and also not being executed (so shouldn't exist).
40
    struct ListEntry { std::shared_ptr<CValidationInterface> callbacks; int count = 1; };
41
    std::list<ListEntry> m_list GUARDED_BY(m_mutex);
42
    std::unordered_map<CValidationInterface*, std::list<ListEntry>::iterator> m_map GUARDED_BY(m_mutex);
43
44
public:
45
    std::unique_ptr<util::TaskRunnerInterface> m_task_runner;
46
47
    explicit ValidationSignalsImpl(std::unique_ptr<util::TaskRunnerInterface> task_runner)
48
769
        : m_task_runner{std::move(Assert(task_runner))} {}
49
50
    void Register(std::shared_ptr<CValidationInterface> callbacks) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
51
312k
    {
52
312k
        LOCK(m_mutex);
53
312k
        auto inserted = m_map.emplace(callbacks.get(), m_list.end());
54
312k
        if (inserted.second) inserted.first->second = m_list.emplace(m_list.end());
55
312k
        inserted.first->second->callbacks = std::move(callbacks);
56
312k
    }
57
58
    void Unregister(CValidationInterface* callbacks) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
59
312k
    {
60
312k
        LOCK(m_mutex);
61
312k
        auto it = m_map.find(callbacks);
62
312k
        if (it != m_map.end()) {
63
312k
            if (!--it->second->count) m_list.erase(it->second);
64
312k
            m_map.erase(it);
65
312k
        }
66
312k
    }
67
68
    //! Clear unregisters every previously registered callback, erasing every
69
    //! map entry. After this call, the list may still contain callbacks that
70
    //! are currently executing, but it will be cleared when they are done
71
    //! executing.
72
    void Clear() EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
73
0
    {
74
0
        LOCK(m_mutex);
75
0
        for (const auto& entry : m_map) {
76
0
            if (!--entry.second->count) m_list.erase(entry.second);
77
0
        }
78
0
        m_map.clear();
79
0
    }
80
81
    template<typename F> void Iterate(F&& f) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
82
840k
    {
83
840k
        WAIT_LOCK(m_mutex, lock);
84
1.59M
        for (auto it = m_list.begin(); it != m_list.end();) {
85
755k
            ++it->count;
86
755k
            {
87
755k
                REVERSE_LOCK(lock, m_mutex);
88
755k
                f(*it->callbacks);
89
755k
            }
90
755k
            it = --it->count ? std::next(it) : m_list.erase(it);
91
755k
        }
92
840k
    }
validationinterface.cpp:_ZN21ValidationSignalsImpl7IterateIZZN17ValidationSignals15UpdatedBlockTipEPK11CBlockIndexS4_bENK3$_1clEvEUlR20CValidationInterfaceE_EEvOT_
Line
Count
Source
82
106k
    {
83
106k
        WAIT_LOCK(m_mutex, lock);
84
212k
        for (auto it = m_list.begin(); it != m_list.end();) {
85
105k
            ++it->count;
86
105k
            {
87
105k
                REVERSE_LOCK(lock, m_mutex);
88
105k
                f(*it->callbacks);
89
105k
            }
90
105k
            it = --it->count ? std::next(it) : m_list.erase(it);
91
105k
        }
92
106k
    }
validationinterface.cpp:_ZN21ValidationSignalsImpl7IterateIZN17ValidationSignals15ActiveTipChangeERK11CBlockIndexbE3$_0EEvOT_
Line
Count
Source
82
113k
    {
83
113k
        WAIT_LOCK(m_mutex, lock);
84
225k
        for (auto it = m_list.begin(); it != m_list.end();) {
85
112k
            ++it->count;
86
112k
            {
87
112k
                REVERSE_LOCK(lock, m_mutex);
88
112k
                f(*it->callbacks);
89
112k
            }
90
112k
            it = --it->count ? std::next(it) : m_list.erase(it);
91
112k
        }
92
113k
    }
validationinterface.cpp:_ZN21ValidationSignalsImpl7IterateIZZN17ValidationSignals25TransactionAddedToMempoolERK25NewMempoolTransactionInfomENK3$_1clEvEUlR20CValidationInterfaceE_EEvOT_
Line
Count
Source
82
101k
    {
83
101k
        WAIT_LOCK(m_mutex, lock);
84
192k
        for (auto it = m_list.begin(); it != m_list.end();) {
85
90.5k
            ++it->count;
86
90.5k
            {
87
90.5k
                REVERSE_LOCK(lock, m_mutex);
88
90.5k
                f(*it->callbacks);
89
90.5k
            }
90
90.5k
            it = --it->count ? std::next(it) : m_list.erase(it);
91
90.5k
        }
92
101k
    }
validationinterface.cpp:_ZN21ValidationSignalsImpl7IterateIZZN17ValidationSignals29TransactionRemovedFromMempoolERKSt10shared_ptrIK12CTransactionE20MemPoolRemovalReasonmENK3$_1clEvEUlR20CValidationInterfaceE_EEvOT_
Line
Count
Source
82
54.0k
    {
83
54.0k
        WAIT_LOCK(m_mutex, lock);
84
108k
        for (auto it = m_list.begin(); it != m_list.end();) {
85
54.2k
            ++it->count;
86
54.2k
            {
87
54.2k
                REVERSE_LOCK(lock, m_mutex);
88
54.2k
                f(*it->callbacks);
89
54.2k
            }
90
54.2k
            it = --it->count ? std::next(it) : m_list.erase(it);
91
54.2k
        }
92
54.0k
    }
validationinterface.cpp:_ZN21ValidationSignalsImpl7IterateIZZN17ValidationSignals14BlockConnectedE14ChainstateRoleRKSt10shared_ptrIK6CBlockEPK11CBlockIndexENK3$_1clEvEUlR20CValidationInterfaceE_EEvOT_
Line
Count
Source
82
106k
    {
83
106k
        WAIT_LOCK(m_mutex, lock);
84
212k
        for (auto it = m_list.begin(); it != m_list.end();) {
85
105k
            ++it->count;
86
105k
            {
87
105k
                REVERSE_LOCK(lock, m_mutex);
88
105k
                f(*it->callbacks);
89
105k
            }
90
105k
            it = --it->count ? std::next(it) : m_list.erase(it);
91
105k
        }
92
106k
    }
validationinterface.cpp:_ZN21ValidationSignalsImpl7IterateIZZN17ValidationSignals34MempoolTransactionsRemovedForBlockERKSt6vectorI29RemovedMempoolTransactionInfoSaIS3_EEjENK3$_1clEvEUlR20CValidationInterfaceE_EEvOT_
Line
Count
Source
82
106k
    {
83
106k
        WAIT_LOCK(m_mutex, lock);
84
212k
        for (auto it = m_list.begin(); it != m_list.end();) {
85
105k
            ++it->count;
86
105k
            {
87
105k
                REVERSE_LOCK(lock, m_mutex);
88
105k
                f(*it->callbacks);
89
105k
            }
90
105k
            it = --it->count ? std::next(it) : m_list.erase(it);
91
105k
        }
92
106k
    }
Unexecuted instantiation: validationinterface.cpp:_ZN21ValidationSignalsImpl7IterateIZZN17ValidationSignals17BlockDisconnectedERKSt10shared_ptrIK6CBlockEPK11CBlockIndexENK3$_1clEvEUlR20CValidationInterfaceE_EEvOT_
validationinterface.cpp:_ZN21ValidationSignalsImpl7IterateIZZN17ValidationSignals17ChainStateFlushedE14ChainstateRoleRK13CBlockLocatorENK3$_1clEvEUlR20CValidationInterfaceE_EEvOT_
Line
Count
Source
82
68.1k
    {
83
68.1k
        WAIT_LOCK(m_mutex, lock);
84
68.1k
        for (auto it = m_list.begin(); it != m_list.end();) {
85
48
            ++it->count;
86
48
            {
87
48
                REVERSE_LOCK(lock, m_mutex);
88
48
                f(*it->callbacks);
89
48
            }
90
48
            it = --it->count ? std::next(it) : m_list.erase(it);
91
48
        }
92
68.1k
    }
validationinterface.cpp:_ZN21ValidationSignalsImpl7IterateIZN17ValidationSignals12BlockCheckedERKSt10shared_ptrIK6CBlockERK20BlockValidationStateE3$_0EEvOT_
Line
Count
Source
82
123k
    {
83
123k
        WAIT_LOCK(m_mutex, lock);
84
244k
        for (auto it = m_list.begin(); it != m_list.end();) {
85
121k
            ++it->count;
86
121k
            {
87
121k
                REVERSE_LOCK(lock, m_mutex);
88
121k
                f(*it->callbacks);
89
121k
            }
90
121k
            it = --it->count ? std::next(it) : m_list.erase(it);
91
121k
        }
92
123k
    }
validationinterface.cpp:_ZN21ValidationSignalsImpl7IterateIZN17ValidationSignals16NewPoWValidBlockEPK11CBlockIndexRKSt10shared_ptrIK6CBlockEE3$_0EEvOT_
Line
Count
Source
82
60.3k
    {
83
60.3k
        WAIT_LOCK(m_mutex, lock);
84
120k
        for (auto it = m_list.begin(); it != m_list.end();) {
85
60.3k
            ++it->count;
86
60.3k
            {
87
60.3k
                REVERSE_LOCK(lock, m_mutex);
88
60.3k
                f(*it->callbacks);
89
60.3k
            }
90
60.3k
            it = --it->count ? std::next(it) : m_list.erase(it);
91
60.3k
        }
92
60.3k
    }
93
};
94
95
ValidationSignals::ValidationSignals(std::unique_ptr<util::TaskRunnerInterface> task_runner)
96
769
    : m_internals{std::make_unique<ValidationSignalsImpl>(std::move(task_runner))} {}
97
98
791
ValidationSignals::~ValidationSignals() = default;
99
100
void ValidationSignals::FlushBackgroundCallbacks()
101
791
{
102
791
    m_internals->m_task_runner->flush();
103
791
}
104
105
size_t ValidationSignals::CallbacksPending()
106
122k
{
107
122k
    return m_internals->m_task_runner->size();
108
122k
}
109
110
void ValidationSignals::RegisterSharedValidationInterface(std::shared_ptr<CValidationInterface> callbacks)
111
312k
{
112
    // Each connection captures the shared_ptr to ensure that each callback is
113
    // executed before the subscriber is destroyed. For more details see #18338.
114
312k
    m_internals->Register(std::move(callbacks));
115
312k
}
116
117
void ValidationSignals::RegisterValidationInterface(CValidationInterface* callbacks)
118
121k
{
119
    // Create a shared_ptr with a no-op deleter - CValidationInterface lifecycle
120
    // is managed by the caller.
121
121k
    RegisterSharedValidationInterface({callbacks, [](CValidationInterface*){}});
122
121k
}
123
124
void ValidationSignals::UnregisterSharedValidationInterface(std::shared_ptr<CValidationInterface> callbacks)
125
191k
{
126
191k
    UnregisterValidationInterface(callbacks.get());
127
191k
}
128
129
void ValidationSignals::UnregisterValidationInterface(CValidationInterface* callbacks)
130
312k
{
131
312k
    m_internals->Unregister(callbacks);
132
312k
}
133
134
void ValidationSignals::UnregisterAllValidationInterfaces()
135
0
{
136
0
    m_internals->Clear();
137
0
}
138
139
void ValidationSignals::CallFunctionInValidationInterfaceQueue(std::function<void()> func)
140
455k
{
141
455k
    m_internals->m_task_runner->insert(std::move(func));
142
455k
}
143
144
void ValidationSignals::SyncWithValidationInterfaceQueue()
145
455k
{
146
455k
    AssertLockNotHeld(cs_main);
147
    // Block until the validation queue drains
148
455k
    std::promise<void> promise;
149
455k
    CallFunctionInValidationInterfaceQueue([&promise] {
150
455k
        promise.set_value();
151
455k
    });
152
455k
    promise.get_future().wait();
153
455k
}
154
155
// Use a macro instead of a function for conditional logging to prevent
156
// evaluating arguments when logging is not enabled.
157
//
158
// NOTE: The lambda captures all local variables by value.
159
#define ENQUEUE_AND_LOG_EVENT(event, fmt, name, ...)           \
160
543k
    do {                                                       \
161
543k
        auto local_name = (name);                              \
162
543k
        LOG_EVENT("Enqueuing " fmt, local_name, __VA_ARGS__);  \
163
543k
        m_internals->m_task_runner->insert([=] { \
164
543k
            LOG_EVENT(fmt, local_name, __VA_ARGS__);           \
165
543k
            event();                                           \
166
543k
        });                                                    \
validationinterface.cpp:_ZZN17ValidationSignals15UpdatedBlockTipEPK11CBlockIndexS2_bENK3$_0clEv
Line
Count
Source
163
106k
        m_internals->m_task_runner->insert([=] { \
164
106k
            LOG_EVENT(fmt, local_name, __VA_ARGS__);           \
165
106k
            event();                                           \
166
106k
        });                                                    \
validationinterface.cpp:_ZZN17ValidationSignals25TransactionAddedToMempoolERK25NewMempoolTransactionInfomENK3$_0clEv
Line
Count
Source
163
101k
        m_internals->m_task_runner->insert([=] { \
164
101k
            LOG_EVENT(fmt, local_name, __VA_ARGS__);           \
165
101k
            event();                                           \
166
101k
        });                                                    \
validationinterface.cpp:_ZZN17ValidationSignals29TransactionRemovedFromMempoolERKSt10shared_ptrIK12CTransactionE20MemPoolRemovalReasonmENK3$_0clEv
Line
Count
Source
163
54.0k
        m_internals->m_task_runner->insert([=] { \
164
54.0k
            LOG_EVENT(fmt, local_name, __VA_ARGS__);           \
165
54.0k
            event();                                           \
166
54.0k
        });                                                    \
validationinterface.cpp:_ZZN17ValidationSignals14BlockConnectedE14ChainstateRoleRKSt10shared_ptrIK6CBlockEPK11CBlockIndexENK3$_0clEv
Line
Count
Source
163
106k
        m_internals->m_task_runner->insert([=] { \
164
106k
            LOG_EVENT(fmt, local_name, __VA_ARGS__);           \
165
106k
            event();                                           \
166
106k
        });                                                    \
validationinterface.cpp:_ZZN17ValidationSignals34MempoolTransactionsRemovedForBlockERKSt6vectorI29RemovedMempoolTransactionInfoSaIS1_EEjENK3$_0clEv
Line
Count
Source
163
106k
        m_internals->m_task_runner->insert([=] { \
164
106k
            LOG_EVENT(fmt, local_name, __VA_ARGS__);           \
165
106k
            event();                                           \
166
106k
        });                                                    \
Unexecuted instantiation: validationinterface.cpp:_ZZN17ValidationSignals17BlockDisconnectedERKSt10shared_ptrIK6CBlockEPK11CBlockIndexENK3$_0clEv
validationinterface.cpp:_ZZN17ValidationSignals17ChainStateFlushedE14ChainstateRoleRK13CBlockLocatorENK3$_0clEv
Line
Count
Source
163
68.1k
        m_internals->m_task_runner->insert([=] { \
164
68.1k
            LOG_EVENT(fmt, local_name, __VA_ARGS__);           \
165
68.1k
            event();                                           \
166
68.1k
        });                                                    \
167
543k
    } while (0)
168
169
#define LOG_EVENT(fmt, ...) \
170
1.38M
    LogDebug(BCLog::VALIDATION, fmt "\n", __VA_ARGS__)
171
172
106k
void ValidationSignals::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) {
173
    // Dependencies exist that require UpdatedBlockTip events to be delivered in the order in which
174
    // the chain actually updates. One way to ensure this is for the caller to invoke this signal
175
    // in the same critical section where the chain is updated
176
177
106k
    auto event = [pindexNew, pindexFork, fInitialDownload, this] {
178
106k
        m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.UpdatedBlockTip(pindexNew, pindexFork, fInitialDownload); });
179
106k
    };
180
106k
    ENQUEUE_AND_LOG_EVENT(event, "%s: new block hash=%s fork block hash=%s (in IBD=%s)", __func__,
181
106k
                          pindexNew->GetBlockHash().ToString(),
182
106k
                          pindexFork ? pindexFork->GetBlockHash().ToString() : "null",
183
106k
                          fInitialDownload);
184
106k
}
185
186
void ValidationSignals::ActiveTipChange(const CBlockIndex& new_tip, bool is_ibd)
187
113k
{
188
113k
    LOG_EVENT("%s: new block hash=%s block height=%d", __func__, new_tip.GetBlockHash().ToString(), new_tip.nHeight);
189
113k
    m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.ActiveTipChange(new_tip, is_ibd); });
190
113k
}
191
192
void ValidationSignals::TransactionAddedToMempool(const NewMempoolTransactionInfo& tx, uint64_t mempool_sequence)
193
101k
{
194
101k
    auto event = [tx, mempool_sequence, this] {
195
101k
        m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.TransactionAddedToMempool(tx, mempool_sequence); });
196
101k
    };
197
101k
    ENQUEUE_AND_LOG_EVENT(event, "%s: txid=%s wtxid=%s", __func__,
198
101k
                          tx.info.m_tx->GetHash().ToString(),
199
101k
                          tx.info.m_tx->GetWitnessHash().ToString());
200
101k
}
201
202
54.0k
void ValidationSignals::TransactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason, uint64_t mempool_sequence) {
203
54.0k
    auto event = [tx, reason, mempool_sequence, this] {
204
54.2k
        m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.TransactionRemovedFromMempool(tx, reason, mempool_sequence); });
205
54.0k
    };
206
54.0k
    ENQUEUE_AND_LOG_EVENT(event, "%s: txid=%s wtxid=%s reason=%s", __func__,
207
54.0k
                          tx->GetHash().ToString(),
208
54.0k
                          tx->GetWitnessHash().ToString(),
209
54.0k
                          RemovalReasonToString(reason));
210
54.0k
}
211
212
106k
void ValidationSignals::BlockConnected(ChainstateRole role, const std::shared_ptr<const CBlock> &pblock, const CBlockIndex *pindex) {
213
106k
    auto event = [role, pblock, pindex, this] {
214
106k
        m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.BlockConnected(role, pblock, pindex); });
215
106k
    };
216
106k
    ENQUEUE_AND_LOG_EVENT(event, "%s: block hash=%s block height=%d", __func__,
217
106k
                          pblock->GetHash().ToString(),
218
106k
                          pindex->nHeight);
219
106k
}
220
221
void ValidationSignals::MempoolTransactionsRemovedForBlock(const std::vector<RemovedMempoolTransactionInfo>& txs_removed_for_block, unsigned int nBlockHeight)
222
106k
{
223
106k
    auto event = [txs_removed_for_block, nBlockHeight, this] {
224
106k
        m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.MempoolTransactionsRemovedForBlock(txs_removed_for_block, nBlockHeight); });
225
106k
    };
226
106k
    ENQUEUE_AND_LOG_EVENT(event, "%s: block height=%s txs removed=%s", __func__,
227
106k
                          nBlockHeight,
228
106k
                          txs_removed_for_block.size());
229
106k
}
230
231
void ValidationSignals::BlockDisconnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindex)
232
0
{
233
0
    auto event = [pblock, pindex, this] {
234
0
        m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.BlockDisconnected(pblock, pindex); });
235
0
    };
236
0
    ENQUEUE_AND_LOG_EVENT(event, "%s: block hash=%s block height=%d", __func__,
237
0
                          pblock->GetHash().ToString(),
238
0
                          pindex->nHeight);
239
0
}
240
241
68.1k
void ValidationSignals::ChainStateFlushed(ChainstateRole role, const CBlockLocator &locator) {
242
68.1k
    auto event = [role, locator, this] {
243
68.1k
        m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.ChainStateFlushed(role, locator); });
244
68.1k
    };
245
68.1k
    ENQUEUE_AND_LOG_EVENT(event, "%s: block hash=%s", __func__,
246
68.1k
                          locator.IsNull() ? "null" : locator.vHave.front().ToString());
247
68.1k
}
248
249
void ValidationSignals::BlockChecked(const std::shared_ptr<const CBlock>& block, const BlockValidationState& state)
250
123k
{
251
123k
    LOG_EVENT("%s: block hash=%s state=%s", __func__,
252
123k
              block->GetHash().ToString(), state.ToString());
253
123k
    m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.BlockChecked(block, state); });
254
123k
}
255
256
60.3k
void ValidationSignals::NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock> &block) {
257
60.3k
    LOG_EVENT("%s: block hash=%s", __func__, block->GetHash().ToString());
258
60.3k
    m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.NewPoWValidBlock(pindex, block); });
259
60.3k
}