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

libbitcoin / libbitcoin-system / 9879696031

10 Jul 2024 06:40PM UTC coverage: 82.863% (-0.01%) from 82.874%
9879696031

Pull #1498

github

web-flow
Merge 8a7dacadf into 155e5fae6
Pull Request #1498: Optimizing deserializations (block, header, txs, point).

30 of 31 new or added lines in 4 files covered. (96.77%)

3 existing lines in 3 files now uncovered.

9980 of 12044 relevant lines covered (82.86%)

4793774.11 hits per line

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

80.72
/src/chain/header.cpp
1
/**
2
 * Copyright (c) 2011-2023 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
74✔
42
  : header(0, {}, {}, 0, 0, 0, false)
74✔
43
{
44
}
74✔
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,
8✔
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
}
6✔
61

62
header::header(const data_slice& data) NOEXCEPT
1✔
63
    BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
64
  : header(stream::in::copy(data))
1✔
65
    BC_POP_WARNING()
66
{
67
}
1✔
68

69
////header::header(stream::in::fast&& stream) NOEXCEPT
70
////  : header(read::bytes::fast(stream))
71
////{
72
////}
73

74
header::header(stream::in::fast& stream) NOEXCEPT
1✔
75
  : header(read::bytes::fast(stream))
1✔
76
{
77
}
1✔
78

79
header::header(std::istream&& stream) NOEXCEPT
1✔
80
  : header(read::bytes::istream(stream))
1✔
81
{
82
}
1✔
83

84
header::header(std::istream& stream) NOEXCEPT
3✔
85
  : header(read::bytes::istream(stream))
3✔
86
{
87
}
3✔
88

89
header::header(reader&& source) NOEXCEPT
5✔
90
  : header(source/*from_data(source)*/)
5✔
91
{
UNCOV
92
}
×
93

94
header::header(reader& source) NOEXCEPT
84✔
95
  /*: header(from_data(source))*/
96
{
97
    assign_data(source);
84✔
98
}
84✔
99

100
// protected
101
header::header(uint32_t version, hash_digest&& previous_block_hash,
82✔
102
    hash_digest&& merkle_root, uint32_t timestamp, uint32_t bits,
103
    uint32_t nonce, bool valid) NOEXCEPT
82✔
104
  : version_(version),
82✔
105
    previous_block_hash_(std::move(previous_block_hash)),
82✔
106
    merkle_root_(std::move(merkle_root)),
82✔
107
    timestamp_(timestamp),
82✔
108
    bits_(bits),
82✔
109
    nonce_(nonce),
82✔
110
    valid_(valid)
82✔
111
{
112
}
×
113

114
// protected
115
header::header(uint32_t version, const hash_digest& previous_block_hash,
8✔
116
    const hash_digest& merkle_root, uint32_t timestamp, uint32_t bits,
117
    uint32_t nonce, bool valid) NOEXCEPT
6✔
118
  : version_(version),
8✔
119
    previous_block_hash_(previous_block_hash),
8✔
120
    merkle_root_(merkle_root),
8✔
121
    timestamp_(timestamp),
8✔
122
    bits_(bits),
8✔
123
    nonce_(nonce),
8✔
124
    valid_(valid)
2✔
125
{
126
}
×
127

128
// Operators.
129
// ----------------------------------------------------------------------------
130

131
bool header::operator==(const header& other) const NOEXCEPT
27✔
132
{
133
    return (version_ == other.version_)
27✔
134
        && (previous_block_hash_ == other.previous_block_hash_)
20✔
135
        && (merkle_root_ == other.merkle_root_)
20✔
136
        && (timestamp_ == other.timestamp_)
20✔
137
        && (bits_ == other.bits_)
138
        && (nonce_ == other.nonce_);
47✔
139
}
140

141
bool header::operator!=(const header& other) const NOEXCEPT
2✔
142
{
143
    return !(*this == other);
2✔
144
}
145

146
// Deserialization.
147
// ----------------------------------------------------------------------------
148

149
////// static/private
150
////header header::from_data(reader& source) NOEXCEPT
151
////{
152
////    return
153
////    {
154
////        source.read_4_bytes_little_endian(),
155
////        source.read_hash(),
156
////        source.read_hash(),
157
////        source.read_4_bytes_little_endian(),
158
////        source.read_4_bytes_little_endian(),
159
////        source.read_4_bytes_little_endian(),
160
////        source
161
////    };
162
////}
163

164
// private
165
// This denormalization eliminates allocation and copy of 64 bytes per block.
166
void header::assign_data(reader& source) NOEXCEPT
84✔
167
{
168
    // Hashes are copied directly into to header-allocated space.
169
    // Integrals are stack-allocated and copied to header-allocated space.
170
    version_ = source.read_4_bytes_little_endian();
84✔
171
    source.read_bytes(previous_block_hash_.data(), hash_size);
84✔
172
    source.read_bytes(merkle_root_.data(), hash_size);
84✔
173
    timestamp_ = source.read_4_bytes_little_endian();
84✔
174
    bits_ = source.read_4_bytes_little_endian();
84✔
175
    nonce_ = source.read_4_bytes_little_endian();
84✔
176
    valid_ = source;
84✔
177
}
84✔
178

179
// Serialization.
180
// ----------------------------------------------------------------------------
181

182
data_chunk header::to_data() const NOEXCEPT
7✔
183
{
184
    data_chunk data(serialized_size());
7✔
185

186
    BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
187
    stream::out::copy ostream(data);
7✔
188
    BC_POP_WARNING()
189

190
    to_data(ostream);
7✔
191
    return data;
14✔
192
}
7✔
193

194
void header::to_data(std::ostream& stream) const NOEXCEPT
8✔
195
{
196
    write::bytes::ostream out(stream);
8✔
197
    to_data(out);
8✔
198
}
8✔
199

200
void header::to_data(writer& sink) const NOEXCEPT
76✔
201
{
202
    sink.write_4_bytes_little_endian(version_);
76✔
203
    sink.write_bytes(previous_block_hash_);
76✔
204
    sink.write_bytes(merkle_root_);
76✔
205
    sink.write_4_bytes_little_endian(timestamp_);
76✔
206
    sink.write_4_bytes_little_endian(bits_);
76✔
207
    sink.write_4_bytes_little_endian(nonce_);
76✔
208
}
76✔
209

210
// Properties.
211
// ----------------------------------------------------------------------------
212

213
bool header::is_valid() const NOEXCEPT
11✔
214
{
215
    return valid_;
11✔
216
}
217

218
uint32_t header::version() const NOEXCEPT
6✔
219
{
220
    return version_;
4✔
221
}
222

223
const hash_digest& header::previous_block_hash() const NOEXCEPT
6✔
224
{
225
    return previous_block_hash_;
6✔
226
}
227

228
const hash_digest& header::merkle_root() const NOEXCEPT
17✔
229
{
230
    return merkle_root_;
17✔
231
}
232

233
uint32_t header::timestamp() const NOEXCEPT
6✔
234
{
235
    return timestamp_;
4✔
236
}
237

238
uint32_t header::bits() const NOEXCEPT
6✔
239
{
240
    return bits_;
4✔
241
}
242

243
uint32_t header::nonce() const NOEXCEPT
6✔
244
{
245
    return nonce_;
4✔
246
}
247

248
void header::set_hash(hash_digest&& hash) const NOEXCEPT
×
249
{
250
    hash_ = to_shared(std::move(hash));
×
251
}
×
252

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

259
    BC_PUSH_WARNING(LOCAL_VARIABLE_NOT_INITIALIZED)
260
    hash_digest digest;
39✔
261
    BC_POP_WARNING()
262

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

270
const hash_digest& header::get_hash() const NOEXCEPT
×
271
{
272
    if (!hash_)
×
273
        set_hash(hash());
×
274

275
    return *hash_;
×
276
}
277

278
// static
279
uint256_t header::proof(uint32_t bits) NOEXCEPT
1✔
280
{
281
    auto target = compact::expand(bits);
1✔
282

283
    //*************************************************************************
284
    // CONSENSUS: bits may be overflowed, which is guarded here.
285
    // A target of zero is disallowed so is useful as a sentinel value.
286
    //*************************************************************************
287
    if (is_zero(target))
1✔
288
        return target;
×
289

290
    //*************************************************************************
291
    // CONSENSUS: If target is (2^256)-1, division would fail, however compact
292
    // compression is lossy, and therefore unable to produce negative one.
293
    //*************************************************************************
294

295
    // We need to compute 2**256 / (target + 1), but we can't represent 2**256
296
    // as it's too large for uint256. However as 2**256 is at least as large as
297
    // target + 1, it is equal to ((2**256 - target - 1) / (target + 1)) + 1, or
298
    // (~target / (target + 1)) + 1.
299
    return ++(~target / (target + one));
2✔
300
}
301

302
// computed
303
uint256_t header::proof() const NOEXCEPT
1✔
304
{
305
    // Returns zero if bits_ mantissa is less than one or bits_ is overflowed.
306
    return proof(bits_);
1✔
307
}
308

309
// Check.
310
// ----------------------------------------------------------------------------
311

312
bool header::is_invalid_proof_of_work(uint32_t proof_of_work_limit,
6✔
313
    bool scrypt) const NOEXCEPT
314
{
315
    static const auto limit = compact::expand(proof_of_work_limit);
6✔
316
    const auto target = compact::expand(bits_);
6✔
317

318
    //*************************************************************************
319
    // CONSENSUS: bits_ may be overflowed, which is guarded here.
320
    // A target of zero is disallowed so is useful as a sentinel value.
321
    //*************************************************************************
322
    if (is_zero(target))
6✔
323
        return true;
324

325
    // Ensure claimed work is at or above minimum (less is more).
326
    if (target > limit)
5✔
327
        return true;
328

329
    // Conditionally use scrypt proof of work (e.g. Litecoin).
330
    return to_uintx(scrypt ? scrypt_hash(to_data()) : hash()) > target;
10✔
331
}
332

333
// ****************************************************************************
334
// CONSENSUS: bitcoin 32bit unix time: en.wikipedia.org/wiki/Year_2038_problem
335
// ****************************************************************************
336
bool header::is_invalid_timestamp(
2✔
337
    uint32_t timestamp_limit_seconds) const NOEXCEPT
338
{
339
    using namespace std::chrono;
2✔
340
    static const auto two_hours = seconds(timestamp_limit_seconds);
2✔
341
    const auto time = wall_clock::from_time_t(timestamp_);
2✔
342
    const auto future = wall_clock::now() + two_hours;
2✔
343
    return time > future;
2✔
344
}
345

346
// Validation.
347
// ----------------------------------------------------------------------------
348

349
code header::check(uint32_t timestamp_limit_seconds,
×
350
    uint32_t proof_of_work_limit, bool scrypt) const NOEXCEPT
351
{
352
    if (is_invalid_proof_of_work(proof_of_work_limit, scrypt))
×
353
        return error::invalid_proof_of_work;
×
354
    if (is_invalid_timestamp(timestamp_limit_seconds))
×
355
        return error::futuristic_timestamp;
×
356

357
    return error::block_success;
×
358
}
359

360
// minimum_block_version
361
// median_time_past
362
// work_required
363

364
// Checkpoints and previous_block_hash are chain validation (not here).
365
// bits_ below is the consensus direct comparison of the header.bits value.
366
// All other work comparisons performed on expanded/normalized bits values.
367
code header::accept(const context& ctx) const NOEXCEPT
×
368
{
369
    if (version_ < ctx.minimum_block_version)
×
370
        return error::invalid_block_version;
×
371
    if (timestamp_ <= ctx.median_time_past)
×
372
        return error::timestamp_too_early;
×
373
    if (bits_ != ctx.work_required)
×
374
        return error::incorrect_proof_of_work;
×
375

376
    return error::block_success;
×
377
}
378

379
// JSON value convertors.
380
// ----------------------------------------------------------------------------
381

382
namespace json = boost::json;
383

384
// boost/json will soon have NOEXCEPT: github.com/boostorg/json/pull/636
385
BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
386

387
header tag_invoke(json::value_to_tag<header>,
2✔
388
    const json::value& value) NOEXCEPT
389
{
390
    hash_digest previous, merkle_root;
2✔
391
    if (!decode_hash(previous, value.at("previous").get_string().c_str()) ||
4✔
392
        !decode_hash(merkle_root, value.at("merkle_root").get_string().c_str()))
2✔
393
        return {};
×
394

395
    return
2✔
396
    {
397
        value.at("version").to_number<uint32_t>(),
2✔
398
        previous,
399
        merkle_root,
400
        value.at("timestamp").to_number<uint32_t>(),
2✔
401
        value.at("bits").to_number<uint32_t>(),
2✔
402
        value.at("nonce").to_number<uint32_t>()
4✔
403
    };
8✔
404
}
405

406
void tag_invoke(json::value_from_tag, json::value& value,
4✔
407
    const header& tx) NOEXCEPT
408
{
409
    value =
16✔
410
    {
411
        { "version", tx.version() },
412
        { "previous", encode_hash(tx.previous_block_hash()) },
4✔
413
        { "merkle_root", encode_hash(tx.merkle_root()) },
8✔
414
        { "timestamp", tx.timestamp() },
415
        { "bits", tx.bits() },
416
        { "nonce", tx.nonce() }
417
    };
4✔
418
}
4✔
419

420
BC_POP_WARNING()
421

422
header::cptr tag_invoke(json::value_to_tag<header::cptr>,
×
423
    const json::value& value) NOEXCEPT
424
{
425
    return to_shared(tag_invoke(json::value_to_tag<header>{}, value));
×
426
}
427

428
// Shared pointer overload is required for navigation.
429
BC_PUSH_WARNING(SMART_PTR_NOT_NEEDED)
430
BC_PUSH_WARNING(NO_VALUE_OR_CONST_REF_SHARED_PTR)
431

432
void tag_invoke(json::value_from_tag tag, json::value& value,
×
433
    const header::cptr& tx) NOEXCEPT
434
{
435
    tag_invoke(tag, value, *tx);
×
436
}
×
437

438
BC_POP_WARNING()
439
BC_POP_WARNING()
440

441
} // namespace chain
442
} // namespace system
443
} // 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

© 2025 Coveralls, Inc