Coverage Report

Created: 2025-03-27 15:33

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