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

libbitcoin / libbitcoin-system / 9952171247

16 Jul 2024 06:56AM UTC coverage: 83.171% (-0.03%) from 83.203%
9952171247

push

github

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

Avoid unnecessary witness initializations, style, comments.

12 of 27 new or added lines in 3 files covered. (44.44%)

5 existing lines in 1 file now uncovered.

10092 of 12134 relevant lines covered (83.17%)

4758960.56 hits per line

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

78.5
/src/chain/input.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/input.hpp>
20

21
#include <algorithm>
22
#include <memory>
23
#include <utility>
24
#include <bitcoin/system/chain/context.hpp>
25
#include <bitcoin/system/chain/enums/magic_numbers.hpp>
26
#include <bitcoin/system/chain/point.hpp>
27
#include <bitcoin/system/chain/prevout.hpp>
28
#include <bitcoin/system/chain/script.hpp>
29
#include <bitcoin/system/chain/witness.hpp>
30
#include <bitcoin/system/define.hpp>
31
#include <bitcoin/system/math/math.hpp>
32
#include <bitcoin/system/stream/stream.hpp>
33

34
namespace libbitcoin {
35
namespace system {
36
namespace chain {
37

38
BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
39

40
// Product overflows guarded by script size limit.
41
static_assert(max_script_size < 
42
    max_size_t / multisig_default_sigops / heavy_sigops_factor,
43
    "input sigop overflow guard");
44

45
// static/private
46
const witness& input::no_witness() NOEXCEPT
18✔
47
{
48
    static const chain::witness empty_witness{};
18✔
49
    return empty_witness;
18✔
50
}
51

52
// static/private
NEW
53
const witness::cptr& input::no_witness_cptr() NOEXCEPT
×
54
{
55
    BC_PUSH_WARNING(NO_NEW_OR_DELETE)
NEW
56
    static const std::shared_ptr<const chain::witness> empty
×
57
    {
NEW
58
        new const chain::witness{}
×
NEW
59
    };
×
60
    BC_POP_WARNING()
NEW
61
    return empty;
×
62
}
63

64
// Constructors.
65
// ----------------------------------------------------------------------------
66

67
// Default point is null_hash and point::null_index. 
68
// Default metadata is spent, invalid, max_size_t value. 
69
input::input() NOEXCEPT
22✔
70
  : input(
71
      to_shared<chain::point>(),
22✔
72
      to_shared<chain::script>(),
22✔
73
      to_shared<chain::witness>(),
22✔
74
      0, false)
88✔
75
{
76
}
22✔
77

78
input::input(chain::point&& point, chain::script&& script,
160✔
79
    uint32_t sequence) NOEXCEPT
160✔
80
  : input(
81
      to_shared(std::move(point)),
160✔
82
      to_shared(std::move(script)),
160✔
83
      to_shared<chain::witness>(),
160✔
84
      sequence, true)
320✔
85
{
86
}
160✔
87

88
input::input(const chain::point& point, const chain::script& script,
734✔
89
    uint32_t sequence) NOEXCEPT
734✔
90
  : input(
91
      to_shared(point),
734✔
92
      to_shared(script),
734✔
93
      to_shared<chain::witness>(),
734✔
94
      sequence, true)
1,468✔
95
{
96
}
734✔
97

98
input::input(const chain::point::cptr& point,
×
99
    const chain::script::cptr& script, uint32_t sequence) NOEXCEPT
×
100
  : input(
101
      point ? point : to_shared<chain::point>(),
×
102
      script ? script : to_shared<chain::script>(),
×
103
      to_shared<chain::witness>(),
×
104
      sequence, true)
×
105
{
106
}
×
107

108
input::input(chain::point&& point, chain::script&& script,
14✔
109
    chain::witness&& witness, uint32_t sequence) NOEXCEPT
14✔
110
  : input(
111
      to_shared(std::move(point)),
14✔
112
      to_shared(std::move(script)),
14✔
113
      to_shared(std::move(witness)),
14✔
114
      sequence, true)
14✔
115
{
116
}
14✔
117

118
input::input(const chain::point& point, const chain::script& script,
1✔
119
    const chain::witness& witness, uint32_t sequence) NOEXCEPT
1✔
120
  : input(
121
      to_shared(point),
1✔
122
      to_shared(script),
123
      to_shared(witness),
1✔
124
      sequence, true)
1✔
125
{
126
}
1✔
127

128
input::input(const chain::point::cptr& point, const chain::script::cptr& script,
×
129
    const chain::witness::cptr& witness, uint32_t sequence) NOEXCEPT
×
130
  : input(point, script, witness, sequence, true)
×
131
{
132
}
×
133

134
input::input(const data_slice& data) NOEXCEPT
5✔
135
  : input(stream::in::copy(data))
5✔
136
{
137
}
5✔
138

139
////input::input(stream::in::fast&& stream) NOEXCEPT
140
////  : input(read::bytes::fast(stream))
141
////{
142
////}
143

144
input::input(stream::in::fast& stream) NOEXCEPT
1✔
145
  : input(read::bytes::fast(stream))
1✔
146
{
147
}
1✔
148

149
input::input(std::istream&& stream) NOEXCEPT
5✔
150
  : input(read::bytes::istream(stream))
5✔
151
{
152
}
5✔
153

154
input::input(std::istream& stream) NOEXCEPT
3✔
155
  : input(read::bytes::istream(stream))
3✔
156
{
157
}
3✔
158

159
input::input(reader&& source) NOEXCEPT
9✔
160
  : input(source/*from_data(source)*/)
9✔
161
{
162
}
×
163

164
// Witness is deserialized and assigned by transaction.
165
input::input(reader& source) NOEXCEPT
255✔
166
////: input(from_data(source))
167
  : point_(
255✔
168
        source.get_allocator().new_object<chain::point>(source),
255✔
169
        source.get_allocator().deleter<chain::point>(source.get_arena())),
255✔
170
    script_(
510✔
171
        source.get_allocator().new_object<chain::script>(source, true),
510✔
172
        source.get_allocator().deleter<chain::script>(source.get_arena())),
255✔
173
    witness_(nullptr),
174
    sequence_(source.read_4_bytes_little_endian()),
255✔
175
    valid_(source),
255✔
176
    size_(serialized_size(*script_))
510✔
177
{
178
    ////assign_data(source);
179
}
255✔
180

181
// protected
182
input::input(const chain::point::cptr& point, const chain::script::cptr& script,
931✔
183
    const chain::witness::cptr& witness, uint32_t sequence, bool valid) NOEXCEPT
931✔
184
  : point_(point),
185
    script_(script),
186
    witness_(witness),
187
    sequence_(sequence),
931✔
188
    valid_(valid),
931✔
189
    size_(serialized_size(*script, *witness))
1,862✔
190
{
191
}
931✔
192

193
// Operators.
194
// ----------------------------------------------------------------------------
195

196
bool input::operator==(const input& other) const NOEXCEPT
43✔
197
{
198
    return (sequence_ == other.sequence_)
43✔
199
        && (point_ == other.point_ || *point_ == *other.point_)
41✔
200
        && (script_ == other.script_ || *script_ == *other.script_)
41✔
201
        && (witness_ == other.witness_ || get_witness() == other.get_witness());
84✔
202
}
203

204
bool input::operator!=(const input& other) const NOEXCEPT
2✔
205
{
206
    return !(*this == other);
2✔
207
}
208

209
// Deserialization.
210
// ----------------------------------------------------------------------------
211

212
////// static/private
213
////input input::from_data(reader& source) NOEXCEPT
214
////{
215
////    // Witness is deserialized by transaction.
216
////    return
217
////    {
218
////        to_shared<chain::point>(source),
219
////        to_shared<chain::script>(source, true),
220
////        to_shared<chain::witness>(),
221
////        source.read_4_bytes_little_endian(),
222
////        source
223
////    };
224
////}
225

226
////// private
227
////void input::assign_data(reader& source) NOEXCEPT
228
////{
229
////    auto& allocator = source.get_allocator();
230
////    
231
////    allocator.construct<chain::point::cptr>(&point_,
232
////        allocator.new_object<chain::point>(source),
233
////        allocator.deleter<chain::point>(source.get_arena()));
234
////    
235
////    allocator.construct<chain::script::cptr>(&script_,
236
////        allocator.new_object<chain::script>(source, true),
237
////        allocator.deleter<chain::script>(source.get_arena()));
238
////    
239
////    // Witness is deserialized and assigned by transaction.
240
////    allocator.construct<chain::witness::cptr>(&witness_, nullptr);
241
////    
242
////    sequence_ = source.read_4_bytes_little_endian();
243
////    size_ = serialized_size(*script_);
244
////    valid_ = source;
245
////}
246

247
// Serialization.
248
// ----------------------------------------------------------------------------
249

250
data_chunk input::to_data() const NOEXCEPT
1✔
251
{
252
    data_chunk data(serialized_size(false));
1✔
253
    stream::out::copy ostream(data);
1✔
254
    to_data(ostream);
1✔
255
    return data;
2✔
256
}
1✔
257

258
void input::to_data(std::ostream& stream) const NOEXCEPT
2✔
259
{
260
    write::bytes::ostream out(stream);
2✔
261
    to_data(out);
2✔
262
}
2✔
263

264
// Witness is serialized by transaction.
265
void input::to_data(writer& sink) const NOEXCEPT
1,392✔
266
{
267
    point_->to_data(sink);
1,392✔
268
    script_->to_data(sink, true);
1,392✔
269
    sink.write_4_bytes_little_endian(sequence_);
1,392✔
270
}
1,392✔
271

272
// static/private
273
input::sizes input::serialized_size(const chain::script& script) NOEXCEPT
255✔
274
{
275
    constexpr auto const_size = ceilinged_add(
255✔
276
        point::serialized_size(),
277
        sizeof(sequence_));
278

279
    const auto nominal_size = ceilinged_add(
255✔
280
        const_size,
281
        script.serialized_size(true));
282

283
    return { nominal_size, zero };
255✔
284
}
285

286
// static/private
287
input::sizes input::serialized_size(const chain::script& script,
931✔
288
    const chain::witness& witness) NOEXCEPT
289
{
290
    constexpr auto const_size = ceilinged_add(
931✔
291
        point::serialized_size(),
292
        sizeof(sequence_));
293

294
    const auto nominal_size = ceilinged_add(
931✔
295
        const_size,
296
        script.serialized_size(true));
297

298
    const auto witnessed_size = ceilinged_add(
931✔
299
        nominal_size,
300
        witness.serialized_size(true));
301

302
    return { nominal_size, witnessed_size };
931✔
303
}
304

305
// input.serialized_size(witness) provides sizing for witness, however
306
// witnesses are serialized by the transaction. This is an ugly hack as a
307
// consequence of bip144 not serializing witnesses as part of inputs, which
308
// is logically the proper association.
309
size_t input::serialized_size(bool witness) const NOEXCEPT
2✔
310
{
311
    return witness ? size_.witnessed : size_.nominal;
2✔
312
}
313

314
// Friend accessors (private).
315
// ----------------------------------------------------------------------------
316

317
size_t input::nominal_size() const NOEXCEPT
2,130✔
318
{
319
    return size_.nominal;
2,130✔
320
}
321

322
size_t input::witnessed_size() const NOEXCEPT
46✔
323
{
324
    return size_.witnessed;
46✔
325
}
326

327
////void input::set_witness(reader& source) NOEXCEPT
328
////{
329
////    witness_ = to_shared<chain::witness>(source, true);
330
////    size_.witnessed = ceilinged_add(size_.nominal,
331
////        witness_->serialized_size(true));
332
////}
333

334
void input::set_witness(reader& source) NOEXCEPT
20✔
335
{
336
    auto& allocator = source.get_allocator();
20✔
337

338
    witness_.reset(
20✔
339
        allocator.new_object<chain::witness>(source, true),
20✔
340
        allocator.deleter<chain::witness>(source.get_arena()));
20✔
341

342
    size_.witnessed = ceilinged_add(size_.nominal,
20✔
343
        witness_->serialized_size(true));
344
}
20✔
345

346
// Properties.
347
// ----------------------------------------------------------------------------
348

349
bool input::is_valid() const NOEXCEPT
16✔
350
{
351
    return valid_;
16✔
352
}
353

354
const point& input::point() const NOEXCEPT
169✔
355
{
356
    return *point_;
10✔
357
}
358

359
const chain::script& input::script() const NOEXCEPT
75✔
360
{
361
    return *script_;
10✔
362
}
363

364
const chain::witness& input::witness() const NOEXCEPT
1,893✔
365
{
366
    return get_witness();
1,893✔
367
}
368

369
const point::cptr& input::point_ptr() const NOEXCEPT
×
370
{
371
    return point_;
×
372
}
373

374
const chain::script::cptr& input::script_ptr() const NOEXCEPT
1,555✔
375
{
376
    return script_;
1,555✔
377
}
378

379
const chain::witness::cptr& input::witness_ptr() const NOEXCEPT
×
380
{
NEW
381
    return get_witness_cptr();
×
382
}
383

384
uint32_t input::sequence() const NOEXCEPT
73✔
385
{
386
    return sequence_;
10✔
387
}
388

389
// Methods.
390
// ----------------------------------------------------------------------------
391

392
bool input::is_final() const NOEXCEPT
22✔
393
{
394
    return sequence_ == max_input_sequence;
22✔
395
}
396

397
bool input::is_roller() const NOEXCEPT
4✔
398
{
399
    return script_->is_roller() || (prevout && prevout->script().is_roller());
4✔
400
}
401

402
// static
403
bool input::is_locked(uint32_t sequence, size_t height,
10✔
404
    uint32_t median_time_past, size_t prevout_height,
405
    uint32_t prevout_median_time_past) NOEXCEPT
406
{
407
    // BIP68: if bit 31 is set then no consensus meaning is applied.
408
    if (get_right(sequence, relative_locktime_disabled_bit))
10✔
409
        return false;
410

411
    // BIP68: the low 16 bits of the sequence apply to relative lock-time.
412
    const auto blocks = mask_left(sequence, relative_locktime_mask_left);
8✔
413

414
    // BIP68: bit 22 determines if relative lock is time or block based.
415
    if (get_right(sequence, relative_locktime_time_locked_bit))
8✔
416
    {
417
        // BIP68: change sequence to seconds by shift up by 9 bits (x 512).
418
        auto time = shift_left(blocks, relative_locktime_seconds_shift_left);
3✔
419
        auto age = floored_subtract(median_time_past, prevout_median_time_past);
3✔
420
        return age < time;
3✔
421
    }
422

423
    const auto age = floored_subtract(height, prevout_height);
5✔
424
    return age < blocks;
5✔
425
}
426

427
bool input::is_locked(size_t height, uint32_t median_time_past) const NOEXCEPT
10✔
428
{
429
    // Prevout must be found and height/median_time_past metadata populated.
430
    ////BC_ASSERT(!is_zero(metadata.height));
431
    return is_locked(sequence_, height, median_time_past, metadata.height,
10✔
432
        metadata.median_time_past);
10✔
433
}
434

435
bool input::reserved_hash(hash_digest& out) const NOEXCEPT
×
436
{
NEW
437
    if (!witness::is_reserved_pattern(get_witness().stack()))
×
438
        return false;
439

NEW
440
    std::copy_n(get_witness().stack().front()->begin(), hash_size, out.begin());
×
441
    return true;
×
442
}
443

444
// private
445
// prevout_script is only used to determine is_pay_script_hash_pattern.
446
bool input::extract_sigop_script(chain::script& out,
×
447
    const chain::script& prevout_script) const NOEXCEPT
448
{
449
    // There are no embedded sigops when the prevout script is not p2sh.
450
    if (!script::is_pay_script_hash_pattern(prevout_script.ops()))
×
451
        return false;
452

453
    // There are no embedded sigops when the input script is not push only.
454
    const auto& ops = script_->ops();
×
455
    if (ops.empty() || !script::is_relaxed_push_pattern(ops))
×
456
        return false;
×
457

458
    // Parse the embedded script from the last input script item (data).
459
    // This cannot fail because there is no prefix to invalidate the length.
460
    out = { ops.back().data(), false };
×
461
    return true;
×
462
}
463

464
// TODO: Prior to block 79400 sigops were limited only by policy.
465
// TODO: Create legacy sigops fork/flag and pass here, return 0 if false.
466
// TODO: this was an unbipped flag day soft fork, prior to BIP16/141.
467
// TODO: if (nHeight > 79400 && GetSigOpCount() > MAX_BLOCK_SIGOPS).
468
size_t input::signature_operations(bool bip16, bool bip141) const NOEXCEPT
7✔
469
{
470
    // Penalize quadratic signature operations (bip141).
471
    const auto factor = bip141 ? heavy_sigops_factor : one;
7✔
472
    const auto sigops = script_->signature_operations(false) * factor;
7✔
473

474
    // ************************************************************************
475
    // CONSENSUS: coinbase input cannot execute, but sigops are counted anyway.
476
    // ************************************************************************
477
    if (!prevout)
7✔
478
        return sigops;
479

480
    // Null prevout/input (coinbase) cannot have witness or embedded script.
481
    // Embedded/witness scripts are deserialized here and again on scipt eval.
482

483
    chain::script witness;
×
NEW
484
    if (bip141 && get_witness().extract_sigop_script(witness, prevout->script()))
×
485
    {
486
        // Add sigops in the witness script (bip141).
487
        return ceilinged_add(sigops, witness.signature_operations(true));
×
488
    }
489

490
    chain::script embedded;
×
491
    if (bip16 && extract_sigop_script(embedded, prevout->script()))
×
492
    {
NEW
493
        if (bip141 && get_witness().extract_sigop_script(witness, embedded))
×
494
        {
495
            // Add sigops in the embedded witness script (bip141).
496
            return ceilinged_add(sigops, witness.signature_operations(true));
×
497
        }
498
        else
499
        {
500
            // Add heavy sigops in the embedded script (bip16).
501
            return ceilinged_add(sigops, embedded.signature_operations(true) *
×
502
                factor);
503
        }
504
    }
505

506
    return sigops;
507
}
×
508

509
BC_POP_WARNING()
510

511
// JSON value convertors.
512
// ----------------------------------------------------------------------------
513

514
namespace json = boost::json;
515

516
// boost/json will soon have NOEXCEPT: github.com/boostorg/json/pull/636
517
BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
518

519
input tag_invoke(json::value_to_tag<input>, const json::value& value) NOEXCEPT
5✔
520
{
521
    return
5✔
522
    {
523
        json::value_to<chain::point>(value.at("point")),
5✔
524
        json::value_to<chain::script>(value.at("script")),
5✔
525
        json::value_to<chain::witness>(value.at("witness")),
10✔
526
        value.at("sequence").to_number<uint32_t>()
10✔
527
    };
5✔
528
}
529

530
void tag_invoke(json::value_from_tag, json::value& value,
10✔
531
    const input& input) NOEXCEPT
532
{
533
    value =
20✔
534
    {
535
        { "point", input.point() },
536
        { "script", input.script() },
537
        { "witness", input.witness() },
538
        { "sequence", input.sequence() }
539
    };
10✔
540
}
10✔
541

542
BC_POP_WARNING()
543

544
input::cptr tag_invoke(json::value_to_tag<input::cptr>,
×
545
    const json::value& value) NOEXCEPT
546
{
547
    return to_shared(tag_invoke(json::value_to_tag<input>{}, value));
×
548
}
549

550
// Shared pointer overload is required for navigation.
551
BC_PUSH_WARNING(SMART_PTR_NOT_NEEDED)
552
BC_PUSH_WARNING(NO_VALUE_OR_CONST_REF_SHARED_PTR)
553

554
void tag_invoke(json::value_from_tag tag, json::value& value,
8✔
555
    const input::cptr& input) NOEXCEPT
556
{
557
    tag_invoke(tag, value, *input);
8✔
558
}
8✔
559

560
BC_POP_WARNING()
561
BC_POP_WARNING()
562

563
} // namespace chain
564
} // namespace system
565
} // 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