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

libbitcoin / libbitcoin-system / 12739695152

13 Jan 2025 02:44AM UTC coverage: 82.969% (-0.1%) from 83.098%
12739695152

push

github

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

Optimize populate by avoiding hash copies, normalize ref optimizations.

14 of 40 new or added lines in 6 files covered. (35.0%)

2 existing lines in 1 file now uncovered.

10065 of 12131 relevant lines covered (82.97%)

4721517.14 hits per line

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

72.04
/src/chain/input.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/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
// Null witness helpers.
46
// ----------------------------------------------------------------------------
47

48
// static/private
49
const witness& input::no_witness() NOEXCEPT
×
50
{
51
    static const chain::witness empty_witness{};
×
52
    return empty_witness;
×
53
}
54

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

67
const chain::witness& input::get_witness() const NOEXCEPT
1,965✔
68
{
69
    return witness_ ? *witness_ : no_witness();
1,965✔
70
}
71

72
const chain::witness::cptr& input::get_witness_cptr() const NOEXCEPT
×
73
{
74
    return witness_ ? witness_ : no_witness_cptr();
×
75
}
76

77
// Constructors.
78
// ----------------------------------------------------------------------------
79

80
// Default point is null_hash and point::null_index. 
81
// Default metadata is spent, invalid, max_size_t value. 
82
input::input() NOEXCEPT
22✔
83
  : input(
84
      to_shared<chain::point>(),
22✔
85
      to_shared<chain::script>(),
22✔
86
      to_shared<chain::witness>(),
22✔
87
      0, false)
88✔
88
{
89
}
22✔
90

91
input::input(chain::point&& point, chain::script&& script,
160✔
92
    uint32_t sequence) NOEXCEPT
160✔
93
  : input(
94
      to_shared(std::move(point)),
160✔
95
      to_shared(std::move(script)),
160✔
96
      to_shared<chain::witness>(),
160✔
97
      sequence, true)
320✔
98
{
99
}
160✔
100

101
input::input(const chain::point& point, const chain::script& script,
736✔
102
    uint32_t sequence) NOEXCEPT
736✔
103
  : input(
104
      to_shared(point),
736✔
105
      to_shared(script),
736✔
106
      to_shared<chain::witness>(),
736✔
107
      sequence, true)
1,472✔
108
{
109
}
736✔
110

111
input::input(const chain::point::cptr& point,
×
112
    const chain::script::cptr& script, uint32_t sequence) NOEXCEPT
×
113
  : input(
114
      point ? point : to_shared<chain::point>(),
×
115
      script ? script : to_shared<chain::script>(),
×
116
      to_shared<chain::witness>(),
×
117
      sequence, true)
×
118
{
119
}
×
120

121
input::input(chain::point&& point, chain::script&& script,
14✔
122
    chain::witness&& witness, uint32_t sequence) NOEXCEPT
14✔
123
  : input(
124
      to_shared(std::move(point)),
14✔
125
      to_shared(std::move(script)),
14✔
126
      to_shared(std::move(witness)),
14✔
127
      sequence, true)
14✔
128
{
129
}
14✔
130

131
input::input(const chain::point& point, const chain::script& script,
1✔
132
    const chain::witness& witness, uint32_t sequence) NOEXCEPT
1✔
133
  : input(
134
      to_shared(point),
1✔
135
      to_shared(script),
1✔
136
      to_shared(witness),
1✔
137
      sequence, true)
1✔
138
{
139
}
1✔
140

141
input::input(const chain::point::cptr& point, const chain::script::cptr& script,
×
142
    const chain::witness::cptr& witness, uint32_t sequence) NOEXCEPT
×
143
  : input(point, script, witness, sequence, true)
×
144
{
145
}
×
146

147
input::input(const data_slice& data) NOEXCEPT
5✔
148
  : input(stream::in::copy(data))
5✔
149
{
150
}
5✔
151

152
////input::input(stream::in::fast&& stream) NOEXCEPT
153
////  : input(read::bytes::fast(stream))
154
////{
155
////}
156

157
input::input(stream::in::fast& stream) NOEXCEPT
1✔
158
  : input(read::bytes::fast(stream))
1✔
159
{
160
}
1✔
161

162
input::input(std::istream&& stream) NOEXCEPT
5✔
163
  : input(read::bytes::istream(stream))
5✔
164
{
165
}
5✔
166

167
input::input(std::istream& stream) NOEXCEPT
3✔
168
  : input(read::bytes::istream(stream))
3✔
169
{
170
}
3✔
171

172
input::input(reader&& source) NOEXCEPT
9✔
173
  : input(source)
9✔
174
{
175
}
×
176

177
// Witness is deserialized and assigned by transaction.
178
input::input(reader& source) NOEXCEPT
256✔
179
  : point_(CREATE(chain::point, source.get_allocator(), source)),
256✔
180
    script_(CREATE(chain::script, source.get_allocator(), source, true)),
256✔
181
    witness_(CREATE(chain::witness, source.get_allocator())),
256✔
182
    sequence_(source.read_4_bytes_little_endian()),
256✔
183
    valid_(source),
256✔
184
    size_(serialized_size(*script_))
512✔
185
{
186
}
256✔
187

188
// protected
189
input::input(const chain::point::cptr& point, const chain::script::cptr& script,
933✔
190
    const chain::witness::cptr& witness, uint32_t sequence, bool valid) NOEXCEPT
933✔
191
  : point_(point),
192
    script_(script),
193
    witness_(witness),
194
    sequence_(sequence),
933✔
195
    valid_(valid),
933✔
196
    size_(serialized_size(*script, *witness))
1,866✔
197
{
198
}
933✔
199

200
// Operators.
201
// ----------------------------------------------------------------------------
202

203
bool input::operator==(const input& other) const NOEXCEPT
43✔
204
{
205
    return (sequence_ == other.sequence_)
43✔
206
        && (point_ == other.point_ || *point_ == *other.point_)
41✔
207
        && (script_ == other.script_ || *script_ == *other.script_)
41✔
208
        && (witness_ == other.witness_ || get_witness() == other.get_witness());
84✔
209
}
210

211
bool input::operator!=(const input& other) const NOEXCEPT
2✔
212
{
213
    return !(*this == other);
2✔
214
}
215

216
// Constant reference optimizers.
217

NEW
218
bool operator<(const cref_point& left, const cref_point& right) NOEXCEPT
×
219
{
220
    // Arbitrary compare, for uniqueness sorting.
NEW
221
    return left.index == right.index ?
×
NEW
222
        left.hash.get() < right.hash.get() :
×
NEW
223
        left.index < right.index;
×
224
}
225

NEW
226
bool operator==(const cref_point& left, const cref_point& right) NOEXCEPT
×
227
{
NEW
228
    return (left.hash.get() == right.hash.get())
×
NEW
229
        && (left.index == right.index);
×
230
}
231

NEW
232
bool operator!=(const cref_point& left, const cref_point& right) NOEXCEPT
×
233
{
NEW
234
    return !(left == right);
×
235
}
236

237
// Deserialization.
238
// ----------------------------------------------------------------------------
239

240
// Serialization.
241
// ----------------------------------------------------------------------------
242

243
data_chunk input::to_data() const NOEXCEPT
1✔
244
{
245
    data_chunk data(serialized_size(false));
1✔
246
    stream::out::copy ostream(data);
1✔
247
    to_data(ostream);
1✔
248
    return data;
2✔
249
}
1✔
250

251
void input::to_data(std::ostream& stream) const NOEXCEPT
2✔
252
{
253
    write::bytes::ostream out(stream);
2✔
254
    to_data(out);
2✔
255
}
2✔
256

257
// Witness is serialized by transaction.
258
void input::to_data(writer& sink) const NOEXCEPT
1,390✔
259
{
260
    point_->to_data(sink);
1,390✔
261
    script_->to_data(sink, true);
1,390✔
262
    sink.write_4_bytes_little_endian(sequence_);
1,390✔
263
}
1,390✔
264

265
// static/private
266
input::sizes input::serialized_size(const chain::script& script) NOEXCEPT
256✔
267
{
268
    constexpr auto const_size = ceilinged_add(point::serialized_size(),
256✔
269
        sizeof(sequence_));
270

271
    const auto nominal_size = ceilinged_add(const_size,
256✔
272
        script.serialized_size(true));
273

274
    return { nominal_size, zero };
256✔
275
}
276

277
// static/private
278
input::sizes input::serialized_size(const chain::script& script,
933✔
279
    const chain::witness& witness) NOEXCEPT
280
{
281
    constexpr auto const_size = ceilinged_add(point::serialized_size(),
933✔
282
        sizeof(sequence_));
283

284
    const auto nominal_size = ceilinged_add(const_size,
933✔
285
        script.serialized_size(true));
286

287
    const auto witnessed_size = ceilinged_add(nominal_size,
933✔
288
        witness.serialized_size(true));
289

290
    return { nominal_size, witnessed_size };
933✔
291
}
292

293
// input.serialized_size(witness) provides sizing for witness, however
294
// witnesses are serialized by the transaction. This is an ugly hack as a
295
// consequence of bip144 not serializing witnesses as part of inputs, which
296
// is logically the proper association.
297
size_t input::serialized_size(bool witness) const NOEXCEPT
2✔
298
{
299
    return witness ? size_.witnessed : size_.nominal;
2✔
300
}
301

302
// Friend accessors (private).
303
// ----------------------------------------------------------------------------
304

305
size_t input::nominal_size() const NOEXCEPT
1,159✔
306
{
307
    return size_.nominal;
1,159✔
308
}
309

310
size_t input::witnessed_size() const NOEXCEPT
32✔
311
{
312
    return size_.witnessed;
32✔
313
}
314

315
////void input::set_witness(reader& source) NOEXCEPT
316
////{
317
////    witness_ = to_shared<chain::witness>(source, true);
318
////    size_.witnessed = ceilinged_add(size_.nominal,
319
////        witness_->serialized_size(true));
320
////}
321

322
void input::set_witness(reader& source) NOEXCEPT
20✔
323
{
324
    auto& allocator = source.get_allocator();
20✔
325
    witness_.reset(CREATE(chain::witness, allocator, source, true));
20✔
326
    size_.witnessed = ceilinged_add(size_.nominal,
20✔
327
        witness_->serialized_size(true));
328
}
20✔
329

330
// Properties.
331
// ----------------------------------------------------------------------------
332

333
bool input::is_valid() const NOEXCEPT
16✔
334
{
335
    return valid_;
16✔
336
}
337

338
const point& input::point() const NOEXCEPT
169✔
339
{
340
    return *point_;
10✔
341
}
342

343
const chain::script& input::script() const NOEXCEPT
75✔
344
{
345
    return *script_;
10✔
346
}
347

348
const chain::witness& input::witness() const NOEXCEPT
1,899✔
349
{
350
    return get_witness();
1,899✔
351
}
352

353
const point::cptr& input::point_ptr() const NOEXCEPT
×
354
{
355
    return point_;
×
356
}
357

358
const chain::script::cptr& input::script_ptr() const NOEXCEPT
1,559✔
359
{
360
    return script_;
1,559✔
361
}
362

363
const chain::witness::cptr& input::witness_ptr() const NOEXCEPT
×
364
{
365
    return get_witness_cptr();
×
366
}
367

368
uint32_t input::sequence() const NOEXCEPT
73✔
369
{
370
    return sequence_;
10✔
371
}
372

373
// Methods.
374
// ----------------------------------------------------------------------------
375

376
bool input::is_final() const NOEXCEPT
22✔
377
{
378
    return sequence_ == max_input_sequence;
22✔
379
}
380

381
bool input::is_roller() const NOEXCEPT
4✔
382
{
383
    return script_->is_roller() || (prevout && prevout->script().is_roller());
4✔
384
}
385

386
// static
387
bool input::is_locked(uint32_t sequence, size_t height,
10✔
388
    uint32_t median_time_past, size_t prevout_height,
389
    uint32_t prevout_median_time_past) NOEXCEPT
390
{
391
    // BIP68: if bit 31 is set then no consensus meaning is applied.
392
    if (get_right(sequence, relative_locktime_disabled_bit))
10✔
393
        return false;
394

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

398
    // BIP68: bit 22 determines if relative lock is time or block based.
399
    if (get_right(sequence, relative_locktime_time_locked_bit))
8✔
400
    {
401
        // BIP68: change sequence to seconds by shift up by 9 bits (x 512).
402
        auto time = shift_left(blocks, relative_locktime_seconds_shift_left);
3✔
403
        auto age = floored_subtract(median_time_past, prevout_median_time_past);
3✔
404
        return age < time;
3✔
405
    }
406

407
    const auto age = floored_subtract(height, prevout_height);
5✔
408
    return age < blocks;
5✔
409
}
410

411
bool input::is_locked(size_t height, uint32_t median_time_past) const NOEXCEPT
10✔
412
{
413
    // Prevout must be found and height/median_time_past metadata populated.
414
    ////BC_ASSERT(!is_zero(metadata.height));
415
    return is_locked(sequence_, height, median_time_past, metadata.height,
10✔
416
        metadata.median_time_past);
10✔
417
}
418

419
bool input::is_internally_locked() const NOEXCEPT
×
420
{
421
    // Internal spends have zero relative height/mtp.
422
    return is_locked(sequence_, {}, {}, {}, {});
×
423
}
424

425
bool input::reserved_hash(hash_digest& out) const NOEXCEPT
×
426
{
427
    if (!witness::is_reserved_pattern(get_witness().stack()))
×
428
        return false;
429

430
    std::copy_n(get_witness().stack().front()->begin(), hash_size, out.begin());
×
431
    return true;
×
432
}
433

434
// private
435
// prevout_script is only used to determine is_pay_script_hash_pattern.
436
bool input::extract_sigop_script(chain::script& out,
×
437
    const chain::script& prevout_script) const NOEXCEPT
438
{
439
    // There are no embedded sigops when the prevout script is not p2sh.
440
    if (!script::is_pay_script_hash_pattern(prevout_script.ops()))
×
441
        return false;
442

443
    // There are no embedded sigops when the input script is not push only.
444
    const auto& ops = script_->ops();
×
445
    if (ops.empty() || !script::is_relaxed_push_pattern(ops))
×
446
        return false;
×
447

448
    // Parse the embedded script from the last input script item (data).
449
    // This cannot fail because there is no prefix to invalidate the length.
450
    out = { ops.back().data(), false };
×
451
    return true;
×
452
}
453

454
// TODO: Prior to block 79400 sigops were limited only by policy.
455
// TODO: Create legacy sigops fork/flag and pass here, return 0 if false.
456
// TODO: this was an unbipped flag day soft fork, prior to BIP16/141.
457
// TODO: if (nHeight > 79400 && GetSigOpCount() > MAX_BLOCK_SIGOPS).
458
size_t input::signature_operations(bool bip16, bool bip141) const NOEXCEPT
7✔
459
{
460
    // Penalize quadratic signature operations (bip141).
461
    const auto factor = bip141 ? heavy_sigops_factor : one;
7✔
462
    const auto sigops = script_->signature_operations(false) * factor;
7✔
463

464
    // ************************************************************************
465
    // CONSENSUS: coinbase input cannot execute, but sigops are counted anyway.
466
    // ************************************************************************
467
    if (!prevout)
7✔
468
        return sigops;
469

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

473
    chain::script witness;
×
474
    if (bip141 && get_witness().extract_sigop_script(witness, prevout->script()))
×
475
    {
476
        // Add sigops in the witness script (bip141).
477
        return ceilinged_add(sigops, witness.signature_operations(true));
×
478
    }
479

480
    chain::script embedded;
×
481
    if (bip16 && extract_sigop_script(embedded, prevout->script()))
×
482
    {
483
        if (bip141 && get_witness().extract_sigop_script(witness, embedded))
×
484
        {
485
            // Add sigops in the embedded witness script (bip141).
486
            return ceilinged_add(sigops, witness.signature_operations(true));
×
487
        }
488
        else
489
        {
490
            // Add heavy sigops in the embedded script (bip16).
491
            return ceilinged_add(sigops, embedded.signature_operations(true) *
×
492
                factor);
493
        }
494
    }
495

496
    return sigops;
497
}
×
498

499
BC_POP_WARNING()
500

501
// JSON value convertors.
502
// ----------------------------------------------------------------------------
503

504
namespace json = boost::json;
505

506
// boost/json will soon have NOEXCEPT: github.com/boostorg/json/pull/636
507
BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
508

509
input tag_invoke(json::value_to_tag<input>, const json::value& value) NOEXCEPT
5✔
510
{
511
    return
5✔
512
    {
513
        json::value_to<chain::point>(value.at("point")),
5✔
514
        json::value_to<chain::script>(value.at("script")),
5✔
515
        json::value_to<chain::witness>(value.at("witness")),
10✔
516
        value.at("sequence").to_number<uint32_t>()
10✔
517
    };
5✔
518
}
519

520
void tag_invoke(json::value_from_tag, json::value& value,
10✔
521
    const input& input) NOEXCEPT
522
{
523
    value =
20✔
524
    {
525
        { "point", input.point() },
526
        { "script", input.script() },
527
        { "witness", input.witness() },
528
        { "sequence", input.sequence() }
529
    };
10✔
530
}
10✔
531

532
BC_POP_WARNING()
533

534
input::cptr tag_invoke(json::value_to_tag<input::cptr>,
×
535
    const json::value& value) NOEXCEPT
536
{
537
    return to_shared(tag_invoke(json::value_to_tag<input>{}, value));
×
538
}
539

540
// Shared pointer overload is required for navigation.
541
BC_PUSH_WARNING(SMART_PTR_NOT_NEEDED)
542
BC_PUSH_WARNING(NO_VALUE_OR_CONST_REF_SHARED_PTR)
543

544
void tag_invoke(json::value_from_tag tag, json::value& value,
8✔
545
    const input::cptr& input) NOEXCEPT
546
{
547
    tag_invoke(tag, value, *input);
8✔
548
}
8✔
549

550
BC_POP_WARNING()
551
BC_POP_WARNING()
552

553
} // namespace chain
554
} // namespace system
555
} // 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