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

libbitcoin / libbitcoin-system / 15383478380

02 Jun 2025 03:58AM UTC coverage: 81.14% (+0.008%) from 81.132%
15383478380

push

github

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

Program initialize is_prevalid() insufficiently prioritized.

3 of 4 new or added lines in 1 file covered. (75.0%)

10433 of 12858 relevant lines covered (81.14%)

3686925.64 hits per line

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

93.5
/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 <utility>
23
#include <bitcoin/system/chain/chain.hpp>
24
#include <bitcoin/system/data/data.hpp>
25
#include <bitcoin/system/define.hpp>
26
#include <bitcoin/system/math/math.hpp>
27

28
namespace libbitcoin {
29
namespace system {
30
namespace machine {
31

32
// Public.
33
// ----------------------------------------------------------------------------
34

35
TEMPLATE
36
inline bool CLASS::
1,088✔
37
is_true(bool clean_stack) const NOEXCEPT
38
{
39
    return (!clean_stack || is_stack_clean()) && !is_stack_empty() &&
3,244✔
40
        peek_bool_();
1,088✔
41
}
42

43
TEMPLATE
44
inline const data_chunk& CLASS::
17✔
45
pop() NOEXCEPT
46
{
47
    BC_ASSERT_MSG(!is_stack_empty(), "pop from empty stack");
48

49
    return *pop_chunk_();
17✔
50
}
51

52
// Non-public.
53
// ============================================================================
54

55
TEMPLATE
56
INLINE error::script_error_t CLASS::
3,095✔
57
initialize() const NOEXCEPT
58
{
59
    // TODO: nops rule must first be enabled in tests and config.
60
    constexpr auto nops = true; ////is_enabled(flags::nops_rule);
61
    const auto bip141 = is_enabled(flags::bip141_rule);
62
    const auto bip342 = is_enabled(flags::bip342_rule);
63

64
    // Succeed if any success code, overrides all codes and errors [bip342].
NEW
65
    if (bip342 && script_->is_prevalid())
×
66
        return error::prevalid_script;
67

68
    // Fail if last op is underflow (same behavior as prefail, invalid code).
69
    if (script_->is_underflow())
3,095✔
70
        return error::invalid_script;
71

72
    // Stack limit (1,000) applied to initial stack [bip342].
73
    if (bip342 && is_stack_overflow())
3,095✔
74
        return error::invalid_stack_size;
75

76
    // Apply stack element limit (520) to initial witness [bip342|bip141].
77
    if ((bip342 || bip141) && witness_ && !chain::witness::is_push_size(*witness_))
3,095✔
78
        return error::invalid_witness_stack;
79

80
    // Script size limit (10,000) [0.3.7+], removed [bip342].
81
    if (!bip342 && nops && script_->is_oversized())
3,095✔
82
        return error::invalid_script_size;
83

84
    // Fail if any op invalid (invalid codes reduced in tapscript).
85
    // Should be after underflow check since underflow is also an invalid op.
86
    // Promoted success codes are not reachable here due to is_prevalid above.
87
    // So only op_verif/op_vernotif (unpromoted invalids) are caught here for
88
    // tapscript, otherwise is_prevalid bypassed and all invalids caught here.
89
    if (script_->is_prefail())
3,093✔
90
        return error::prefail_script;
91

92
    return error::script_success;
93
}
94

95
TEMPLATE
96
INLINE typename CLASS::op_iterator CLASS::
3,033✔
97
begin() const NOEXCEPT
98
{
99
    return script_->ops().begin();
3,033✔
100
}
101

102
TEMPLATE
103
INLINE typename CLASS::op_iterator CLASS::
25,009✔
104
end() const NOEXCEPT
105
{
106
    return script_->ops().end();
25,009✔
107
}
108

109
TEMPLATE
110
INLINE const chain::transaction& CLASS::
7✔
111
tx() const NOEXCEPT
112
{
113
    return transaction_;
7✔
114
}
115

116
TEMPLATE
117
INLINE const chain::input& CLASS::
18✔
118
input() const NOEXCEPT
119
{
120
    return **input_;
121
}
122

123
TEMPLATE
124
INLINE bool CLASS::
38,819✔
125
is_enabled(flags flag) const NOEXCEPT
126
{
127
    return to_bool(flags_ & flag);
11,856✔
128
}
129

130
// Primary stack (conversions).
131
// ----------------------------------------------------------------------------
132

133
// static
134
TEMPLATE
135
INLINE bool CLASS::
560✔
136
equal_chunks(const stack_variant& left, const stack_variant& right) NOEXCEPT
137
{
138
    return primary_stack::equal_chunks(left, right);
560✔
139
}
140

141
TEMPLATE
142
INLINE bool CLASS::
1,593✔
143
peek_bool_() const NOEXCEPT
144
{
145
    return primary_.peek_bool();
1,593✔
146
}
147

148
TEMPLATE
149
INLINE chunk_xptr CLASS::
3,578✔
150
peek_chunk_() const NOEXCEPT
151
{
152
    return primary_.peek_chunk();
3,578✔
153
}
154

155
TEMPLATE
156
INLINE size_t CLASS::
58✔
157
peek_size() const NOEXCEPT
158
{
159
    return primary_.peek_size();
58✔
160
}
161

162
// Primary stack (push).
163
// ----------------------------------------------------------------------------
164

165
// This is the only source of push (write) tethering.
166
TEMPLATE
167
INLINE void CLASS::
167✔
168
push_chunk(data_chunk&& datum) NOEXCEPT
169
{
170
    primary_.push(std::move(datum));
171
}
172

173
// Passing data_chunk& would be poor interface design, as it would allow
174
// derived callers to (unsafely) store raw pointers to unshared data_chunk.
175
BC_PUSH_WARNING(SMART_PTR_NOT_NEEDED)
176
BC_PUSH_WARNING(NO_VALUE_OR_CONST_REF_SHARED_PTR)
177
TEMPLATE
178
INLINE void CLASS::
4,474✔
179
push_chunk(const chunk_cptr& datum) NOEXCEPT
180
BC_POP_WARNING()
181
BC_POP_WARNING()
182
{
183
    primary_.emplace_chunk(datum.get());
8,948✔
184
}
185

186
// private
187
TEMPLATE
188
INLINE void CLASS::
189
push_chunk(const chunk_xptr& datum) NOEXCEPT
190
{
191
    primary_.emplace_chunk(datum);
192
}
193

194
TEMPLATE
195
INLINE void CLASS::
2,018✔
196
push_bool(bool value) NOEXCEPT
197
{
198
    primary_.emplace_boolean(value);
2,018✔
199
}
200

201
TEMPLATE
202
INLINE void CLASS::
7,256✔
203
push_signed64(int64_t value) NOEXCEPT
204
{
205
    primary_.emplace_integer(value);
7,073✔
206
}
207

208
TEMPLATE
209
INLINE void CLASS::
241✔
210
push_length(size_t value) NOEXCEPT
211
{
212
    // This is guarded by stack size and push data limits.
213
    BC_ASSERT_MSG(value <= max_int64, "integer overflow");
214

215
    push_signed64(possible_narrow_sign_cast<int64_t>(value));
241✔
216
}
217

218
// Primary stack (pop).
219
// ----------------------------------------------------------------------------
220

221
// This tethers a chunk if the stack value is not chunk.
222
TEMPLATE
223
INLINE chunk_xptr CLASS::
3,552✔
224
pop_chunk_() NOEXCEPT
225
{
226
    const auto value = peek_chunk_();
227
    drop_();
228
    return value;
193✔
229
}
230

231
// This tethers chunks if the stack values are not chunk.
232
TEMPLATE
233
INLINE bool CLASS::
4,102✔
234
pop_chunks(chunk_xptrs& data, size_t count) NOEXCEPT
235
{
236
    if (stack_size() < count)
4,102✔
237
        return false;
238

239
    data.reserve(count);
4,102✔
240
    for (size_t index = 0; index < count; ++index)
7,444✔
241
        data.push_back(pop_chunk_());
3,342✔
242

243
    return true;
244
}
245

246
TEMPLATE
247
INLINE bool CLASS::
2,050✔
248
pop_strict_bool_() NOEXCEPT
249
{
250
    const auto value = primary_.peek_strict_bool();
2,050✔
251
    drop_();
252
    return value;
253
}
254

255
TEMPLATE
256
INLINE bool CLASS::
446✔
257
pop_bool_(bool& value, bool minimal) NOEXCEPT
258
{
259
    if (!minimal)
446✔
260
        value = peek_bool_();
446✔
261
    else if (!primary_.peek_minimal_bool(value))
×
262
        return false;
263

264
    drop_();
265
    return true;
266
}
267

268
TEMPLATE
269
INLINE bool CLASS::
4,738✔
270
pop_signed32_(int32_t& value) NOEXCEPT
271
{
272
    const auto result = peek_signed32_(value);
273
    drop_();
274
    return result;
275
}
276

277
TEMPLATE
278
INLINE bool CLASS::
4,272✔
279
pop_signed32(int32_t& value) NOEXCEPT
280
{
281
    if (is_stack_empty())
4,272✔
282
        return false;
283

284
    return pop_signed32_(value);
285
}
286

287
TEMPLATE
288
INLINE bool CLASS::
242✔
289
pop_binary32(int32_t& left, int32_t& right) NOEXCEPT
290
{
291
    if (stack_size() < 2)
242✔
292
        return false;
293

294
    // The right hand side operand is at the top of the stack.
295
    return pop_signed32_(right) && pop_signed32_(left);
430✔
296
}
297

298
TEMPLATE
299
INLINE bool CLASS::
18✔
300
pop_ternary32(int32_t& upper, int32_t& lower,
301
    int32_t& value) NOEXCEPT
302
{
303
    if (stack_size() < 3)
18✔
304
        return false;
305

306
    // The upper bound is at stack top, lower bound next, value next.
307
    return pop_signed32_(upper) && pop_signed32_(lower) &&
48✔
308
        pop_signed32_(value);
309
}
310

311
// ****************************************************************************
312
// CONSENSUS: Satoshi limits this value to the int32_t domain (getint()).
313
// This value is only used for stack indexing (key/sig counts & pick/roll).
314
// The upper bound of int32_t always exceeds the possible stack size, which
315
// is checked downstream. Similarly, a negative causes a downstream script
316
// failure. As such it is sufficient to fail on non-idexability here,
317
// allowing the value to be returned as a valid and unsigned stack index.
318
// ****************************************************************************
319
TEMPLATE
320
INLINE bool CLASS::
4,160✔
321
pop_index32(size_t& index) NOEXCEPT
322
{
323
    int32_t value;
324
    if (!pop_signed32(value))
4,160✔
325
        return false;
326

327
    if (is_negative(value))
4,160✔
328
        return false;
329

330
    // Cast guarded by stack size.
331
    index = limit<size_t>(value);
46✔
332

333
    // True if popped value valid post-pop stack index (precluded if size < 2).
334
    return index < stack_size();
4,156✔
335
}
336

337
// private
338
TEMPLATE
339
INLINE bool CLASS::
246✔
340
peek_signed32_(int32_t& value) const NOEXCEPT
341
{
342
    return primary_.peek_signed4(value);
4,492✔
343
}
344

345
// private
346
TEMPLATE
347
INLINE bool CLASS::
12✔
348
peek_signed40_(int64_t& value) const NOEXCEPT
349
{
350
    return primary_.peek_signed5(value);
12✔
351
}
352

353
// ****************************************************************************
354
// CONSENSUS: Read of 40 bit (vs. 32 bit) value for comparison against uint32_t
355
// input.sequence allows use of the full unsigned 32 bit domain, without use of
356
// the negative range.
357
// ****************************************************************************
358
TEMPLATE
359
INLINE bool CLASS::
×
360
peek_unsigned32(uint32_t& value) const NOEXCEPT
361
{
362
    if (is_stack_empty())
×
363
        return false;
364

365
    int64_t signed64;
366
    if (!peek_signed40_(signed64) || is_negative(signed64))
×
367
        return false;
368

369
    // 32 bits are used in unsigned input.sequence compare.
370
    value = narrow_sign_cast<uint32_t>(signed64);
371
    return true;
×
372
}
373

374
// ****************************************************************************
375
// CONSENSUS: Read of 40 bit (vs. 32 bit) value for comparison against uint32_t
376
// input.locktime allows use of the full unsigned 32 bit domain, without use of
377
// the negative range. Otherwise a 2038 limit (vs. the inherent 2106 limit)
378
// would have been introduced.
379
// ****************************************************************************
380
TEMPLATE
381
INLINE bool CLASS::
18✔
382
peek_unsigned40(uint64_t& value) const NOEXCEPT
383
{
384
    if (is_stack_empty())
18✔
385
        return false;
386

387
    int64_t signed64;
388
    if (!peek_signed40_(signed64) || is_negative(signed64))
12✔
389
        return false;
390

391
    // 40 bits are usable in unsigned tx.locktime compare.
392
    value = sign_cast<uint64_t>(signed64);
393
    return true;
7✔
394
}
395

396
// Primary stack (variant - index).
397
// ----------------------------------------------------------------------------
398
// Stack index is zero-based, back() is element zero.
399

400
// This swaps the variant elements of the stack vector.
401
TEMPLATE
402
INLINE void CLASS::
174✔
403
swap_(size_t left_index, size_t right_index) NOEXCEPT
404
{
405
    primary_.swap(left_index, right_index);
406
}
407

408
TEMPLATE
409
INLINE void CLASS::
16✔
410
erase_(size_t index) NOEXCEPT
411
{
412
    primary_.erase(index);
413
}
414

415
TEMPLATE
416
INLINE const stack_variant& CLASS::
9,916✔
417
peek_(size_t index) const NOEXCEPT
418
{
419
    return primary_.peek(index);
420
}
421

422
// Primary stack (variant - top).
423
// ----------------------------------------------------------------------------
424

425
TEMPLATE
426
INLINE void CLASS::
10,901✔
427
drop_() NOEXCEPT
428
{
429
    primary_.drop();
430
}
431

432
TEMPLATE
433
INLINE void CLASS::
9,957✔
434
push_variant(const stack_variant& vary) NOEXCEPT
435
{
436
    primary_.push(vary);
437
}
4✔
438

439
TEMPLATE
440
INLINE const stack_variant& CLASS::
35✔
441
peek_() const NOEXCEPT
442
{
443
    return primary_.top();
444
}
445

446
TEMPLATE
447
INLINE stack_variant CLASS::
1,138✔
448
pop_() NOEXCEPT
449
{
450
    return primary_.pop();
451
}
452

453
// Primary stack state (untyped).
454
// ----------------------------------------------------------------------------
455

456
TEMPLATE
457
INLINE size_t CLASS::
12,749✔
458
stack_size() const NOEXCEPT
459
{
460
    return primary_.size();
461
}
462

463
TEMPLATE
464
INLINE bool CLASS::
8,289✔
465
is_stack_empty() const NOEXCEPT
466
{
467
    return primary_.empty();
468
}
469

470
TEMPLATE
471
INLINE bool CLASS::
20,900✔
472
is_stack_overflow() const NOEXCEPT
473
{
474
    // Addition is safe due to stack size constraint.
475
    // Limit of 1000 elements in stack and altstack remains [bip342]. 
476
    return (stack_size() + alternate_.size()) > chain::max_unified_stack_size;
20,900✔
477
}
478

479
// private
480
TEMPLATE
481
INLINE bool CLASS::
21✔
482
is_stack_clean() const NOEXCEPT
483
{
484
    return is_one(stack_size());
485
}
486

487
// Alternate stack.
488
// ----------------------------------------------------------------------------
489

490
TEMPLATE
491
INLINE bool CLASS::
10✔
492
is_alternate_empty() const NOEXCEPT
493
{
494
    return alternate_.empty();
495
}
496

497
// Moving a shared pointer to the alternate stack is optimal and acceptable.
498
BC_PUSH_WARNING(NO_RVALUE_REF_SHARED_PTR)
499
TEMPLATE
500
INLINE void CLASS::
18✔
501
push_alternate(stack_variant&& vary) NOEXCEPT
502
BC_POP_WARNING()
503
{
504
    alternate_.push_back(std::move(vary));
18✔
505
}
506

507
TEMPLATE
508
INLINE stack_variant CLASS::
6✔
509
pop_alternate_() NOEXCEPT
510
{
511
    BC_ASSERT(!alternate_.empty());
512

513
    stack_variant value{ std::move(alternate_.back()) };
6✔
514
    alternate_.pop_back();
6✔
515
    return value;
6✔
516
}
517

518
// Conditional stack.
519
// ----------------------------------------------------------------------------
520

521
TEMPLATE
522
INLINE void CLASS::
474✔
523
begin_if(bool value) NOEXCEPT
524
{
525
    // Addition is safe due to script size constraint.
526
    BC_ASSERT(value || !is_add_overflow(negative_conditions_, one));
527

528
    negative_conditions_ += (value ? 0 : 1);
474✔
529
    condition_.push_back(value);
474✔
530
}
531

532
// ****************************************************************************
533
// CONSENSUS: "You may have noticed the strange behavior of Bitcoin's ELSE
534
// statement. Bitcoin allows one to switch between true and false conditions
535
// several times. For example, the following script is valid and leaves the
536
// value 2 on the stack: 1 OP_IF OP_ELSE OP_ELSE 2 OP_ENDIF"
537
// bitslog.com/2017/04/17/new-quadratic-delays-in-bitcoin-scripts
538
// ****************************************************************************
539
TEMPLATE
540
INLINE void CLASS::
442✔
541
else_if_() NOEXCEPT
542
{
543
    // Subtraction must be guarded by caller logical constraints.
544
    BC_ASSERT(!is_balanced());
545

546
    // Addition is safe due to script size constraint.
547
    BC_ASSERT(condition_.back() || !is_add_overflow(negative_conditions_, one));
548

549
    negative_conditions_ += (condition_.back() ? 1 : -1);
442✔
550
    condition_.back() = !condition_.back();
442✔
551
}
552

553
TEMPLATE
554
INLINE void CLASS::
308✔
555
end_if_() NOEXCEPT
556
{
557
    // Subtraction must be guarded by caller logical constraints.
558
    BC_ASSERT(!is_balanced());
559

560
    negative_conditions_ += (condition_.back() ? 0 : -1);
308✔
561
    condition_.pop_back();
308✔
562
}
563

564
TEMPLATE
565
INLINE bool CLASS::
3,368✔
566
is_balanced() const NOEXCEPT
567
{
568
    return condition_.empty();
3,368✔
569
}
570

571
TEMPLATE
572
INLINE bool CLASS::
21,630✔
573
is_succeess() const NOEXCEPT
574
{
575
    // Optimization changes O(n) search [for every operation] to O(1).
576
    // bitslog.com/2017/04/17/new-quadratic-delays-in-bitcoin-scripts
577
    return is_zero(negative_conditions_);
21,630✔
578
}
579

580
TEMPLATE
581
INLINE bool CLASS::
22,402✔
582
if_(const operation& op) const NOEXCEPT
583
{
584
    // Conditional op execution is not predicated on conditional stack.
585
    return op.is_conditional() || is_succeess();
22,402✔
586
}
587

588
//  Accumulator.
589
// ----------------------------------------------------------------------------
590

591
// ****************************************************************************
592
// CONSENSUS:
593
// Satoshi compares the count to 200 with a composed postfix increment, which
594
// makes the actual maximum 201, not the presumably-intended 200. The code was
595
// later revised to make this explicit, by use of a prefix increment against a
596
// limit of 201.
597
// ****************************************************************************
598
INLINE constexpr bool operation_count_exceeded(size_t count) NOEXCEPT
599
{
600
    return count > chain::max_counted_ops;
601
}
602

603
TEMPLATE
604
INLINE bool CLASS::
×
605
sigops_increment() NOEXCEPT
606
{
607
    BC_ASSERT(is_enabled(flags::bip342_rule));
608

609
    // Executing signature op with non-empty signature decrements budget by 50.
610
    // If the budget falls below zero script fails immediately [bip342].
611

612
    // Budget initialized add1(50) to make it zero-based, avoiding signed type.
613
    budget_ = floored_subtract(budget_, chain::signature_cost);
×
614
    return !is_zero(budget_);
615
}
616

617
TEMPLATE
618
INLINE bool CLASS::
22,409✔
619
ops_increment(const operation& op) NOEXCEPT
620
{
621
    // Non-push opcodes limit of 201 per script does not apply [bip342].
622
    if (is_enabled(flags::bip342_rule))
22,409✔
623
        return true;
624

625
    // Addition is safe due to script size constraint.
626
    BC_ASSERT(!is_add_overflow(operations_, one));
627

628
    if (operation::is_counted(op.code()))
22,409✔
629
        ++operations_;
10,530✔
630

631
    return operations_ <= chain::max_counted_ops;
22,409✔
632
}
633

634
TEMPLATE
635
INLINE bool CLASS::
2,058✔
636
ops_increment(size_t public_keys) NOEXCEPT
637
{
638
    // Non-push opcodes limit of 201 per script does not apply [bip342].
639
    if (is_enabled(flags::bip342_rule))
2,058✔
640
        return true;
641

642
    // Addition is safe due to script size constraint.
643
    BC_ASSERT(!is_add_overflow(operations_, public_keys));
644

645
    operations_ += public_keys;
2,058✔
646
    return !operation_count_exceeded(operations_);
2,058✔
647
}
648

649
} // namespace machine
650
} // namespace system
651
} // namespace libbitcoin
652

653
#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