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

libbitcoin / libbitcoin-system / 14917173188

08 May 2025 10:15PM UTC coverage: 82.739% (+0.1%) from 82.628%
14917173188

push

github

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

Fix machine|chain include cycles, refactor opcode utils.

120 of 147 new or added lines in 8 files covered. (81.63%)

1 existing line in 1 file now uncovered.

10287 of 12433 relevant lines covered (82.74%)

3875327.57 hits per line

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

96.24
/include/bitcoin/system/impl/machine/program.ipp
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
#ifndef LIBBITCOIN_SYSTEM_MACHINE_PROGRAM_IPP
20
#define LIBBITCOIN_SYSTEM_MACHINE_PROGRAM_IPP
21

22
#include <iterator>
23
#include <utility>
24
#include <variant>
25
#include <bitcoin/system/chain/chain.hpp>
26
#include <bitcoin/system/crypto/crypto.hpp>
27
#include <bitcoin/system/data/data.hpp>
28
#include <bitcoin/system/define.hpp>
29
#include <bitcoin/system/math/math.hpp>
30

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

35
using namespace system::chain;
36
using namespace system::error;
37

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

41
// Input script run (default/empty stack).
42
// 'tx' must remain in scope, this holds state referenced by weak pointers.
43
// This expectation is guaranteed by the retained tx reference.
44
TEMPLATE
45
inline CLASS::
1,559✔
46
program(const chain::transaction& tx, const input_iterator& input,
47
     uint32_t active_flags) NOEXCEPT
48
  : transaction_(tx),
1,559✔
49
    input_(input),
1,559✔
50
    script_((*input)->script_ptr()),
1,559✔
51
    flags_(active_flags),
1,559✔
52
    value_(max_uint64),
1,559✔
53
    version_(script_version::unversioned),
1,559✔
54
    witness_(),
55
    primary_()
1,559✔
56
{
57
}
1,559✔
58

59
// Legacy p2sh or prevout script run (copied input stack - use first).
60
// 'other' must remain in scope, this holds state referenced by weak pointers.
61
// This expectation is guaranteed by the retained transaction_ member reference
62
// and copied program tether (which is not tx state).
63
TEMPLATE
64
inline CLASS::
1,496✔
65
program(const program& other, const script::cptr& script) NOEXCEPT
66
  : transaction_(other.transaction_),
1,496✔
67
    input_(other.input_),
1,496✔
68
    script_(script),
69
    flags_(other.flags_),
1,496✔
70
    value_(other.value_),
1,496✔
71
    version_(other.version_),
1,496✔
72
    witness_(),
73
    primary_(other.primary_)
1,496✔
74
{
75
}
1,496✔
76

77
// Legacy p2sh or prevout script run (moved input stack/tether - use last).
78
TEMPLATE
79
inline CLASS::
17✔
80
program(program&& other, const script::cptr& script) NOEXCEPT
81
  : transaction_(other.transaction_),
17✔
82
    input_(other.input_),
17✔
83
    script_(script),
84
    flags_(other.flags_),
17✔
85
    value_(other.value_),
17✔
86
    version_(other.version_),
17✔
87
    witness_(),
88
    primary_(std::move(other.primary_))
17✔
89
{
90
}
17✔
91

92
// Witness script run (witness-initialized stack).
93
// 'tx', 'input' (and iterated chain::input) must remain in scope, as these
94
// hold chunk state weak references. A witness pointer is explicitly retained
95
// to guarantee the lifetime of its elements.
96
TEMPLATE
97
inline CLASS::
23✔
98
program(const chain::transaction& tx, const input_iterator& input,
99
    const script::cptr& script, uint32_t active_flags, script_version version,
100
    const chunk_cptrs_ptr& witness) NOEXCEPT
101
  : transaction_(tx),
23✔
102
    input_(input),
23✔
103
    script_(script),
104
    flags_(active_flags),
23✔
105
    value_((*input)->prevout->value()),
23✔
106
    version_(version),
23✔
107
    witness_(witness),
108
    primary_(projection<Stack>(*witness))
69✔
109
{
110
}
23✔
111

112
// Public.
113
// ----------------------------------------------------------------------------
114

115
TEMPLATE
116
inline bool CLASS::
1,088✔
117
is_true(bool clean_stack) const NOEXCEPT
118
{
119
    return (!clean_stack || is_stack_clean()) && !is_stack_empty() &&
3,244✔
120
        peek_bool_();
1,088✔
121
}
122

123
TEMPLATE
124
inline const data_chunk& CLASS::
17✔
125
pop() NOEXCEPT
126
{
127
    BC_ASSERT_MSG(!is_stack_empty(), "pop from empty stack");
128

129
    return *pop_chunk_();
17✔
130
}
131

132
// Non-public.
133
// ============================================================================
134

135
TEMPLATE
136
INLINE typename CLASS::op_iterator CLASS::
3,033✔
137
begin() const NOEXCEPT
138
{
139
    return script_->ops().begin();
3,033✔
140
}
141

142
TEMPLATE
143
INLINE typename CLASS::op_iterator CLASS::
25,009✔
144
end() const NOEXCEPT
145
{
146
    return script_->ops().end();
25,009✔
147
}
148

149
TEMPLATE
150
INLINE const chain::input& CLASS::
18✔
151
input() const NOEXCEPT
152
{
153
    return **input_;
154
}
155

156
TEMPLATE
157
INLINE const chain::transaction& CLASS::
7✔
158
transaction() const NOEXCEPT
159
{
160
    return transaction_;
7✔
161
}
162

163
TEMPLATE
164
INLINE bool CLASS::
36,934✔
165
is_enabled(chain::flags flag) const NOEXCEPT
166
{
167
    return to_bool(flags_ & flag);
4,811✔
168
}
169

170
TEMPLATE
171
INLINE script_error_t CLASS::
3,095✔
172
validate() const NOEXCEPT
173
{
174
    // TODO: nops rule must first be enabled in tests and config.
175
    const auto nops = true; ////is_enabled(flags::nops_rule);
176
    const auto bip141 = is_enabled(flags::bip141_rule);
177
    const auto bip342 = is_enabled(flags::bip342_rule);
178

179
    // Apply stack element limit (520) to initial witness [bip141][tapscript].
180
    if (bip141 && witness_ && !witness::is_push_size(*witness_))
3,095✔
181
        return error::invalid_witness_stack;
182

183
    // Script size limit (10,000) [0.3.7+], removed [tapscript].
184
    if (!bip342 && nops && script_->is_oversized())
3,095✔
185
        return error::invalid_script_size;
186

187
    // Stacks element limit (1,000) applied to initial stack [tapscript].
NEW
188
    if (bip342 && is_stack_overflow())
×
189
        return error::invalid_stack_size;
190

191
    // Succeed if any success code, one overrides all codes [tapscript].
NEW
192
    if (bip342 && script_->is_prevalid())
×
193
        return error::prevalid_script;
194

195
    // Fail if last op underflow, lower priority than easy [tapscript].
196
    if (script_->is_underflow())
3,093✔
197
        return error::invalid_script;
198

199
    // Fail if any op invalid (invalid codes reduced in tapscript).
200
    if (script_->is_prefail())
3,093✔
201
        return error::prefail_script;
202

203
    return error::script_success;
204
}
205

206
// Primary stack (conversions).
207
// ----------------------------------------------------------------------------
208

209
// static
210
TEMPLATE
211
INLINE bool CLASS::
560✔
212
equal_chunks(const stack_variant& left, const stack_variant& right) NOEXCEPT
213
{
214
    return primary_stack::equal_chunks(left, right);
560✔
215
}
216

217
TEMPLATE
218
INLINE bool CLASS::
1,593✔
219
peek_bool_() const NOEXCEPT
220
{
221
    return primary_.peek_bool();
1,593✔
222
}
223

224
TEMPLATE
225
INLINE chunk_xptr CLASS::
3,578✔
226
peek_chunk_() const NOEXCEPT
227
{
228
    return primary_.peek_chunk();
3,578✔
229
}
230

231
TEMPLATE
232
INLINE size_t CLASS::
58✔
233
peek_size() const NOEXCEPT
234
{
235
    return primary_.peek_size();
58✔
236
}
237

238
// Primary stack (push).
239
// ----------------------------------------------------------------------------
240

241
// This is the only source of push (write) tethering.
242
TEMPLATE
243
INLINE void CLASS::
167✔
244
push_chunk(data_chunk&& datum) NOEXCEPT
245
{
246
    primary_.push(std::move(datum));
247
}
248

249
// Passing data_chunk& would be poor interface design, as it would allow
250
// derived callers to (unsafely) store raw pointers to unshared data_chunk.
251
BC_PUSH_WARNING(SMART_PTR_NOT_NEEDED)
252
BC_PUSH_WARNING(NO_VALUE_OR_CONST_REF_SHARED_PTR)
253
TEMPLATE
254
INLINE void CLASS::
4,474✔
255
push_chunk(const chunk_cptr& datum) NOEXCEPT
256
BC_POP_WARNING()
257
BC_POP_WARNING()
258
{
259
    primary_.emplace_chunk(datum.get());
8,948✔
260
}
261

262
// private
263
TEMPLATE
264
INLINE void CLASS::
265
push_chunk(const chunk_xptr& datum) NOEXCEPT
266
{
267
    primary_.emplace_chunk(datum);
268
}
269

270
TEMPLATE
271
INLINE void CLASS::
2,018✔
272
push_bool(bool value) NOEXCEPT
273
{
274
    primary_.emplace_boolean(value);
2,018✔
275
}
276

277
TEMPLATE
278
INLINE void CLASS::
7,256✔
279
push_signed64(int64_t value) NOEXCEPT
280
{
281
    primary_.emplace_integer(value);
7,073✔
282
}
283

284
TEMPLATE
285
INLINE void CLASS::
241✔
286
push_length(size_t value) NOEXCEPT
287
{
288
    // This is guarded by stack size and push data limits.
289
    BC_ASSERT_MSG(value <= max_int64, "integer overflow");
290

291
    push_signed64(possible_narrow_sign_cast<int64_t>(value));
241✔
292
}
293

294
// Primary stack (pop).
295
// ----------------------------------------------------------------------------
296

297
// This tethers a chunk if the stack value is not chunk.
298
TEMPLATE
299
INLINE chunk_xptr CLASS::
3,552✔
300
pop_chunk_() NOEXCEPT
301
{
302
    const auto value = peek_chunk_();
303
    drop_();
304
    return value;
193✔
305
}
306

307
// This tethers chunks if the stack values are not chunk.
308
TEMPLATE
309
INLINE bool CLASS::
4,102✔
310
pop_chunks(chunk_xptrs& data, size_t count) NOEXCEPT
311
{
312
    if (stack_size() < count)
4,102✔
313
        return false;
314

315
    data.reserve(count);
4,102✔
316
    for (size_t index = 0; index < count; ++index)
7,444✔
317
        data.push_back(pop_chunk_());
3,342✔
318

319
    return true;
320
}
321

322
TEMPLATE
323
INLINE bool CLASS::
2,050✔
324
pop_strict_bool_() NOEXCEPT
325
{
326
    const auto value = primary_.peek_strict_bool();
2,050✔
327
    drop_();
328
    return value;
329
}
330

331
TEMPLATE
332
INLINE bool CLASS::
446✔
333
pop_bool_(bool& value, bool minimal) NOEXCEPT
334
{
335
    if (!minimal)
446✔
336
        value = peek_bool_();
446✔
337
    else if (!primary_.peek_minimal_bool(value))
×
338
        return false;
339

340
    drop_();
341
    return true;
342
}
343

344
TEMPLATE
345
INLINE bool CLASS::
4,738✔
346
pop_signed32_(int32_t& value) NOEXCEPT
347
{
348
    const auto result = peek_signed32_(value);
349
    drop_();
350
    return result;
351
}
352

353
TEMPLATE
354
INLINE bool CLASS::
4,272✔
355
pop_signed32(int32_t& value) NOEXCEPT
356
{
357
    if (is_stack_empty())
4,272✔
358
        return false;
359

360
    return pop_signed32_(value);
361
}
362

363
TEMPLATE
364
INLINE bool CLASS::
242✔
365
pop_binary32(int32_t& left, int32_t& right) NOEXCEPT
366
{
367
    if (stack_size() < 2)
242✔
368
        return false;
369

370
    // The right hand side operand is at the top of the stack.
371
    return pop_signed32_(right) && pop_signed32_(left);
430✔
372
}
373

374
TEMPLATE
375
INLINE bool CLASS::
18✔
376
pop_ternary32(int32_t& upper, int32_t& lower,
377
    int32_t& value) NOEXCEPT
378
{
379
    if (stack_size() < 3)
18✔
380
        return false;
381

382
    // The upper bound is at stack top, lower bound next, value next.
383
    return pop_signed32_(upper) && pop_signed32_(lower) &&
48✔
384
        pop_signed32_(value);
385
}
386

387
// ****************************************************************************
388
// CONSENSUS: Satoshi limits this value to the int32_t domain (getint()).
389
// This value is only used for stack indexing (key/sig counts & pick/roll).
390
// The upper bound of int32_t always exceeds the possible stack size, which
391
// is checked downstream. Similarly, a negative causes a downstream script
392
// failure. As such it is sufficient to fail on non-idexability here,
393
// allowing the value to be returned as a valid and unsigned stack index.
394
// ****************************************************************************
395
TEMPLATE
396
INLINE bool CLASS::
4,160✔
397
pop_index32(size_t& index) NOEXCEPT
398
{
399
    int32_t value;
400
    if (!pop_signed32(value))
4,160✔
401
        return false;
402

403
    if (is_negative(value))
4,160✔
404
        return false;
405

406
    // Cast guarded by stack size.
407
    index = limit<size_t>(value);
46✔
408

409
    // True if popped value valid post-pop stack index (precluded if size < 2).
410
    return index < stack_size();
4,156✔
411
}
412

413
// private
414
TEMPLATE
415
INLINE bool CLASS::
246✔
416
peek_signed32_(int32_t& value) const NOEXCEPT
417
{
418
    return primary_.peek_signed4(value);
4,492✔
419
}
420

421
// private
422
TEMPLATE
423
INLINE bool CLASS::
12✔
424
peek_signed40_(int64_t& value) const NOEXCEPT
425
{
426
    return primary_.peek_signed5(value);
12✔
427
}
428

429
// ****************************************************************************
430
// CONSENSUS: Read of 40 bit (vs. 32 bit) value for comparison against uint32_t
431
// input.sequence allows use of the full unsigned 32 bit domain, without use of
432
// the negative range.
433
// ****************************************************************************
434
TEMPLATE
435
INLINE bool CLASS::
×
436
peek_unsigned32(uint32_t& value) const NOEXCEPT
437
{
438
    if (is_stack_empty())
×
439
        return false;
440

441
    int64_t signed64;
442
    if (!peek_signed40_(signed64) || is_negative(signed64))
×
443
        return false;
444

445
    // 32 bits are used in unsigned input.sequence compare.
446
    value = narrow_sign_cast<uint32_t>(signed64);
447
    return true;
×
448
}
449

450
// ****************************************************************************
451
// CONSENSUS: Read of 40 bit (vs. 32 bit) value for comparison against uint32_t
452
// input.locktime allows use of the full unsigned 32 bit domain, without use of
453
// the negative range. Otherwise a 2038 limit (vs. the inherent 2106 limit)
454
// would have been introduced.
455
// ****************************************************************************
456
TEMPLATE
457
INLINE bool CLASS::
18✔
458
peek_unsigned40(uint64_t& value) const NOEXCEPT
459
{
460
    if (is_stack_empty())
18✔
461
        return false;
462

463
    int64_t signed64;
464
    if (!peek_signed40_(signed64) || is_negative(signed64))
12✔
465
        return false;
466

467
    // 40 bits are usable in unsigned tx.locktime compare.
468
    value = sign_cast<uint64_t>(signed64);
469
    return true;
7✔
470
}
471

472
// Primary stack (variant - index).
473
// ----------------------------------------------------------------------------
474
// Stack index is zero-based, back() is element zero.
475

476
// This swaps the variant elements of the stack vector.
477
TEMPLATE
478
INLINE void CLASS::
174✔
479
swap_(size_t left_index, size_t right_index) NOEXCEPT
480
{
481
    primary_.swap(left_index, right_index);
482
}
483

484
TEMPLATE
485
INLINE void CLASS::
16✔
486
erase_(size_t index) NOEXCEPT
487
{
488
    primary_.erase(index);
489
}
490

491
TEMPLATE
492
INLINE const stack_variant& CLASS::
9,916✔
493
peek_(size_t index) const NOEXCEPT
494
{
495
    return primary_.peek(index);
496
}
497

498
// Primary stack (variant - top).
499
// ----------------------------------------------------------------------------
500

501
TEMPLATE
502
INLINE void CLASS::
10,901✔
503
drop_() NOEXCEPT
504
{
505
    primary_.drop();
506
}
507

508
TEMPLATE
509
INLINE void CLASS::
9,957✔
510
push_variant(const stack_variant& vary) NOEXCEPT
511
{
512
    primary_.push(vary);
513
}
4✔
514

515
TEMPLATE
516
INLINE const stack_variant& CLASS::
35✔
517
peek_() const NOEXCEPT
518
{
519
    return primary_.top();
520
}
521

522
TEMPLATE
523
INLINE stack_variant CLASS::
1,138✔
524
pop_() NOEXCEPT
525
{
526
    return primary_.pop();
527
}
528

529
// Primary stack state (untyped).
530
// ----------------------------------------------------------------------------
531

532
TEMPLATE
533
INLINE size_t CLASS::
12,749✔
534
stack_size() const NOEXCEPT
535
{
536
    return primary_.size();
537
}
538

539
TEMPLATE
540
INLINE bool CLASS::
8,289✔
541
is_stack_empty() const NOEXCEPT
542
{
543
    return primary_.empty();
544
}
545

546
TEMPLATE
547
INLINE bool CLASS::
20,900✔
548
is_stack_overflow() const NOEXCEPT
549
{
550
    // Addition is safe due to stack size constraint.
551
    // Limit of 1000 elements in stack and altstack remains [tapscript]. 
552
    return (stack_size() + alternate_.size()) > max_unified_stack_size;
20,900✔
553
}
554

555
// private
556
TEMPLATE
557
INLINE bool CLASS::
21✔
558
is_stack_clean() const NOEXCEPT
559
{
560
    return is_one(stack_size());
561
}
562

563
// Alternate stack.
564
// ----------------------------------------------------------------------------
565

566
TEMPLATE
567
INLINE bool CLASS::
10✔
568
is_alternate_empty() const NOEXCEPT
569
{
570
    return alternate_.empty();
571
}
572

573
// Moving a shared pointer to the alternate stack is optimal and acceptable.
574
BC_PUSH_WARNING(NO_RVALUE_REF_SHARED_PTR)
575
TEMPLATE
576
INLINE void CLASS::
18✔
577
push_alternate(stack_variant&& vary) NOEXCEPT
578
BC_POP_WARNING()
579
{
580
    BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
581
    alternate_.push_back(std::move(vary));
18✔
582
    BC_POP_WARNING()
583
}
584

585
TEMPLATE
586
INLINE stack_variant CLASS::
6✔
587
pop_alternate_() NOEXCEPT
588
{
589
    BC_ASSERT(!alternate_.empty());
590

591
    stack_variant value{ std::move(alternate_.back()) };
6✔
592
    alternate_.pop_back();
6✔
593
    return value;
6✔
594
}
595

596
// Conditional stack.
597
// ----------------------------------------------------------------------------
598

599
TEMPLATE
600
INLINE void CLASS::
474✔
601
begin_if(bool value) NOEXCEPT
602
{
603
    // Addition is safe due to script size constraint.
604
    BC_ASSERT(value || !is_add_overflow(negative_conditions_, one));
605

606
    negative_conditions_ += (value ? 0 : 1);
474✔
607
    condition_.push_back(value);
474✔
608
}
609

610
// ****************************************************************************
611
// CONSENSUS: "You may have noticed the strange behavior of Bitcoin's ELSE
612
// statement. Bitcoin allows one to switch between true and false conditions
613
// several times. For example, the following script is valid and leaves the
614
// value 2 on the stack: 1 OP_IF OP_ELSE OP_ELSE 2 OP_ENDIF"
615
// bitslog.com/2017/04/17/new-quadratic-delays-in-bitcoin-scripts
616
// ****************************************************************************
617
TEMPLATE
618
INLINE void CLASS::
442✔
619
else_if_() NOEXCEPT
620
{
621
    // Subtraction must be guarded by caller logical constraints.
622
    BC_ASSERT(!is_balanced());
623

624
    // Addition is safe due to script size constraint.
625
    BC_ASSERT(condition_.back() || !is_add_overflow(negative_conditions_, one));
626

627
    negative_conditions_ += (condition_.back() ? 1 : -1);
442✔
628
    condition_.back() = !condition_.back();
442✔
629
}
630

631
TEMPLATE
632
INLINE void CLASS::
308✔
633
end_if_() NOEXCEPT
634
{
635
    // Subtraction must be guarded by caller logical constraints.
636
    BC_ASSERT(!is_balanced());
637

638
    negative_conditions_ += (condition_.back() ? 0 : -1);
308✔
639
    condition_.pop_back();
308✔
640
}
641

642
TEMPLATE
643
INLINE bool CLASS::
3,368✔
644
is_balanced() const NOEXCEPT
645
{
646
    return condition_.empty();
3,368✔
647
}
648

649
TEMPLATE
650
INLINE bool CLASS::
21,630✔
651
is_succeess() const NOEXCEPT
652
{
653
    // Optimization changes O(n) search [for every operation] to O(1).
654
    // bitslog.com/2017/04/17/new-quadratic-delays-in-bitcoin-scripts
655
    return is_zero(negative_conditions_);
21,630✔
656
}
657

658
TEMPLATE
659
INLINE bool CLASS::
22,402✔
660
if_(const operation& op) const NOEXCEPT
661
{
662
    // Conditional op execution is not predicated on conditional stack.
663
    return op.is_conditional() || is_succeess();
22,402✔
664
}
665

666
//  Accumulator.
667
// ----------------------------------------------------------------------------
668

669
// ****************************************************************************
670
// CONSENSUS:
671
// Satoshi compares the count to 200 with a composed postfix increment, which
672
// makes the actual maximum 201, not the presumably-intended 200. The code was
673
// later revised to make this explicit, by use of a prefix increment against a
674
// limit of 201.
675
// ****************************************************************************
676
INLINE constexpr bool operation_count_exceeded(size_t count) NOEXCEPT
677
{
678
    return count > max_counted_ops;
679
}
680

681
TEMPLATE
682
INLINE bool CLASS::
22,409✔
683
ops_increment(const operation& op) NOEXCEPT
684
{
685
    // Non-push opcodes limit of 201 per script does not apply [tapscript].
686
    if (is_enabled(flags::bip342_rule))
22,409✔
687
        return true;
688

689
    // Addition is safe due to script size constraint.
690
    BC_ASSERT(!is_add_overflow(operations_, one));
691

692
    if (operation::is_counted(op.code()))
22,409✔
693
        ++operations_;
10,530✔
694

695
    return operations_ <= max_counted_ops;
22,409✔
696
}
697

698
TEMPLATE
699
INLINE bool CLASS::
2,058✔
700
ops_increment(size_t public_keys) NOEXCEPT
701
{
702
    // Non-push opcodes limit of 201 per script does not apply [tapscript].
703
    if (is_enabled(flags::bip342_rule))
2,058✔
704
        return true;
705

706
    // Addition is safe due to script size constraint.
707
    BC_ASSERT(!is_add_overflow(operations_, public_keys));
708

709
    operations_ += public_keys;
2,058✔
710
    return !operation_count_exceeded(operations_);
2,058✔
711
}
712

713
// Signature validation helpers.
714
// ----------------------------------------------------------------------------
715

716
// Subscripts are referenced by script.offset mutable metadata. This allows for
717
// efficient subscripting with no copying. However, concurrent execution of any
718
// one input script instance is not thread safe (unnecessary scenario).
719
TEMPLATE
720
inline void CLASS::
9✔
721
set_subscript(const op_iterator& op) NOEXCEPT
722
{
723
    // Not possible unless op is not an element of script_.
724
    BC_ASSERT(!script_->ops().empty() && op != script_->ops().end());
725

726
    // Advance the offset to the op following the found code separator.
727
    // This is non-const because changes script state (despite being mutable).
728
    script_->offset = std::next(op);
9✔
729
}
730

731
inline chain::strippers create_strip_ops(
1,958✔
732
    const chunk_xptrs& endorsements) NOEXCEPT
733
{
734
    chain::strippers strip{};
1,958✔
735

736
    BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
737
    strip.reserve(add1(endorsements.size()));
1,958✔
738

739
    for (const auto& endorsement: endorsements)
1,980✔
740
        strip.emplace_back(endorsement);
22✔
741

742
    strip.emplace_back(opcode::codeseparator);
1,958✔
743
    BC_POP_WARNING()
744

745
    return strip;
1,958✔
746
}
747

748
// ****************************************************************************
749
// CONSENSUS: Endorsement and code separator stripping are always performed in
750
// conjunction and are limited to non-witness signature hash subscripts.
751
// The order of operations is inconsequential, as they are all removed.
752
// Subscripts are not evaluated, they are limited to signature hash creation.
753
// ****************************************************************************
754
TEMPLATE
755
inline script::cptr CLASS::
1,975✔
756
subscript(const chunk_xptrs& endorsements) const NOEXCEPT
757
{
758
    // bip141: establishes the version property.
759
    // bip143: op stripping is not applied to bip141 v0 scripts.
760
    if (is_enabled(flags::bip143_rule) && version_ == script_version::zero)
1,975✔
761
        return script_;
762

763
    // Transform into a set of endorsement push ops and one op_codeseparator.
764
    const auto strip = create_strip_ops(endorsements);
1,958✔
765
    const auto stop = script_->ops().end();
1,958✔
766
    const op_iterator offset{ script_->offset };
1,958✔
767

768
    // If none of the strip ops are found, return the subscript.
769
    if (!is_intersecting<operations>(offset, stop, strip))
1,958✔
770
        return script_;
771

772
    // Create new script from stripped copy of subscript operations.
773
    return to_shared<script>(difference<operations>(offset, stop, strip));
8✔
774
}
1,958✔
775

776
// TODO: use sighash and key to generate signature in sign mode.
777
TEMPLATE
778
inline bool CLASS::
26✔
779
prepare(ec_signature& signature, const data_chunk&, hash_digest& hash,
780
    const chunk_xptr& endorsement) const NOEXCEPT
781
{
782
    uint8_t sighash_flags;
783
    data_slice distinguished;
26✔
784

785
    // Parse Bitcoin endorsement into DER signature and sighash flags.
786
    if (!parse_endorsement(sighash_flags, distinguished, *endorsement))
26✔
787
        return false;
788

789
    // Obtain the signature hash from subscript and sighash flags.
790
    hash = signature_hash(*subscript({ endorsement }), sighash_flags);
78✔
791

792
    // Parse DER signature into an ECDSA signature (bip66 sets strict).
793
    const auto bip66 = is_enabled(flags::bip66_rule);
794
    return parse_signature(signature, distinguished, bip66);
26✔
795
}
796

797
// TODO: use sighash and key to generate signature in sign mode.
798
TEMPLATE
799
inline bool CLASS::
20✔
800
prepare(ec_signature& signature, const data_chunk&, hash_cache& cache,
801
    uint8_t& sighash_flags, const data_chunk& endorsement,
802
    const script& sub) const NOEXCEPT
803
{
804
    data_slice distinguished;
20✔
805

806
    // Parse Bitcoin endorsement into DER signature and sighash flags.
807
    if (!parse_endorsement(sighash_flags, distinguished, endorsement))
20✔
808
        return false;
809

810
    // Obtain the signature hash from subscript and sighash flags.
811
    signature_hash(cache, sub, sighash_flags);
20✔
812

813
    // Parse DER signature into an ECDSA signature (bip66 sets strict).
814
    const auto bip66 = is_enabled(flags::bip66_rule);
815
    return parse_signature(signature, distinguished, bip66);
20✔
816
}
817

818
// Signature hashing.
819
// ----------------------------------------------------------------------------
820

821
TEMPLATE
822
INLINE hash_digest CLASS::
26✔
823
signature_hash(const script& sub, uint8_t flags) const NOEXCEPT
824
{
825
    // The bip141 fork establishes witness version, hashing is a distinct fork.
826
    const auto bip143 = is_enabled(flags::bip143_rule);
827

828
    // bip143: the method of signature hashing is changed for v0 scripts.
829
    return transaction_.signature_hash(input_, sub, value_, flags, version_,
36✔
830
        bip143);
831
}
832

833
// Caches signature hashes in a map against sighash flags.
834
// Prevents recomputation in the common case where flags are the same.
835
TEMPLATE
836
INLINE void CLASS::
20✔
837
signature_hash(hash_cache& cache, const script& sub,
838
    uint8_t sighash_flags) const NOEXCEPT
839
{
840
    BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
841
    if (cache.find(sighash_flags) == cache.end())
20✔
842
        cache.emplace(sighash_flags, signature_hash(sub, sighash_flags));
10✔
843
    BC_POP_WARNING()
844
}
845

846
} // namespace machine
847
} // namespace system
848
} // namespace libbitcoin
849

850
#endif
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