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

libbitcoin / libbitcoin-system / 18415090430

10 Oct 2025 06:26PM UTC coverage: 80.903% (-0.06%) from 80.965%
18415090430

push

github

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

Add mutable chain_state field and const get/set for header/block.

6 of 19 new or added lines in 2 files covered. (31.58%)

2 existing lines in 1 file now uncovered.

10591 of 13091 relevant lines covered (80.9%)

3617136.95 hits per line

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

76.74
/src/chain/header.cpp
1
/**
2
 * Copyright (c) 2011-2025 libbitcoin developers (see AUTHORS)
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/system/chain/header.hpp>
20

21
#include <chrono>
22
#include <utility>
23
#include <bitcoin/system/chain/chain_state.hpp>
24
#include <bitcoin/system/chain/compact.hpp>
25
#include <bitcoin/system/data/data.hpp>
26
#include <bitcoin/system/define.hpp>
27
#include <bitcoin/system/hash/hash.hpp>
28
#include <bitcoin/system/error/error.hpp>
29
#include <bitcoin/system/stream/stream.hpp>
30

31
namespace libbitcoin {
32
namespace system {
33
namespace chain {
34

35
// Use system clock because we require accurate time of day.
36
using wall_clock = std::chrono::system_clock;
37

38
// Constructors.
39
// ----------------------------------------------------------------------------
40

41
header::header() NOEXCEPT
99✔
42
  : header(0, {}, {}, 0, 0, 0, false)
99✔
43
{
44
}
99✔
45

46
header::header(uint32_t version, hash_digest&& previous_block_hash,
8✔
47
    hash_digest&& merkle_root, uint32_t timestamp, uint32_t bits,
48
    uint32_t nonce) NOEXCEPT
49
  : header(version, std::move(previous_block_hash), std::move(merkle_root),
50
      timestamp, bits, nonce, true)
51
{
52
}
8✔
53

54
header::header(uint32_t version, const hash_digest& previous_block_hash,
10✔
55
    const hash_digest& merkle_root, uint32_t timestamp, uint32_t bits,
56
    uint32_t nonce) NOEXCEPT
57
  : header(version, previous_block_hash, merkle_root, timestamp, bits, nonce,
58
      true)
59
{
60
}
10✔
61

62
header::header(stream::in::fast&& stream) NOEXCEPT
1✔
63
  : header(read::bytes::fast(stream))
1✔
64
{
65
}
1✔
66

67
header::header(stream::in::fast& stream) NOEXCEPT
1✔
68
  : header(read::bytes::fast(stream))
1✔
69
{
70
}
1✔
71

72
header::header(std::istream&& stream) NOEXCEPT
×
73
  : header(read::bytes::istream(stream))
×
74
{
75
}
×
76

77
header::header(std::istream& stream) NOEXCEPT
3✔
78
  : header(read::bytes::istream(stream))
3✔
79
{
80
}
3✔
81

82
header::header(reader&& source) NOEXCEPT
5✔
83
  : header(source)
5✔
84
{
85
}
×
86

87
header::header(reader& source) NOEXCEPT
113✔
88
{
89
    assign_data(source);
113✔
90
}
113✔
91

92
// protected
93
header::header(uint32_t version, hash_digest&& previous_block_hash,
107✔
94
    hash_digest&& merkle_root, uint32_t timestamp, uint32_t bits,
95
    uint32_t nonce, bool valid) NOEXCEPT
107✔
96
  : version_(version),
107✔
97
    previous_block_hash_(std::move(previous_block_hash)),
107✔
98
    merkle_root_(std::move(merkle_root)),
107✔
99
    timestamp_(timestamp),
107✔
100
    bits_(bits),
107✔
101
    nonce_(nonce),
107✔
102
    valid_(valid)
107✔
103
{
104
}
×
105

106
// protected
107
header::header(uint32_t version, const hash_digest& previous_block_hash,
10✔
108
    const hash_digest& merkle_root, uint32_t timestamp, uint32_t bits,
109
    uint32_t nonce, bool valid) NOEXCEPT
10✔
110
  : version_(version),
10✔
111
    previous_block_hash_(previous_block_hash),
10✔
112
    merkle_root_(merkle_root),
10✔
113
    timestamp_(timestamp),
10✔
114
    bits_(bits),
10✔
115
    nonce_(nonce),
10✔
116
    valid_(valid)
10✔
117
{
118
}
×
119

120
// Operators.
121
// ----------------------------------------------------------------------------
122

123
bool header::operator==(const header& other) const NOEXCEPT
38✔
124
{
125
    return (version_ == other.version_)
38✔
126
        && (previous_block_hash_ == other.previous_block_hash_)
31✔
127
        && (merkle_root_ == other.merkle_root_)
31✔
128
        && (timestamp_ == other.timestamp_)
31✔
129
        && (bits_ == other.bits_)
130
        && (nonce_ == other.nonce_);
69✔
131
}
132

133
bool header::operator!=(const header& other) const NOEXCEPT
2✔
134
{
135
    return !(*this == other);
2✔
136
}
137

138
// Deserialization.
139
// ----------------------------------------------------------------------------
140

141
// private
142
void header::assign_data(reader& source) NOEXCEPT
113✔
143
{
144
    // Hashes are copied directly into to header-allocated space.
145
    // Integrals are stack-allocated and copied to header-allocated space.
146
    version_ = source.read_4_bytes_little_endian();
113✔
147
    source.read_bytes(previous_block_hash_.data(), hash_size);
113✔
148
    source.read_bytes(merkle_root_.data(), hash_size);
113✔
149
    timestamp_ = source.read_4_bytes_little_endian();
113✔
150
    bits_ = source.read_4_bytes_little_endian();
113✔
151
    nonce_ = source.read_4_bytes_little_endian();
113✔
152
    valid_ = source;
113✔
153
}
113✔
154

155
// Serialization.
156
// ----------------------------------------------------------------------------
157

158
data_chunk header::to_data() const NOEXCEPT
9✔
159
{
160
    data_chunk data(serialized_size());
9✔
161
    stream::out::fast ostream(data);
9✔
162
    write::bytes::fast out(ostream);
9✔
163
    to_data(out);
9✔
164
    return data;
18✔
165
}
9✔
166

167
void header::to_data(std::ostream& stream) const NOEXCEPT
1✔
168
{
169
    write::bytes::ostream out(stream);
1✔
170
    to_data(out);
1✔
171
}
1✔
172

173
void header::to_data(writer& sink) const NOEXCEPT
86✔
174
{
175
    sink.write_4_bytes_little_endian(version_);
86✔
176
    sink.write_bytes(previous_block_hash_);
86✔
177
    sink.write_bytes(merkle_root_);
86✔
178
    sink.write_4_bytes_little_endian(timestamp_);
86✔
179
    sink.write_4_bytes_little_endian(bits_);
86✔
180
    sink.write_4_bytes_little_endian(nonce_);
86✔
181
}
86✔
182

183
// Properties.
184
// ----------------------------------------------------------------------------
185

186
bool header::is_valid() const NOEXCEPT
11✔
187
{
188
    return valid_;
11✔
189
}
190

191
uint32_t header::version() const NOEXCEPT
6✔
192
{
193
    return version_;
4✔
194
}
195

196
const hash_digest& header::previous_block_hash() const NOEXCEPT
6✔
197
{
198
    return previous_block_hash_;
6✔
199
}
200

201
const hash_digest& header::merkle_root() const NOEXCEPT
20✔
202
{
203
    return merkle_root_;
20✔
204
}
205

206
uint32_t header::timestamp() const NOEXCEPT
6✔
207
{
208
    return timestamp_;
4✔
209
}
210

211
uint32_t header::bits() const NOEXCEPT
6✔
212
{
213
    return bits_;
4✔
214
}
215

216
uint32_t header::nonce() const NOEXCEPT
6✔
217
{
218
    return nonce_;
4✔
219
}
220

221
// static/computed
222
uint256_t header::proof(uint32_t bits) NOEXCEPT
1✔
223
{
224
    auto target = compact::expand(bits);
1✔
225

226
    //*************************************************************************
227
    // CONSENSUS: bits may be overflowed, which is guarded here.
228
    // A target of zero is disallowed so is useful as a sentinel value.
229
    //*************************************************************************
230
    if (is_zero(target))
1✔
NEW
231
        return target;
×
232

233
    //*************************************************************************
234
    // CONSENSUS: If target is (2^256)-1, division would fail, however compact
235
    // compression is lossy, and therefore unable to produce negative one.
236
    //*************************************************************************
237

238
    // We need to compute 2**256 / (target + 1), but we can't represent 2**256
239
    // as it's too large for uint256. However as 2**256 is at least as large as
240
    // target + 1, it is equal to ((2**256 - target - 1) / (target + 1)) + 1, or
241
    // (~target / (target + 1)) + 1.
242
    return ++(~target / (target + one));
2✔
243
}
244

245
// computed
246
uint256_t header::proof() const NOEXCEPT
1✔
247
{
248
    // Returns zero if bits_ mantissa is less than one or bits_ is overflowed.
249
    return proof(bits_);
1✔
250
}
251

252
// computed
253
hash_digest header::hash() const NOEXCEPT
42✔
254
{
255
    if (hash_)
42✔
256
        return *hash_;
×
257

258
    BC_PUSH_WARNING(LOCAL_VARIABLE_NOT_INITIALIZED)
259
    hash_digest digest;
42✔
260
    BC_POP_WARNING()
261

262
    stream::out::fast stream{ digest };
42✔
263
    hash::sha256x2::fast sink{ stream };
42✔
264
    to_data(sink);
42✔
265
    sink.flush();
42✔
266
    return digest;
42✔
267
}
42✔
268

269
// Cache and metadata.
270
// ----------------------------------------------------------------------------
271

NEW
272
void header::set_hash(const hash_digest& hash) const NOEXCEPT
×
273
{
NEW
274
    hash_ = hash;
×
NEW
275
}
×
276

UNCOV
277
const hash_digest& header::get_hash() const NOEXCEPT
×
278
{
279
    if (!hash_)
×
280
        set_hash(hash());
×
281

282
    return *hash_;
×
283
}
284

NEW
285
const chain_state::cptr& header::get_state() const NOEXCEPT
×
286
{
NEW
287
    return state_;
×
288
}
289

NEW
290
void header::set_state(const chain_state::cptr& state) const NOEXCEPT
×
291
{
NEW
292
    state_ = state;
×
UNCOV
293
}
×
294

295
// Check.
296
// ----------------------------------------------------------------------------
297

298
bool header::is_invalid_proof_of_work(uint32_t proof_of_work_limit,
5✔
299
    bool scrypt) const NOEXCEPT
300
{
301
    static const auto limit = compact::expand(proof_of_work_limit);
5✔
302
    const auto target = compact::expand(bits_);
5✔
303

304
    //*************************************************************************
305
    // CONSENSUS: bits_ may be overflowed, which is guarded here.
306
    // A target of zero is disallowed so is useful as a sentinel value.
307
    //*************************************************************************
308
    if (is_zero(target))
5✔
309
        return true;
310

311
    // Ensure claimed work is at or above minimum (less is more).
312
    if (target > limit)
4✔
313
        return true;
314

315
    // Conditionally use scrypt proof of work (e.g. Litecoin).
316
    return to_uintx(scrypt ? scrypt_hash(to_data()) : hash()) > target;
10✔
317
}
318

319
// ****************************************************************************
320
// CONSENSUS: 32 bit unsigned unix time overflows in 2106.
321
// ****************************************************************************
322
bool header::is_futuristic_timestamp(
2✔
323
    uint32_t timestamp_limit_seconds) const NOEXCEPT
324
{
325
    using namespace std::chrono;
2✔
326
    static const auto two_hours = seconds(timestamp_limit_seconds);
2✔
327
    const auto time = wall_clock::from_time_t(timestamp_);
2✔
328
    const auto future = wall_clock::now() + two_hours;
2✔
329
    return time > future;
2✔
330
}
331

332
// Validation.
333
// ----------------------------------------------------------------------------
334

335
code header::check(uint32_t timestamp_limit_seconds,
×
336
    uint32_t proof_of_work_limit, bool scrypt) const NOEXCEPT
337
{
338
    if (is_invalid_proof_of_work(proof_of_work_limit, scrypt))
×
339
        return error::invalid_proof_of_work;
×
340
    if (is_futuristic_timestamp(timestamp_limit_seconds))
×
341
        return error::futuristic_timestamp;
×
342

343
    return error::block_success;
×
344
}
345

346
// minimum_block_version
347
// median_time_past
348
// work_required
349

350
// Checkpoints and previous_block_hash are chain validation (not here).
351
// bits_ below is the consensus direct comparison of the header.bits value.
352
// All other work comparisons performed on expanded/normalized bits values.
353
code header::accept(const context& ctx) const NOEXCEPT
×
354
{
355
    if (ctx.is_insufficient_version(version_))
×
356
        return error::insufficient_block_version;
×
357
    if (ctx.is_anachronistic_timestamp(timestamp_))
×
358
        return error::anachronistic_timestamp;
×
359
    if (ctx.is_invalid_work(bits_))
×
360
        return error::incorrect_proof_of_work;
×
361

362
    return error::block_success;
×
363
}
364

365
// JSON value convertors.
366
// ----------------------------------------------------------------------------
367

368
namespace json = boost::json;
369

370
// boost/json will soon have NOEXCEPT: github.com/boostorg/json/pull/636
371
BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
372

373
header tag_invoke(json::value_to_tag<header>,
2✔
374
    const json::value& value) NOEXCEPT
375
{
376
    hash_digest previous, merkle_root;
2✔
377
    if (!decode_hash(previous, value.at("previous").get_string().c_str()) ||
4✔
378
        !decode_hash(merkle_root, value.at("merkle_root").get_string().c_str()))
2✔
379
        return {};
×
380

381
    return
2✔
382
    {
383
        value.at("version").to_number<uint32_t>(),
2✔
384
        previous,
385
        merkle_root,
386
        value.at("timestamp").to_number<uint32_t>(),
2✔
387
        value.at("bits").to_number<uint32_t>(),
2✔
388
        value.at("nonce").to_number<uint32_t>()
4✔
389
    };
8✔
390
}
391

392
void tag_invoke(json::value_from_tag, json::value& value,
4✔
393
    const header& tx) NOEXCEPT
394
{
395
    value =
16✔
396
    {
397
        { "version", tx.version() },
398
        { "previous", encode_hash(tx.previous_block_hash()) },
4✔
399
        { "merkle_root", encode_hash(tx.merkle_root()) },
8✔
400
        { "timestamp", tx.timestamp() },
401
        { "bits", tx.bits() },
402
        { "nonce", tx.nonce() }
403
    };
4✔
404
}
4✔
405

406
BC_POP_WARNING()
407

408
header::cptr tag_invoke(json::value_to_tag<header::cptr>,
×
409
    const json::value& value) NOEXCEPT
410
{
411
    return to_shared(tag_invoke(json::value_to_tag<header>{}, value));
×
412
}
413

414
// Shared pointer overload is required for navigation.
415
BC_PUSH_WARNING(SMART_PTR_NOT_NEEDED)
416
BC_PUSH_WARNING(NO_VALUE_OR_CONST_REF_SHARED_PTR)
417

418
void tag_invoke(json::value_from_tag tag, json::value& value,
×
419
    const header::cptr& tx) NOEXCEPT
420
{
421
    tag_invoke(tag, value, *tx);
×
422
}
×
423

424
BC_POP_WARNING()
425
BC_POP_WARNING()
426

427
} // namespace chain
428
} // namespace system
429
} // namespace libbitcoin
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc