• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

libbitcoin / libbitcoin-node / 41739527542

03 Nov 2026 11:29PM UTC coverage: 91.876% (-0.2%) from 92.07%
41739527542

push

github

web-flow
Merge pull request #1244 from evoskuil/master

Initialize bases and members in declaration order.

26 of 26 new or added lines in 12 files covered. (100.0%)

35 existing lines in 13 files now uncovered.

4275 of 4653 relevant lines covered (91.88%)

5183.64 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

91.67
/src/full_node.cpp
1
/**
2
 * Copyright (c) 2011-2026 libbitcoin developers
3
 *
4
 * This file is part of libbitcoin.
5
 *
6
 * This program is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU Affero General Public License as published by
8
 * the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU Affero General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Affero General Public License
17
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
 */
19
#include <bitcoin/node/full_node.hpp>
20

21
#include <bitcoin/node/chasers/chasers.hpp>
22
#include <bitcoin/node/define.hpp>
23
#include <bitcoin/node/estimator.hpp>
24
#include <bitcoin/node/sessions/sessions.hpp>
25

26
namespace libbitcoin {
27
namespace node {
28

29
using namespace system;
30
using namespace database;
31
using namespace network;
32
using namespace std::placeholders;
33

34
BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
35

36
// net::strand() is safe to call from constructor (non-virtual).
37
full_node::full_node(query& query, const configuration& configuration,
354 ✔
38
    const logger& log) NOEXCEPT
354 ✔
39
  : net(configuration.network, log, configuration.node.services_required(),
354 ✔
40
        configuration.node.services_provided()),
41
    config_(configuration),
354 ✔
42
    start_time_(zulu_time()),
708 ✔
43
    query_(query),
354 ✔
44
    chaser_header_(*this),
354 ✔
45
    chaser_download_(*this),
354 ✔
46
    chaser_validate_(*this),
354 ✔
47
    chaser_confirm_(*this),
354 ✔
48
    chaser_transaction_(*this),
354 ✔
49
    chaser_template_(*this),
354 ✔
50
    chaser_estimate_(*this),
354 ✔
51
    chaser_snapshot_(*this),
354 ✔
52
    chaser_storage_(*this)
708 ✔
53
{
54
}
354 ✔
55

56
full_node::~full_node() NOEXCEPT
354 ✔
57
{
58
}
354 ✔
59

60
// Sequences.
61
// ----------------------------------------------------------------------------
62

63
void full_node::start(result_handler&& handler) NOEXCEPT
347 ✔
64
{
65
    if (!query_.is_initialized())
347 ✔
66
    {
67
        handler(error::store_uninitialized);
1 ✔
68
        return;
1 ✔
69
    }
70

71
    // Base (net) invokes do_start().
72
    net::start(std::move(handler));
346 ✔
73
}
74

75
void full_node::do_start(const result_handler& handler) NOEXCEPT
285 ✔
76
{
77
    BC_ASSERT(stranded());
285 ✔
78
    code ec{};
285 ✔
79

80
    if (((ec = chaser_header_.start())) ||
285 ✔
81
        ((ec = chaser_download_.start())) ||
284 ✔
82
        ((ec = chaser_validate_.start())) ||
284 ✔
83
        ((ec = chaser_confirm_.start())) ||
284 ✔
84
        ((ec = chaser_transaction_.start())) ||
284 ✔
85
        ((ec = chaser_template_.start())) ||
284 ✔
86
        ((ec = chaser_estimate_.start())) ||
284 ✔
87
        ((ec = chaser_snapshot_.start())) ||
569 ✔
88
        ((ec = chaser_storage_.start())))
284 ✔
89
    {
90
        handler(ec);
1 ✔
91
        return;
1 ✔
92
    }
93

94
    net::do_start(handler);
284 ✔
95
}
96

97
void full_node::run(result_handler&& handler) NOEXCEPT
338 ✔
98
{
99
    // Base (net) invokes do_run().
100
    net::run(std::move(handler));
338 ✔
101
}
338 ✔
102

103
void full_node::do_run(const result_handler& handler) NOEXCEPT
276 ✔
104
{
105
    BC_ASSERT(stranded());
276 ✔
106

107
    if (closed())
276 ✔
108
    {
109
        handler(network::error::service_stopped);
1 ✔
110
        return;
1 ✔
111
    }
112

113
    // Bump sequential chasers to their starting heights.
114
    // This will kick off lagging validations even if not current.
115
    do_notify(error::success, chases::start{});
275 ✔
116

117
    // Start services after network is running.
118
    net::do_run(handler);
275 ✔
119
}
120

121
void full_node::close() NOEXCEPT
354 ✔
122
{
123
    // Base (net) invokes do_close().
124
    net::close();
354 ✔
125

126
    // Block on chaser stop (including dedicated threadpool joins).
127
    chaser_header_.stop();
354 ✔
128
    chaser_download_.stop();
354 ✔
129
    chaser_validate_.stop();
354 ✔
130
    chaser_confirm_.stop();
354 ✔
131
    chaser_transaction_.stop();
354 ✔
132
    chaser_template_.stop();
354 ✔
133
    chaser_estimate_.stop();
354 ✔
134
    chaser_snapshot_.stop();
354 ✔
135
    chaser_storage_.stop();
354 ✔
136
}
354 ✔
137

138
// Base (net) invokes do_close().
139
void full_node::do_close() NOEXCEPT
354 ✔
140
{
141
    BC_ASSERT(stranded());
354 ✔
142

143
    // Initiate chaser stopping (including dedicated threadpools).
144
    chaser_header_.stopping(network::error::service_stopped);
354 ✔
145
    chaser_download_.stopping(network::error::service_stopped);
354 ✔
146
    chaser_validate_.stopping(network::error::service_stopped);
354 ✔
147
    chaser_confirm_.stopping(network::error::service_stopped);
354 ✔
148
    chaser_transaction_.stopping(network::error::service_stopped);
354 ✔
149
    chaser_template_.stopping(network::error::service_stopped);
354 ✔
150
    chaser_estimate_.stopping(network::error::service_stopped);
354 ✔
151
    chaser_snapshot_.stopping(network::error::service_stopped);
354 ✔
152
    chaser_storage_.stopping(network::error::service_stopped);
354 ✔
153

154
    event_subscriber_.stop(network::error::service_stopped, chases::stop{});
354 ✔
155
    net::do_close();
354 ✔
156
}
354 ✔
157

158
// Organizers.
159
// ----------------------------------------------------------------------------
160

161
void full_node::organize(const system::chain::header::cptr& header,
3 ✔
162
    organize_handler&& handler) NOEXCEPT
163
{
164
    chaser_header_.organize(header, std::move(handler));
3 ✔
165
}
3 ✔
166

167
void full_node::organize(const system::chain::header::cptr& header,
6,012 ✔
168
    bool milestone, organize_handler&& handler) NOEXCEPT
169
{
170
    chaser_header_.organize(header, milestone, std::move(handler));
6,012 ✔
171
}
6,012 ✔
172

173
void full_node::organize_compact(const system::chain::header::cptr& header,
6 ✔
174
    organize_handler&& handler) NOEXCEPT
175
{
176
    chaser_header_.organize_compact(header, std::move(handler));
6 ✔
177
}
6 ✔
178

179
void full_node::prioritize(const system::hash_digest& hash,
3 ✔
180
    organize_handler&& handler) NOEXCEPT
181
{
182
    chaser_header_.prioritize(hash, std::move(handler));
3 ✔
183
}
3 ✔
184

185
void full_node::get_minimum_work(work_handler&& handler) NOEXCEPT
66 ✔
186
{
187
    chaser_header_.get_minimum_work(std::move(handler));
66 ✔
188
}
66 ✔
189

190
void full_node::submit(const system::chain::transactions_cptr& txs, bool test,
44 ✔
191
    submit_handler&& handler) NOEXCEPT
192
{
193
    chaser_transaction_.submit(txs, test, std::move(handler));
44 ✔
194
}
44 ✔
195

196
void full_node::submit_compact(const system::chain::transactions_cptr& txs,
5 ✔
197
    const database::tx_links& links, const database::header_link& link,
198
    submit_handler&& handler) NOEXCEPT
199
{
200
    chaser_transaction_.submit_compact(txs, links, link, std::move(handler));
5 ✔
201
}
5 ✔
202

203
void full_node::get_hashes(map_handler&& handler) NOEXCEPT
64 ✔
204
{
205
    chaser_download_.get_hashes(std::move(handler));
64 ✔
206
}
64 ✔
207

208
void full_node::put_hashes(const map_ptr& map,
27 ✔
209
    result_handler&& handler) NOEXCEPT
210
{
211
    chaser_download_.put_hashes(map, std::move(handler));
27 ✔
212
}
27 ✔
213

214
// Events.
215
// ----------------------------------------------------------------------------
216

217
void full_node::notify(const code& ec, event_value value) NOEXCEPT
6,781 ✔
218
{
219
    network::io::post(strand(),
6,781 ✔
220
        std::bind(&full_node::do_notify,
13,562 ✔
221
            this, ec, value));
6,781 ✔
222
}
6,781 ✔
223

224
// private
225
void full_node::do_notify(const code& ec, event_value value) NOEXCEPT
7,056 ✔
226
{
227
    BC_ASSERT(stranded());
7,056 ✔
228
    event_subscriber_.notify(ec, value);
7,056 ✔
229
}
7,056 ✔
230

231
void full_node::notify_one(object_key key, const code& ec,
506 ✔
232
    event_value value) NOEXCEPT
233
{
234
    network::io::post(strand(),
506 ✔
235
        std::bind(&full_node::do_notify_one,
1,012 ✔
236
            this, key, ec, value));
506 ✔
237
}
506 ✔
238

239
// private
240
void full_node::do_notify_one(object_key key, const code& ec,
506 ✔
241
    event_value value) NOEXCEPT
242
{
243
    BC_ASSERT(stranded());
506 ✔
244
    event_subscriber_.notify_one(key, ec, value);
506 ✔
245
}
506 ✔
246

247
object_key full_node::subscribe_chase(event_notifier&& handler) NOEXCEPT
2,363 ✔
248
{
249
    BC_ASSERT(stranded());
2,363 ✔
250
    const auto key = create_key();
2,363 ✔
251
    event_subscriber_.subscribe(std::move(handler), key);
2,363 ✔
252
    return key;
2,363 ✔
253
}
254

255
void full_node::subscribe_chase(event_notifier&& handler,
476 ✔
256
    event_completer&& complete) NOEXCEPT
257
{
258
    network::io::post(strand(),
476 ✔
259
        std::bind(&full_node::do_subscribe_chase,
476 ✔
260
            this, std::move(handler), std::move(complete)));
476 ✔
261
}
476 ✔
262

263
// private
264
void full_node::do_subscribe_chase(const event_notifier& handler,
476 ✔
265
    const event_completer& complete) NOEXCEPT
266
{
267
    BC_ASSERT(stranded());
476 ✔
268
    const auto key = create_key();
476 ✔
269
    complete(event_subscriber_.subscribe(move_copy(handler), key), key);
476 ✔
270
}
476 ✔
271

272
void full_node::unsubscribe_chase(object_key key) NOEXCEPT
501 ✔
273
{
274
    notify_one(key, network::error::service_stopped, chases::stop{});
501 ✔
275
}
501 ✔
276

277
// Suspensions.
278
// ----------------------------------------------------------------------------
279

280
bool full_node::resume() NOEXCEPT
10 ✔
281
{
282
    if (query_.is_full())
10 ✔
283
    {
284
        LOGF("Cannot resume network, disk full.");
×
285
        return false;
×
286
    }
287

288
    if (query_.is_fault())
10 ✔
289
    {
290
        LOGF("Cannot resume network, " << query_.get_fault());
×
291
        return false;
×
292
    }
293

294
    LOGS("Resuming network.");
10 ✔
295
    const auto resumed = net::resume();
10 ✔
296
    notify(error::success, chases::resume{});
10 ✔
297
    return resumed;
10 ✔
298
}
299

300
// This is just a best effort, the call may have to be repeated.
301
void full_node::suspend(const code& ec) NOEXCEPT
33 ✔
302
{
303
    LOGS("Suspending network, " << ec.message());
33 ✔
304
    net::suspend(ec);
33 ✔
305
    notify(error::suspended_channel, chases::suspend{});
33 ✔
306
}
33 ✔
307

308
void full_node::fault(const code& ec) NOEXCEPT
21 ✔
309
{
310
    if (query_.is_full())
21 ✔
311
    {
312
        LOGF("Disk full [" << query_.get_space()
×
313
            << "] bytes required following, " << ec.message());
314
        notify(ec, chases::space{});
×
315
    }
316
    else if (query_.is_fault())
21 ✔
317
    {
318
        LOGF("Store fault (unrecoverable) '" << query_.get_fault().message()
×
319
            << "' following, " << ec.message());
320
    }
321
    else if (ec)
21 ✔
322
    {
323
        // This is a resumable error condition, arising from calling fault(ec)
324
        // when the cause did not originate from the memory map (!is_fault).
325
        LOGF("Node fault, " << ec.message());
21 ✔
326
    }
327

328
    // If a call does not get all of the channels, subsequent failures do so.
329
    suspend(ec);
21 ✔
330
}
21 ✔
331

332
// Leaves network suspended, caller may want to resume upon success.
333
code full_node::prune(const store::event_handler& handler) NOEXCEPT
5 ✔
334
{
335
    if (query_.is_fault())
5 ✔
336
        return query_.get_code();
×
337

338
    const auto start = logger::now();
5 ✔
339
    suspend(error::store_prune);
5 ✔
340
    const auto ec = query_.prune([&](auto event, auto table) NOEXCEPT
5 ✔
341
    {
342
        // Suspend channels that missed previous suspend events.
343
        if (event == database::event_t::wait_lock)
650 ✔
344
            suspend(error::store_prune);
×
345

346
        handler(event, table);
650 ✔
347
    });
650 ✔
348

349
    net::span<milliseconds>(events::prune_msecs, start);
5 ✔
350
    return ec;
5 ✔
351
}
352

353
// Leaves network suspended, caller may want to resume upon success.
354
code full_node::snapshot(const store::event_handler& handler) NOEXCEPT
3 ✔
355
{
356
    if (query_.is_fault())
3 ✔
357
        return query_.get_code();
×
358

359
    const auto start = logger::now();
3 ✔
360
    suspend(error::store_snapshot);
3 ✔
361
    const auto ec = query_.snapshot([&](auto event, auto table) NOEXCEPT
3 ✔
362
    {
363
        // Suspend channels that missed previous suspend events.
364
        if (event == database::event_t::wait_lock)
285 ✔
365
            suspend(error::store_snapshot);
×
366

367
        handler(event, table);
285 ✔
368
    });
285 ✔
369

370
    net::span<seconds>(events::snapshot_secs, start);
3 ✔
371
    return ec;
3 ✔
372
}
373

374
// Leaves network suspended, caller may want to resume upon success.
375
code full_node::reload(const store::event_handler& handler) NOEXCEPT
2 ✔
376
{
377
    if (!query_.is_full())
2 ✔
378
        return query_.is_fault() ? query_.get_code() : error::success;
2 ✔
379

380
    const auto start = logger::now();
×
381
    suspend(error::store_reload);
×
382

383
    // This will set the store's dirty flag causing increased read activity for
384
    // set(tx/block) due to activation of duplicate detection. The store is
385
    // is however always in a dirty state after startup with non-empty tables.
386
    const auto ec = query_.reload([&](auto event, auto table) NOEXCEPT
×
387
    {
388
        // Suspend channels that missed previous suspend events.
389
        if (event == database::event_t::wait_lock)
×
390
            suspend(error::store_reload);
×
391

392
        handler(event, table);
×
393
    });
×
394

UNCOV
395
    net::span<milliseconds>(events::reload_msecs, start);
×
396
    return ec;
×
397
}
398

399
// Properties.
400
// ----------------------------------------------------------------------------
401

402
query& full_node::archive() const NOEXCEPT
92,527 ✔
403
{
404
    return query_;
92,527 ✔
405
}
406

407
const node::configuration& full_node::node_config() const NOEXCEPT
193 ✔
408
{
409
    return config_;
193 ✔
410
}
411

412
const system::settings& full_node::system_settings() const NOEXCEPT
6,100 ✔
413
{
414
    return config_.bitcoin;
6,100 ✔
415
}
416

417
const database::settings& full_node::database_settings() const NOEXCEPT
386 ✔
418
{
419
    return config_.database;
386 ✔
420
}
421

422
////const network::settings& full_node::network_settings() const NOEXCEPT
423
////{
424
////    return network_.network_settings();
425
////}
426

427
const node::settings& full_node::node_settings() const NOEXCEPT
15,147 ✔
428
{
429
    return config_.node;
15,147 ✔
430
}
431

432
bool full_node::is_current_chain(bool confirmed) const NOEXCEPT
1,859 ✔
433
{
434
    if (is_zero(config_.node.currency_window_minutes))
1,859 ✔
435
        return true;
436

437
    return is_current_time(query_.get_top_timestamp(confirmed));
985 ✔
438
}
439

440
bool full_node::is_current_time(uint32_t timestamp) const NOEXCEPT
7,509 ✔
441
{
442
    if (is_zero(config_.node.currency_window_minutes))
7,509 ✔
443
        return true;
444

445
    const wall_clock::time_point time{ seconds{ timestamp } };
1,491 ✔
446
    const auto current = wall_clock::now() - config_.node.currency_window();
1,491 ✔
447
    return time >= current;
1,491 ✔
448
}
449

450
// get_timestamp error results in false (ok).
451
bool full_node::is_current_header(const header_link& link) const NOEXCEPT
425 ✔
452
{
453
    if (is_zero(config_.node.currency_window_minutes))
425 ✔
454
        return true;
455

456
    uint32_t timestamp{};
421 ✔
457
    if (!query_.get_timestamp(timestamp, link))
421 ✔
458
        return false;
459

460
    return is_current_time(timestamp);
420 ✔
461
}
462

463
bool full_node::is_recent() const NOEXCEPT
342 ✔
464
{
465
    if (is_nonzero(config_.node.maximum_height) &&
342 ✔
466
        (query_.get_top_confirmed() >= config_.node.maximum_height))
3 ✔
467
        return true;
468

469
    return is_current_chain(true);
341 ✔
470
}
471

472
time_t full_node::start_time() const NOEXCEPT
7 ✔
473
{
474
    return start_time_;
7 ✔
475
}
476

477
// Methods.
478
// ----------------------------------------------------------------------------
479

480
void full_node::estimate(size_t target, estimator::mode mode,
7 ✔
481
    estimate_handler&& handler) NOEXCEPT
482
{
483
    chaser_estimate_.estimate(target, mode, std::move(handler));
7 ✔
484
}
7 ✔
485

486
void full_node::performance(object_key key, uint64_t speed,
24 ✔
487
    result_handler&& handler) NOEXCEPT
488
{
489
    chaser_download_.update(key, speed, std::move(handler));
24 ✔
490
}
24 ✔
491

492
// Session attachments.
493
// ----------------------------------------------------------------------------
494

495
network::session_manual::ptr full_node::attach_manual_session() NOEXCEPT
345 ✔
496
{
497
    return net::attach<node::session_manual>(*this);
345 ✔
498
}
499

500
network::session_inbound::ptr full_node::attach_inbound_session() NOEXCEPT
336 ✔
501
{
502
    return net::attach<node::session_inbound>(*this);
336 ✔
503
}
504

505
network::session_outbound::ptr full_node::attach_outbound_session() NOEXCEPT
336 ✔
506
{
507
    return net::attach<node::session_outbound>(*this);
336 ✔
508
}
509

510
BC_POP_WARNING()
511

512
} // namespace node
513
} // namespace libbitcoin
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc