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

libbitcoin / libbitcoin-system / 14434326165

13 Apr 2025 11:21PM UTC coverage: 82.798% (-0.1%) from 82.939%
14434326165

push

github

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

Move golomb_coding from /crypto to new /filter folder.

62 of 64 new or added lines in 13 files covered. (96.88%)

32 existing lines in 9 files now uncovered.

10190 of 12307 relevant lines covered (82.8%)

3818174.07 hits per line

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

80.5
/src/chain/script.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/script.hpp>
20

21
#include <algorithm>
22
#include <iterator>
23
#include <numeric>
24
#include <sstream>
25
#include <utility>
26
#include <bitcoin/system/chain/enums/coverage.hpp>
27
#include <bitcoin/system/chain/enums/flags.hpp>
28
#include <bitcoin/system/chain/enums/script_pattern.hpp>
29
#include <bitcoin/system/chain/enums/script_version.hpp>
30
#include <bitcoin/system/chain/enums/magic_numbers.hpp>
31
#include <bitcoin/system/chain/enums/opcode.hpp>
32
#include <bitcoin/system/chain/operation.hpp>
33
#include <bitcoin/system/chain/transaction.hpp>
34
#include <bitcoin/system/chain/witness.hpp>
35
#include <bitcoin/system/data/data.hpp>
36
#include <bitcoin/system/define.hpp>
37
#include <bitcoin/system/error/error.hpp>
38
#include <bitcoin/system/hash/hash.hpp>
39
#include <bitcoin/system/machine/machine.hpp>
40
#include <bitcoin/system/radix/radix.hpp>
41
#include <bitcoin/system/stream/stream.hpp>
42

43
namespace libbitcoin {
44
namespace system {
45
namespace chain {
46

47
using namespace bc::system::machine;
48

49
BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
50

51
// static
52
// TODO: would be inlined but machine is a circular include.
53
//*****************************************************************************
54
// CONSENSUS: BIP34 requires coinbase input script to begin with one byte
55
// that indicates height size. This is inconsistent with an extreme future
56
// where the size byte overflows. However satoshi actually requires nominal
57
// encoding.
58
//*************************************************************************
59
bool script::is_coinbase_pattern(const operations& ops, size_t height) NOEXCEPT
×
60
{
61
    BC_PUSH_WARNING(NO_ARRAY_INDEXING)
62
    return !ops.empty()
×
63
        && ops[0].is_nominal_push()
×
64
        && ops[0].data() == number::chunk::from_integer(to_unsigned(height));
×
65
    BC_POP_WARNING()
66
}
67

68
// Constructors.
69
// ----------------------------------------------------------------------------
70

71
script::script() NOEXCEPT
130✔
72
  : script(operations{}, false, false, zero)
260✔
73
{
74
}
130✔
75

76
script::~script() NOEXCEPT
4,394✔
77
{
78
}
4,394✔
79

80
script::script(script&& other) NOEXCEPT
370✔
81
  : script(std::move(other.ops_), other.valid_, other.prefail_, other.size_)
370✔
82
{
83
}
370✔
84

85
script::script(const script& other) NOEXCEPT
1,474✔
86
  : script(other.ops_, other.valid_, other.prefail_, other.size_)
1,474✔
87
{
88
}
1,474✔
89

90
// Prefail is false.
91
script::script(operations&& ops) NOEXCEPT
225✔
92
  : script(std::move(ops), true, false)
225✔
93
{
94
    // ops moved so cannot pass serialized_size(ops), order not guaranteed.
95
}
225✔
96

97
// Prefail is false.
98
script::script(const operations& ops) NOEXCEPT
1✔
99
  : script(ops, true, false, serialized_size(ops))
1✔
100
{
101
}
1✔
102

103
script::script(operations&& ops, bool prefail) NOEXCEPT
1,498✔
104
  : script(std::move(ops), true, prefail)
1,498✔
105
{
106
    // ops moved so cannot pass serialized_size(ops), order not guaranteed.
107
}
1,498✔
108

109
script::script(const operations& ops, bool prefail) NOEXCEPT
×
110
  : script(ops, true, prefail, serialized_size(ops))
×
111
{
112
}
×
113

114
script::script(stream::in::fast&& stream, bool prefix) NOEXCEPT
133✔
115
  : script(read::bytes::fast(stream), prefix)
133✔
116
{
117
}
133✔
118

119
script::script(stream::in::fast& stream, bool prefix) NOEXCEPT
1✔
120
  : script(read::bytes::fast(stream), prefix)
1✔
121
{
122
}
1✔
123

UNCOV
124
script::script(std::istream&& stream, bool prefix) NOEXCEPT
×
UNCOV
125
  : script(read::bytes::istream(stream), prefix)
×
126
{
UNCOV
127
}
×
128

129
script::script(std::istream& stream, bool prefix) NOEXCEPT
1✔
130
  : script(read::bytes::istream(stream), prefix)
1✔
131
{
132
}
1✔
133

134
script::script(reader&& source, bool prefix) NOEXCEPT
135✔
135
  : script(source, prefix)
135✔
136
{
137
}
×
138

139
script::script(reader& source, bool prefix) NOEXCEPT
696✔
140
  : ops_(source.get_arena())
696✔
141
{
142
    assign_data(source, prefix);
696✔
143
}
696✔
144

145
script::script(const std::string& mnemonic) NOEXCEPT
1,502✔
146
  : script(from_string(mnemonic))
1,502✔
147
{
148
}
1,502✔
149

150
// protected
151
script::script(operations&& ops, bool valid, bool prefail) NOEXCEPT
1,723✔
152
  : ops_(std::move(ops)),
153
    valid_(valid),
1,723✔
154
    prefail_(prefail),
1,723✔
155
    size_(serialized_size(ops_)),
1,723✔
156
    offset(ops_.begin())
1,723✔
157
{
158
}
1,723✔
159

160
// protected
161
script::script(const operations& ops, bool valid, bool prefail) NOEXCEPT
×
162
  : ops_(ops),
×
163
    valid_(valid),
×
164
    prefail_(prefail),
×
165
    size_(serialized_size(ops)),
×
166
    offset(ops_.begin())
×
167
{
168
}
×
169

170
// protected
171
script::script(const operations& ops, bool valid, bool prefail,
1,975✔
172
    size_t size) NOEXCEPT
1,975✔
173
  : ops_(ops),
1,975✔
174
    valid_(valid),
1,975✔
175
    prefail_(prefail),
1,975✔
176
    size_(size),
130✔
177
    offset(ops_.begin())
1,975✔
178
{
179
}
×
180

181
// Operators.
182
// ----------------------------------------------------------------------------
183

184
script& script::operator=(script&& other) NOEXCEPT
4✔
185
{
186
    ops_ = std::move(other.ops_);
4✔
187
    valid_ = other.valid_;
4✔
188
    prefail_ = other.prefail_;
4✔
189
    size_ = other.size_;
4✔
190
    offset = ops_.begin();
4✔
191
    return *this;
4✔
192
}
193

194
script& script::operator=(const script& other) NOEXCEPT
×
195
{
196
    ops_ = other.ops_;
×
197
    valid_ = other.valid_;
×
198
    prefail_ = other.prefail_;
×
199
    size_ = other.size_;
×
200
    offset = ops_.begin();
×
201
    return *this;
×
202
}
203

204
bool script::operator==(const script& other) const NOEXCEPT
87✔
205
{
206
    return size_ == other.size_
87✔
207
        && ops_ == other.ops_;
87✔
208
}
209

210
bool script::operator!=(const script& other) const NOEXCEPT
×
211
{
212
    return !(*this == other);
×
213
}
214

215
// Deserialization.
216
// ----------------------------------------------------------------------------
217

218
// static/private
219
size_t script::op_count(reader& source) NOEXCEPT
696✔
220
{
221
    // Stream errors reset by set_position so trap here.
222
    if (!source)
696✔
223
        return zero;
224

225
    const auto start = source.get_read_position();
696✔
226
    auto count = zero;
696✔
227

228
    // This is expensive (1.1%) but far less than vector reallocs (11.6%).
229
    while (operation::count_op(source))
84,083✔
230
        ++count;
82,691✔
231

232
    source.set_position(start);
696✔
233
    return count;
696✔
234
}
235

236
// private
237
void script::assign_data(reader& source, bool prefix) NOEXCEPT
696✔
238
{
239
    size_t expected{};
696✔
240
    prefail_ = false;
696✔
241

242
    if (prefix)
696✔
243
    {
244
        expected = source.read_size();
567✔
245
        source.set_limit(expected);
567✔
246
    }
247

248
    ops_.reserve(op_count(source));
696✔
249
    const auto start = source.get_read_position();
696✔
250

251
    while (!source.is_exhausted())
84,083✔
252
    {
253
        ops_.emplace_back(source);
82,691✔
254
        prefail_ |= ops_.back().is_invalid();
82,691✔
255
    }
256

257
    size_ = source.get_read_position() - start;
696✔
258

259
    if (prefix)
696✔
260
    {
261
        source.set_limit();
567✔
262
        if (size_ != expected)
567✔
263
            source.invalidate();
2✔
264
    }
265

266
    valid_ = source;
696✔
267
    offset = ops_.begin();
696✔
268
}
696✔
269

270
// static/private
271
script script::from_string(const std::string& mnemonic) NOEXCEPT
1,502✔
272
{
273
    // There is always one operation per non-empty string token.
274
    auto tokens = split(mnemonic);
1,502✔
275
    auto prefail = false;
1,502✔
276

277
    // Split always returns at least one token, and when trimming it will be
278
    // empty only if there was nothing but whitespace in the mnemonic.
279
    if (tokens.front().empty())
1,502✔
280
        tokens.clear();
66✔
281

282
    operations ops{};
1,502✔
283
    ops.reserve(tokens.size());
1,502✔
284

285
    // Create an op list from the split tokens.
286
    for (const auto& token: tokens)
12,200✔
287
    {
288
        ops.emplace_back(token);
10,702✔
289
        prefail |= ops.back().is_invalid();
10,702✔
290

291
        // This is a deserialization failure, not just an invalid code.
292
        if (!ops.back().is_valid())
10,702✔
293
            return {};
4✔
294
    }
295

296
    return { std::move(ops), prefail };
1,498✔
297
}
1,502✔
298

299
// Serialization.
300
// ----------------------------------------------------------------------------
301

302
data_chunk script::to_data(bool prefix) const NOEXCEPT
165✔
303
{
304
    data_chunk data(serialized_size(prefix));
165✔
305
    stream::out::fast ostream(data);
165✔
306
    write::bytes::fast out(ostream);
165✔
307
    to_data(out, prefix);
165✔
308
    return data;
165✔
309
}
165✔
310

311
void script::to_data(std::ostream& stream, bool prefix) const NOEXCEPT
×
312
{
313
    write::bytes::ostream out(stream);
×
314
    to_data(out, prefix);
×
315
}
×
316

317
// see also: subscript.to_data().
318
void script::to_data(writer& sink, bool prefix) const NOEXCEPT
3,327✔
319
{
320
    if (prefix)
3,327✔
321
        sink.write_variable(serialized_size(false));
3,145✔
322

323
    // Data serialization is affected by offset metadata.
324
    for (iterator op{ offset }; op != ops().end(); ++op)
1,494,744✔
325
        op->to_data(sink);
1,491,417✔
326
}
3,327✔
327

328
std::string script::to_string(uint32_t active_flags) const NOEXCEPT
28✔
329
{
330
    auto first = true;
28✔
331
    std::ostringstream text;
28✔
332

333
    // Throwing stream aborts.
334
    for (const auto& op: ops())
82✔
335
    {
336
        text << (first ? "" : " ") << op.to_string(active_flags);
80✔
337
        first = false;
54✔
338
    }
339

340
    // An invalid operation has a specialized serialization.
341
    return text.str();
56✔
342
}
28✔
343

344

345
// Properties.
346
// ----------------------------------------------------------------------------
347

348
bool script::is_valid() const NOEXCEPT
1,513✔
349
{
350
    // Any byte vector is a valid script.
351
    // This is false only if the byte count did not match the size prefix.
352
    return valid_;
1,513✔
353
}
354

355
bool script::is_prefail() const NOEXCEPT
3,095✔
356
{
357
    // The script contains an invalid opcode and will thus fail evaluation.
358
    return prefail_;
3,095✔
359
}
360

361
const operations& script::ops() const NOEXCEPT
31,342✔
362
{
363
    return ops_;
31,342✔
364
}
365

366
bool script::is_roller() const NOEXCEPT
8✔
367
{
368
    static const auto roll = operation{ opcode::roll };
8✔
369

370
    // Naive implementation, any op_roll in script, late-counted.
371
    // TODO: precompute on script parse, tune using performance profiling.
372
    return contains(ops_, roll);
8✔
373
};
374

375
// Consensus (witness::extract_script) and Electrum server payments key.
376
hash_digest script::hash() const NOEXCEPT
18✔
377
{
378
    hash_digest sha256{};
18✔
379
    hash::sha256::copy sink(sha256);
18✔
380
    to_data(sink, false);
18✔
381
    sink.flush();
18✔
382
    return sha256;
18✔
383
}
18✔
384

385
// static/private
386
size_t script::serialized_size(const operations& ops) NOEXCEPT
1,724✔
387
{
388
    return std::accumulate(ops.begin(), ops.end(), zero, op_size);
1,724✔
389
}
390

391
size_t script::serialized_size(bool prefix) const NOEXCEPT
8,789✔
392
{
393
    // Recompute it serialization has been affected by offset metadata.
394
    const auto size = (offset == ops_.begin()) ? size_ :
8,789✔
395
        std::accumulate(offset, ops_.end(), zero, op_size);
8✔
396

397
    return prefix ? ceilinged_add(size, variable_size(size)) : size;
8,789✔
398
}
399

400
// Utilities.
401
// ----------------------------------------------------------------------------
402

403
const data_chunk& script::witness_program() const NOEXCEPT
24✔
404
{
405
    static const data_chunk empty{};
25✔
406

407
    BC_PUSH_WARNING(NO_ARRAY_INDEXING)
408
    return is_witness_program_pattern(ops()) ? ops()[1].data() : empty;
24✔
409
    BC_POP_WARNING()
410
}
411

412
script_version script::version() const NOEXCEPT
48✔
413
{
414
    if (!is_witness_program_pattern(ops()))
48✔
415
        return script_version::unversioned;
416

417
    switch (ops_.front().code())
48✔
418
    {
419
        case opcode::push_size_0:
420
            return script_version::zero;
421
        default:
×
422
            return script_version::reserved;
×
423
    }
424
}
425

426
// Caller should test for is_sign_script_hash_pattern when sign_key_hash result
427
// as it is possible for an input script to match both patterns.
428
script_pattern script::pattern() const NOEXCEPT
11✔
429
{
430
    const auto input = output_pattern();
11✔
431
    return input == script_pattern::non_standard ? input_pattern() : input;
11✔
432
}
433

434
// Output patterns are mutually and input unambiguous.
435
// The bip141 coinbase pattern is not tested here, must test independently.
436
script_pattern script::output_pattern() const NOEXCEPT
22✔
437
{
438
    if (is_pay_key_hash_pattern(ops()))
22✔
439
        return script_pattern::pay_key_hash;
440

441
    if (is_pay_script_hash_pattern(ops()))
22✔
442
        return script_pattern::pay_script_hash;
443

444
    if (is_pay_null_data_pattern(ops()))
22✔
445
        return script_pattern::pay_null_data;
446

447
    if (is_pay_public_key_pattern(ops()))
18✔
448
        return script_pattern::pay_public_key;
449

450
    // Limited to 16 signatures though op_check_multisig allows 20.
451
    if (is_pay_multisig_pattern(ops()))
18✔
452
        return script_pattern::pay_multisig;
8✔
453

454
    return script_pattern::non_standard;
455
}
456

457
// A sign_key_hash result always implies sign_script_hash as well.
458
// The bip34 coinbase pattern is not tested here, must test independently.
459
script_pattern script::input_pattern() const NOEXCEPT
16✔
460
{
461
    if (is_sign_key_hash_pattern(ops()))
16✔
462
        return script_pattern::sign_key_hash;
463

464
    // This must follow is_sign_key_hash_pattern for ambiguity comment to hold.
465
    if (is_sign_script_hash_pattern(ops()))
16✔
466
        return script_pattern::sign_script_hash;
467

468
    if (is_sign_public_key_pattern(ops()))
16✔
469
        return script_pattern::sign_public_key;
470

471
    if (is_sign_multisig_pattern(ops()))
16✔
472
        return script_pattern::sign_multisig;
×
473

474
    return script_pattern::non_standard;
475
}
476

477
bool script::is_pay_to_witness(uint32_t active_flags) const NOEXCEPT
961✔
478
{
479
    // This is an optimization over using script::pattern.
480
    return is_enabled(active_flags, flags::bip141_rule) &&
1,419✔
481
        is_witness_program_pattern(ops());
458✔
482
}
483

484
bool script::is_pay_to_script_hash(uint32_t active_flags) const NOEXCEPT
969✔
485
{
486
    // This is an optimization over using script::pattern.
487
    return is_enabled(active_flags, flags::bip16_rule) &&
1,424✔
488
        is_pay_script_hash_pattern(ops());
455✔
489
}
490

491
// Count 1..16 multisig accurately for embedded (bip16) and witness (bip141).
492
constexpr size_t multisig_sigops(bool accurate, opcode code) NOEXCEPT
×
493
{
494
    return accurate && operation::is_positive(code) ?
×
495
        operation::opcode_to_positive(code) : multisig_default_sigops;
×
496
}
497

498
constexpr bool is_single_sigop(opcode code) NOEXCEPT
24✔
499
{
500
    return code == opcode::checksig || code == opcode::checksigverify;
24✔
501
}
502

503
constexpr bool is_multiple_sigop(opcode code) NOEXCEPT
×
504
{
505
    return code == opcode::checkmultisig || code == opcode::checkmultisigverify;
×
506
}
507

508
// TODO: compute in or at script evaluation and add coinbase input scripts.
509
// TODO: this precludes second deserialization of script for sigop counting.
510
size_t script::signature_operations(bool accurate) const NOEXCEPT
12✔
511
{
512
    auto total = zero;
12✔
513
    auto preceding = opcode::push_negative_1;
12✔
514

515
    for (const auto& op: ops())
36✔
516
    {
517
        const auto code = op.code();
24✔
518

519
        if (is_single_sigop(code))
24✔
520
            total = ceilinged_add(total, one);
24✔
521
        else if (is_multiple_sigop(code))
×
522
            total = ceilinged_add(total, multisig_sigops(accurate, preceding));
×
523

524
        preceding = code;
24✔
525
    }
526

527
    return total;
12✔
528
}
529

530
bool script::is_oversized() const NOEXCEPT
3,035✔
531
{
532
    return serialized_size(false) > max_script_size;
3,035✔
533
}
534

535
// An unspendable script is any that can provably not be spent under any
536
// circumstance. This allows for exclusion of the output as unspendable.
537
// The criteria below are not comprehensive but are fast to evaluate.
538
bool script::is_unspendable() const NOEXCEPT
3✔
539
{
540
    if (ops_.empty())
3✔
541
        return false;
542

543
    const auto& code = ops_.front().code();
3✔
544

545
    // There is no condition prior to the first opcode in a script, so
546
    // is_reserved must be checked. is_invalid short-circuits evaluation for
547
    // scripts that fail to parse, but would otherwise be caught in evaluation.
548
    return operation::is_reserved(code) || operation::is_invalid(code);
3✔
549
}
550

551
BC_POP_WARNING()
552

553
// JSON value convertors.
554
// ----------------------------------------------------------------------------
555

556
namespace json = boost::json;
557

558
// boost/json will soon have NOEXCEPT: github.com/boostorg/json/pull/636
559
BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
560

561
script tag_invoke(json::value_to_tag<script>,
11✔
562
    const json::value& value) NOEXCEPT
563
{
564
    return script{ std::string(value.get_string().c_str()) };
22✔
565
}
566

567
void tag_invoke(json::value_from_tag, json::value& value,
22✔
568
    const script& script) NOEXCEPT
569
{
570
    value = script.to_string(flags::all_rules);
22✔
571
}
22✔
572

573
BC_POP_WARNING()
574

575
script::cptr tag_invoke(json::value_to_tag<script::cptr>,
×
576
    const json::value& value) NOEXCEPT
577
{
578
    return to_shared(tag_invoke(json::value_to_tag<script>{}, value));
×
579
}
580

581
// Shared pointer overload is required for navigation.
582
BC_PUSH_WARNING(SMART_PTR_NOT_NEEDED)
583
BC_PUSH_WARNING(NO_VALUE_OR_CONST_REF_SHARED_PTR)
584

585
void tag_invoke(json::value_from_tag tag, json::value& value,
×
586
    const script::cptr& script) NOEXCEPT
587
{
588
    tag_invoke(tag, value, *script);
×
589
}
×
590

591
BC_POP_WARNING()
592
BC_POP_WARNING()
593

594
} // namespace chain
595
} // namespace system
596
} // 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