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

libbitcoin / libbitcoin-system / 9279386570

29 May 2024 02:35AM UTC coverage: 82.795% (-0.03%) from 82.826%
9279386570

push

github

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

Cache witness size, fix std::vector.capacity assumptions.

38 of 49 new or added lines in 6 files covered. (77.55%)

5 existing lines in 2 files now uncovered.

9783 of 11816 relevant lines covered (82.79%)

4826496.0 hits per line

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

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

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

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

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

50
// static (should be inline or constexpr).
51
// TODO: Avoiding circular include on machine.
52
bool script::is_coinbase_pattern(const operations& ops, size_t height) NOEXCEPT
×
53
{
54
    // TODO: number::chunk::from_int constexpr?
55
    return !ops.empty()
×
56
        && ops[0].is_nominal_push()
×
57
        && ops[0].data() == number::chunk::from_integer(to_unsigned(height));
×
58
}
59

60
// Constructors.
61
// ----------------------------------------------------------------------------
62

63
script::script() NOEXCEPT
116✔
64
  : script(operations{}, false, false, zero)
116✔
65
{
66
}
116✔
67

68
script::~script() NOEXCEPT
4,468✔
69
{
70
}
4,468✔
71

72
script::script(script&& other) NOEXCEPT
190✔
73
  : script(std::move(other.ops_), other.valid_, other.prefail_, other.size_)
190✔
74
{
75
}
190✔
76

77
script::script(const script& other) NOEXCEPT
1,470✔
78
  : script(other.ops_, other.valid_, other.prefail_, other.size_)
1,470✔
79
{
80
}
1,470✔
81

82
// Prefail is false.
83
script::script(operations&& ops) NOEXCEPT
59✔
84
  : script(std::move(ops), true, false)
59✔
85
{
86
    // ops moved so cannot pass serialized_size(ops), order not guaranteed.
87
}
59✔
88

89
// Prefail is false.
90
script::script(const operations& ops) NOEXCEPT
1✔
91
  : script(ops, true, false, serialized_size(ops))
1✔
92
{
93
}
1✔
94

95
script::script(operations&& ops, bool prefail) NOEXCEPT
1,494✔
96
  : script(std::move(ops), true, prefail)
1,494✔
97
{
98
    // ops moved so cannot pass serialized_size(ops), order not guaranteed.
99
}
1,494✔
100

101
script::script(const operations& ops, bool prefail) NOEXCEPT
×
102
  : script(ops, true, prefail, serialized_size(ops))
×
103
{
104
}
×
105

106
script::script(const data_slice& data, bool prefix) NOEXCEPT
133✔
107
    BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
108
  : script(stream::in::copy(data), prefix)
133✔
109
    BC_POP_WARNING()
110
{
111
}
133✔
112

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

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

123
script::script(std::istream&& stream, bool prefix) NOEXCEPT
133✔
124
  : script(read::bytes::istream(stream), prefix)
133✔
125
{
126
}
133✔
127

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

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

138
script::script(reader& source, bool prefix) NOEXCEPT
480✔
139
  : script(from_data(source, prefix))
480✔
140
{
141
}
480✔
142

143
script::script(const std::string& mnemonic) NOEXCEPT
1,498✔
144
  : script(from_string(mnemonic))
1,498✔
145
{
146
}
1,498✔
147

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

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

168
// protected
169
script::script(const operations& ops, bool valid, bool prefail,
2,392✔
170
    size_t size) NOEXCEPT
1,777✔
171
  : ops_(ops),
2,392✔
172
    valid_(valid),
2,392✔
173
    prefail_(prefail),
2,392✔
174
    size_(size),
731✔
175
    offset(ops_.begin())
2,392✔
176
{
177
}
×
178

179
// Operators.
180
// ----------------------------------------------------------------------------
181

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

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

202
bool script::operator==(const script& other) const NOEXCEPT
63✔
203
{
204
    return size_ == other.size_
63✔
205
        && ops_ == other.ops_;
63✔
206
}
207

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

213
// Deserialization.
214
// ----------------------------------------------------------------------------
215

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

223
    const auto start = source.get_read_position();
615✔
224
    auto count = zero;
615✔
225

226
    // TODO: this is expensive (0.83%).
227
    while (operation::count_op(source))
83,732✔
228
        ++count;
82,502✔
229

230
    source.set_position(start);
615✔
231
    return count;
615✔
232
}
233

234
// static/private
235
script script::from_data(reader& source, bool prefix) NOEXCEPT
615✔
236
{
237
    auto expected = zero;
615✔
238
    auto prefail = false;
615✔
239

240
    if (prefix)
615✔
241
    {
242
        expected = source.read_size();
486✔
243
        source.set_limit(expected);
486✔
244
    }
245

246
    operations ops;
615✔
247
    ops.reserve(op_count(source));
615✔
248
    const auto start = source.get_read_position();
615✔
249

250
    while (!source.is_exhausted())
83,732✔
251
    {
252
        ops.emplace_back(source);
82,502✔
253
        prefail |= ops.back().is_invalid();
82,502✔
254
    }
255

256
    const auto size = source.get_read_position() - start;
615✔
257

258
    if (prefix)
615✔
259
    {
260
        source.set_limit();
486✔
261
        if (size != expected)
486✔
262
            source.invalidate();
2✔
263
    }
264

265
    return { std::move(ops), source, prefail, size };
615✔
266
}
615✔
267

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

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

280
    operations ops;
1,498✔
281
    ops.reserve(tokens.size());
1,498✔
282

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

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

294
    return { std::move(ops), prefail };
1,494✔
295
}
1,498✔
296

297
// Serialization.
298
// ----------------------------------------------------------------------------
299

300
data_chunk script::to_data(bool prefix) const NOEXCEPT
165✔
301
{
302
    data_chunk data(serialized_size(prefix));
165✔
303

304
    BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
305
    stream::out::copy ostream(data);
165✔
306
    BC_POP_WARNING()
307

308
    to_data(ostream, prefix);
165✔
309
    return data;
330✔
310
}
165✔
311

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

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

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

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

334
    // Throwing stream aborts.
335
    BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
336

337
    for (const auto& op: ops())
82✔
338
    {
339
        text << (first ? "" : " ") << op.to_string(active_flags);
80✔
340
        first = false;
54✔
341
    }
342

343
    // An invalid operation has a specialized serialization.
344
    return text.str();
28✔
345

346
    BC_POP_WARNING()
347
}
28✔
348

349

350
// Properties.
351
// ----------------------------------------------------------------------------
352

353
bool script::is_valid() const NOEXCEPT
1,509✔
354
{
355
    // Any byte vector is a valid script.
356
    // This is false only if the byte count did not match the size prefix.
357
    return valid_;
1,509✔
358
}
359

360
bool script::is_prefail() const NOEXCEPT
3,087✔
361
{
362
    // The script contains an invalid opcode and will thus fail evaluation.
363
    return prefail_;
3,087✔
364
}
365

366
const operations& script::ops() const NOEXCEPT
31,312✔
367
{
368
    return ops_;
31,312✔
369
}
370

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

381
// static/private
382
size_t script::serialized_size(const operations& ops) NOEXCEPT
1,554✔
383
{
384
    return std::accumulate(ops.begin(), ops.end(), zero, op_size);
1,554✔
385
}
386

387
size_t script::serialized_size(bool prefix) const NOEXCEPT
6,492✔
388
{
389
    // Recompute it serialization has been affected by offset metadata.
390
    auto size = (offset == ops_.begin()) ? size_ :
6,492✔
391
        std::accumulate(offset, ops_.end(), zero, op_size);
8✔
392

393
    if (prefix)
6,492✔
394
        size += variable_size(size);
168✔
395

396
    return size;
6,492✔
397
}
398

399
// Utilities.
400
// ----------------------------------------------------------------------------
401

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

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

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

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

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

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

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

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

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

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

453
    return script_pattern::non_standard;
454
}
455

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

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

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

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

473
    return script_pattern::non_standard;
474
}
475

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

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

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

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

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

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

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

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

523
        preceding = code;
24✔
524
    }
525

526
    return total;
12✔
527
}
528

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

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

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

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

550
// JSON value convertors.
551
// ----------------------------------------------------------------------------
552

553
namespace json = boost::json;
554

555
// boost/json will soon have NOEXCEPT: github.com/boostorg/json/pull/636
556
BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
557

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

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

570
BC_POP_WARNING()
571

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

578
// Shared pointer overload is required for navigation.
579
BC_PUSH_WARNING(SMART_PTR_NOT_NEEDED)
580
BC_PUSH_WARNING(NO_VALUE_OR_CONST_REF_SHARED_PTR)
581

582
void tag_invoke(json::value_from_tag tag, json::value& value,
×
583
    const script::cptr& script) NOEXCEPT
584
{
585
    tag_invoke(tag, value, *script);
×
586
}
×
587

588
BC_POP_WARNING()
589
BC_POP_WARNING()
590

591
} // namespace chain
592
} // namespace system
593
} // 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