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

libbitcoin / libbitcoin-system / 15428987191

03 Jun 2025 10:17PM UTC coverage: 81.096% (+0.006%) from 81.09%
15428987191

push

github

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

Update header.version processing, style, refactor.

1 of 17 new or added lines in 3 files covered. (5.88%)

1 existing line in 1 file now uncovered.

10433 of 12865 relevant lines covered (81.1%)

3684919.44 hits per line

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

79.04
/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
}
8✔
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
8✔
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)
2✔
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
void header::set_hash(const hash_digest& hash) const NOEXCEPT
×
222
{
223
    hash_ = hash;
×
224
}
×
225

226
// computed
227
hash_digest header::hash() const NOEXCEPT
42✔
228
{
229
    if (hash_)
42✔
230
        return *hash_;
×
231

232
    BC_PUSH_WARNING(LOCAL_VARIABLE_NOT_INITIALIZED)
233
    hash_digest digest;
42✔
234
    BC_POP_WARNING()
235

236
    stream::out::fast stream{ digest };
42✔
237
    hash::sha256x2::fast sink{ stream };
42✔
238
    to_data(sink);
42✔
239
    sink.flush();
42✔
240
    return digest;
42✔
241
}
42✔
242

243
const hash_digest& header::get_hash() const NOEXCEPT
×
244
{
245
    if (!hash_)
×
246
        set_hash(hash());
×
247

248
    return *hash_;
×
249
}
250

251
// static
252
uint256_t header::proof(uint32_t bits) NOEXCEPT
1✔
253
{
254
    auto target = compact::expand(bits);
1✔
255

256
    //*************************************************************************
257
    // CONSENSUS: bits may be overflowed, which is guarded here.
258
    // A target of zero is disallowed so is useful as a sentinel value.
259
    //*************************************************************************
260
    if (is_zero(target))
1✔
261
        return target;
×
262

263
    //*************************************************************************
264
    // CONSENSUS: If target is (2^256)-1, division would fail, however compact
265
    // compression is lossy, and therefore unable to produce negative one.
266
    //*************************************************************************
267

268
    // We need to compute 2**256 / (target + 1), but we can't represent 2**256
269
    // as it's too large for uint256. However as 2**256 is at least as large as
270
    // target + 1, it is equal to ((2**256 - target - 1) / (target + 1)) + 1, or
271
    // (~target / (target + 1)) + 1.
272
    return ++(~target / (target + one));
2✔
273
}
274

275
// computed
276
uint256_t header::proof() const NOEXCEPT
1✔
277
{
278
    // Returns zero if bits_ mantissa is less than one or bits_ is overflowed.
279
    return proof(bits_);
1✔
280
}
281

282
// Check.
283
// ----------------------------------------------------------------------------
284

285
bool header::is_invalid_proof_of_work(uint32_t proof_of_work_limit,
5✔
286
    bool scrypt) const NOEXCEPT
287
{
288
    static const auto limit = compact::expand(proof_of_work_limit);
5✔
289
    const auto target = compact::expand(bits_);
5✔
290

291
    //*************************************************************************
292
    // CONSENSUS: bits_ may be overflowed, which is guarded here.
293
    // A target of zero is disallowed so is useful as a sentinel value.
294
    //*************************************************************************
295
    if (is_zero(target))
5✔
296
        return true;
297

298
    // Ensure claimed work is at or above minimum (less is more).
299
    if (target > limit)
4✔
300
        return true;
301

302
    // Conditionally use scrypt proof of work (e.g. Litecoin).
303
    return to_uintx(scrypt ? scrypt_hash(to_data()) : hash()) > target;
10✔
304
}
305

306
// ****************************************************************************
307
// CONSENSUS: 32 bit unsigned unix time overflows in 2106.
308
// ****************************************************************************
309
bool header::is_futuristic_timestamp(
2✔
310
    uint32_t timestamp_limit_seconds) const NOEXCEPT
311
{
312
    using namespace std::chrono;
2✔
313
    static const auto two_hours = seconds(timestamp_limit_seconds);
2✔
314
    const auto time = wall_clock::from_time_t(timestamp_);
2✔
315
    const auto future = wall_clock::now() + two_hours;
2✔
316
    return time > future;
2✔
317
}
318

319
// Validation.
320
// ----------------------------------------------------------------------------
321

322
code header::check(uint32_t timestamp_limit_seconds,
×
323
    uint32_t proof_of_work_limit, bool scrypt) const NOEXCEPT
324
{
325
    if (is_invalid_proof_of_work(proof_of_work_limit, scrypt))
×
326
        return error::invalid_proof_of_work;
×
NEW
327
    if (is_futuristic_timestamp(timestamp_limit_seconds))
×
328
        return error::futuristic_timestamp;
×
329

330
    return error::block_success;
×
331
}
332

333
// minimum_block_version
334
// median_time_past
335
// work_required
336

337
// Checkpoints and previous_block_hash are chain validation (not here).
338
// bits_ below is the consensus direct comparison of the header.bits value.
339
// All other work comparisons performed on expanded/normalized bits values.
340
code header::accept(const context& ctx) const NOEXCEPT
×
341
{
NEW
342
    if (ctx.is_insufficient_version(version_))
×
NEW
343
        return error::insufficient_block_version;
×
NEW
344
    if (ctx.is_anachronistic_timestamp(timestamp_))
×
NEW
345
        return error::anachronistic_timestamp;
×
NEW
346
    if (ctx.is_invalid_work(bits_))
×
UNCOV
347
        return error::incorrect_proof_of_work;
×
348

349
    return error::block_success;
×
350
}
351

352
// JSON value convertors.
353
// ----------------------------------------------------------------------------
354

355
namespace json = boost::json;
356

357
// boost/json will soon have NOEXCEPT: github.com/boostorg/json/pull/636
358
BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
359

360
header tag_invoke(json::value_to_tag<header>,
2✔
361
    const json::value& value) NOEXCEPT
362
{
363
    hash_digest previous, merkle_root;
2✔
364
    if (!decode_hash(previous, value.at("previous").get_string().c_str()) ||
4✔
365
        !decode_hash(merkle_root, value.at("merkle_root").get_string().c_str()))
2✔
366
        return {};
×
367

368
    return
2✔
369
    {
370
        value.at("version").to_number<uint32_t>(),
2✔
371
        previous,
372
        merkle_root,
373
        value.at("timestamp").to_number<uint32_t>(),
2✔
374
        value.at("bits").to_number<uint32_t>(),
2✔
375
        value.at("nonce").to_number<uint32_t>()
4✔
376
    };
8✔
377
}
378

379
void tag_invoke(json::value_from_tag, json::value& value,
4✔
380
    const header& tx) NOEXCEPT
381
{
382
    value =
16✔
383
    {
384
        { "version", tx.version() },
385
        { "previous", encode_hash(tx.previous_block_hash()) },
4✔
386
        { "merkle_root", encode_hash(tx.merkle_root()) },
8✔
387
        { "timestamp", tx.timestamp() },
388
        { "bits", tx.bits() },
389
        { "nonce", tx.nonce() }
390
    };
4✔
391
}
4✔
392

393
BC_POP_WARNING()
394

395
header::cptr tag_invoke(json::value_to_tag<header::cptr>,
×
396
    const json::value& value) NOEXCEPT
397
{
398
    return to_shared(tag_invoke(json::value_to_tag<header>{}, value));
×
399
}
400

401
// Shared pointer overload is required for navigation.
402
BC_PUSH_WARNING(SMART_PTR_NOT_NEEDED)
403
BC_PUSH_WARNING(NO_VALUE_OR_CONST_REF_SHARED_PTR)
404

405
void tag_invoke(json::value_from_tag tag, json::value& value,
×
406
    const header::cptr& tx) NOEXCEPT
407
{
408
    tag_invoke(tag, value, *tx);
×
409
}
×
410

411
BC_POP_WARNING()
412
BC_POP_WARNING()
413

414
} // namespace chain
415
} // namespace system
416
} // 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