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

libbitcoin / libbitcoin-system / 4637370737

pending completion
4637370737

push

github

GitHub
Merge pull request #1353 from evoskuil/master

102 of 102 new or added lines in 5 files covered. (100.0%)

9438 of 11391 relevant lines covered (82.85%)

6703526.24 hits per line

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

78.11
/src/chain/input.cpp
1
/**
2
 * Copyright (c) 2011-2022 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
// Product overflows guarded by script size limit.
39
static_assert(max_script_size < 
40
    max_size_t / multisig_default_sigops / heavy_sigops_factor,
41
    "input sigop overflow guard");
42

43
// Constructors.
44
// ----------------------------------------------------------------------------
45

46
// Default point is null_hash and point::null_index. 
47
// Default metadata is spent, invalid, max_size_t value. 
48
input::input() NOEXCEPT
22✔
49
  : input(
50
      to_shared<chain::point>(),
22✔
51
      to_shared<chain::script>(),
22✔
52
      to_shared<chain::witness>(),
22✔
53
      0, false)
88✔
54
{
55
}
22✔
56

57
input::input(chain::point&& point, chain::script&& script,
66✔
58
    uint32_t sequence) NOEXCEPT
66✔
59
  : input(
60
      to_shared(std::move(point)),
66✔
61
      to_shared(std::move(script)),
66✔
62
      to_shared<chain::witness>(),
66✔
63
      sequence, true)
132✔
64
{
65
}
66✔
66

67
input::input(const chain::point& point, const chain::script& script,
734✔
68
    uint32_t sequence) NOEXCEPT
734✔
69
  : input(
70
      to_shared(point),
734✔
71
      to_shared(script),
734✔
72
      to_shared<chain::witness>(),
734✔
73
      sequence, true)
1,468✔
74
{
75
}
734✔
76

77
input::input(const chain::point::cptr& point,
×
78
    const chain::script::cptr& script, uint32_t sequence) NOEXCEPT
×
79
  : input(
80
      point ? point : to_shared<chain::point>(),
×
81
      script ? script : to_shared<chain::script>(),
×
82
      to_shared<chain::witness>(),
×
83
      sequence, true)
×
84
{
85
}
×
86

87
input::input(chain::point&& point, chain::script&& script,
11✔
88
    chain::witness&& witness, uint32_t sequence) NOEXCEPT
11✔
89
  : input(
90
      to_shared(std::move(point)),
11✔
91
      to_shared(std::move(script)),
11✔
92
      to_shared(std::move(witness)),
11✔
93
      sequence, true)
11✔
94
{
95
}
11✔
96

97
input::input(const chain::point& point, const chain::script& script,
1✔
98
    const chain::witness& witness, uint32_t sequence) NOEXCEPT
1✔
99
  : input(
100
      to_shared(point),
1✔
101
      to_shared(script),
1✔
102
      to_shared(witness),
1✔
103
      sequence, true)
1✔
104
{
105
}
1✔
106

107
input::input(const chain::point::cptr& point, const chain::script::cptr& script,
×
108
    const chain::witness::cptr& witness, uint32_t sequence) NOEXCEPT
×
109
  : input(point, script, witness, sequence, true)
×
110
{
111
}
×
112

113
input::input(const data_slice& data) NOEXCEPT
5✔
114
    BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
115
  : input(stream::in::copy(data))
5✔
116
    BC_POP_WARNING()
117
{
118
}
5✔
119

120
input::input(std::istream&& stream) NOEXCEPT
5✔
121
  : input(read::bytes::istream(stream))
5✔
122
{
123
}
5✔
124

125
input::input(std::istream& stream) NOEXCEPT
3✔
126
  : input(read::bytes::istream(stream))
3✔
127
{
128
}
3✔
129

130
input::input(reader&& source) NOEXCEPT
8✔
131
  : input(from_data(source))
8✔
132
{
133
}
8✔
134

135
input::input(reader& source) NOEXCEPT
225✔
136
  : input(from_data(source))
225✔
137
{
138
}
225✔
139

140
// protected
141
input::input(const chain::point::cptr& point, const chain::script::cptr& script,
1,067✔
142
    const chain::witness::cptr& witness, uint32_t sequence, bool valid) NOEXCEPT
1,067✔
143
  : point_(point),
144
    script_(script),
145
    witness_(witness),
146
    sequence_(sequence),
1,067✔
147
    valid_(valid)
1,067✔
148
{
149
}
1,067✔
150

151
// Operators.
152
// ----------------------------------------------------------------------------
153

154
bool input::operator==(const input& other) const NOEXCEPT
40✔
155
{
156
    return (sequence_ == other.sequence_)
40✔
157
        && (point_ == other.point_ || *point_ == *other.point_)
38✔
158
        && (script_ == other.script_ || *script_ == *other.script_)
38✔
159
        && (witness_ == other.witness_ || *witness_ == *other.witness_);
78✔
160
}
161

162
bool input::operator!=(const input& other) const NOEXCEPT
2✔
163
{
164
    return !(*this == other);
2✔
165
}
166

167
// Deserialization.
168
// ----------------------------------------------------------------------------
169

170
// static/private
171
input input::from_data(reader& source) NOEXCEPT
233✔
172
{
173
    // Witness is deserialized by transaction.
174
    return
233✔
175
    {
176
        to_shared<chain::point>(source),
233✔
177
        to_shared<chain::script>(source, true),
466✔
178
        to_shared<chain::witness>(),
233✔
179
        source.read_4_bytes_little_endian(),
233✔
180
        source
181
    };
466✔
182
}
183

184
// Serialization.
185
// ----------------------------------------------------------------------------
186

187
data_chunk input::to_data() const NOEXCEPT
1✔
188
{
189
    data_chunk data(serialized_size(false));
1✔
190

191
    BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
192
    stream::out::copy ostream(data);
1✔
193
    BC_POP_WARNING()
194

195
    to_data(ostream);
1✔
196
    return data;
2✔
197
}
1✔
198

199
void input::to_data(std::ostream& stream) const NOEXCEPT
2✔
200
{
201
    write::bytes::ostream out(stream);
2✔
202
    to_data(out);
2✔
203
}
2✔
204

205
// Witness is serialized by transaction.
206
void input::to_data(writer& sink) const NOEXCEPT
1,357✔
207
{
208
    point_->to_data(sink);
1,357✔
209
    script_->to_data(sink, true);
1,357✔
210
    sink.write_4_bytes_little_endian(sequence_);
1,357✔
211
}
1,357✔
212

213
size_t input::serialized_size(bool witness) const NOEXCEPT
51✔
214
{
215
    // input.serialized_size(witness) provides sizing for witness, however
216
    // witnesses are serialized by the transaction. This is an ugly hack as a
217
    // consequence of bip144 not serializing witnesses as part of inputs, which
218
    // is logically the proper association.
219
    return point_->serialized_size()
51✔
220
        + script_->serialized_size(true)
51✔
221
        + (witness ? witness_->serialized_size(true) : zero)
51✔
222
        + sizeof(sequence_);
51✔
223
}
224

225
// Properties.
226
// ----------------------------------------------------------------------------
227

228
bool input::is_valid() const NOEXCEPT
15✔
229
{
230
    return valid_;
15✔
231
}
232

233
const point& input::point() const NOEXCEPT
155✔
234
{
235
    return *point_;
155✔
236
}
237

238
const chain::script& input::script() const NOEXCEPT
76✔
239
{
240
    return *script_;
76✔
241
}
242

243
const chain::witness& input::witness() const NOEXCEPT
1,793✔
244
{
245
    return *witness_;
1,793✔
246
}
247

248
const point::cptr& input::point_ptr() const NOEXCEPT
×
249
{
250
    return point_;
×
251
}
252

253
const chain::script::cptr& input::script_ptr() const NOEXCEPT
1,555✔
254
{
255
    return script_;
1,555✔
256
}
257

258
const chain::witness::cptr& input::witness_ptr() const NOEXCEPT
×
259
{
260
    return witness_;
×
261
}
262

263
uint32_t input::sequence() const NOEXCEPT
73✔
264
{
265
    return sequence_;
73✔
266
}
267

268
// Methods.
269
// ----------------------------------------------------------------------------
270

271
bool input::is_final() const NOEXCEPT
22✔
272
{
273
    return sequence_ == max_input_sequence;
22✔
274
}
275

276
// static
277
bool input::is_locked(uint32_t sequence, size_t height,
10✔
278
    uint32_t median_time_past, size_t prevout_height,
279
    uint32_t prevout_median_time_past) NOEXCEPT
280
{
281
    // BIP68: if bit 31 is set then no consensus meaning is applied.
282
    if (get_right(sequence, relative_locktime_disabled_bit))
10✔
283
        return false;
284

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

288
    // BIP68: bit 22 determines if relative lock is time or block based.
289
    if (get_right(sequence, relative_locktime_time_locked_bit))
8✔
290
    {
291
        // BIP68: change sequence to seconds by shift up by 9 bits (x 512).
292
        auto time = shift_left(blocks, relative_locktime_seconds_shift_left);
3✔
293
        auto age = floored_subtract(median_time_past, prevout_median_time_past);
3✔
294
        return age < time;
3✔
295
    }
296

297
    const auto age = floored_subtract(height, prevout_height);
5✔
298
    return age < blocks;
5✔
299
}
300

301
bool input::is_locked(size_t height, uint32_t median_time_past) const NOEXCEPT
10✔
302
{
303
    // Prevout must be found and height/median_time_past metadata populated.
304
    ////BC_ASSERT(!is_zero(metadata.height));
305
    return is_locked(sequence_, height, median_time_past, metadata.height,
10✔
306
        metadata.median_time_past);
10✔
307
}
308

309
bool input::reserved_hash(hash_digest& out) const NOEXCEPT
×
310
{
311
    if (!witness::is_reserved_pattern(witness_->stack()))
×
312
        return false;
313

314
    std::copy_n(witness_->stack().front()->begin(), hash_size, out.begin());
×
315
    return true;
×
316
}
317

318
// private
319
// prevout_script is only used to determine is_pay_script_hash_pattern.
320
bool input::extract_sigop_script(chain::script& out,
×
321
    const chain::script& prevout_script) const NOEXCEPT
322
{
323
    // There are no embedded sigops when the prevout script is not p2sh.
324
    if (!script::is_pay_script_hash_pattern(prevout_script.ops()))
×
325
        return false;
326

327
    // There are no embedded sigops when the input script is not push only.
328
    const auto& ops = script_->ops();
×
329
    if (ops.empty() || !script::is_relaxed_push(ops))
×
330
        return false;
×
331

332
    // Parse the embedded script from the last input script item (data).
333
    // This cannot fail because there is no prefix to invalidate the length.
334
    out = { ops.back().data(), false };
×
335
    return true;
×
336
}
337

338
// TODO: Prior to block 79400 sigops were limited only by policy.
339
// TODO: Create legacy sigops fork flag and pass here, return 0 if false.
340
// TODO: this was an unbipped flag day soft fork, prior to BIP16/141.
341
// TODO: if (nHeight > 79400 && GetSigOpCount() > MAX_BLOCK_SIGOPS).
342
size_t input::signature_operations(bool bip16, bool bip141) const NOEXCEPT
7✔
343
{
344
    // Penalize quadratic signature operations (bip141).
345
    const auto factor = bip141 ? heavy_sigops_factor : one;
7✔
346
    const auto sigops = script_->signature_operations(false) * factor;
7✔
347

348
    // ************************************************************************
349
    // CONSENSUS: coinbase input cannot execute, but sigops are counted anyway.
350
    // ************************************************************************
351
    if (!prevout)
7✔
352
        return sigops;
353

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

357
    chain::script witness;
×
358
    if (bip141 && witness_->extract_sigop_script(witness, prevout->script()))
×
359
    {
360
        // Add sigops in the witness script (bip141).
361
        return ceilinged_add(sigops, witness.signature_operations(true));
×
362
    }
363

364
    chain::script embedded;
×
365
    if (bip16 && extract_sigop_script(embedded, prevout->script()))
×
366
    {
367
        if (bip141 && witness_->extract_sigop_script(witness, embedded))
×
368
        {
369
            // Add sigops in the embedded witness script (bip141).
370
            return ceilinged_add(sigops, witness.signature_operations(true));
×
371
        }
372
        else
373
        {
374
            // Add heavy sigops in the embedded script (bip16).
375
            return ceilinged_add(sigops, embedded.signature_operations(true) *
×
376
                factor);
377
        }
378
    }
379

380
    return sigops;
381
}
×
382

383
// JSON value convertors.
384
// ----------------------------------------------------------------------------
385

386
namespace json = boost::json;
387

388
// boost/json will soon have NOEXCEPT: github.com/boostorg/json/pull/636
389
BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
390

391
input tag_invoke(json::value_to_tag<input>, const json::value& value) NOEXCEPT
5✔
392
{
393
    return
5✔
394
    {
395
        json::value_to<chain::point>(value.at("point")),
5✔
396
        json::value_to<chain::script>(value.at("script")),
5✔
397
        json::value_to<chain::witness>(value.at("witness")),
10✔
398
        value.at("sequence").to_number<uint32_t>()
10✔
399
    };
5✔
400
}
401

402
void tag_invoke(json::value_from_tag, json::value& value,
10✔
403
    const input& input) NOEXCEPT
404
{
405
    value =
10✔
406
    {
407
        { "point", input.point() },
408
        { "script", input.script() },
409
        { "witness", input.witness() },
410
        { "sequence", input.sequence() }
411
    };
10✔
412
}
10✔
413

414
BC_POP_WARNING()
415

416
input::cptr tag_invoke(json::value_to_tag<input::cptr>,
×
417
    const json::value& value) NOEXCEPT
418
{
419
    return to_shared(tag_invoke(json::value_to_tag<input>{}, value));
×
420
}
421

422
// Shared pointer overload is required for navigation.
423
BC_PUSH_WARNING(SMART_PTR_NOT_NEEDED)
424
BC_PUSH_WARNING(NO_VALUE_OR_CONST_REF_SHARED_PTR)
425

426
void tag_invoke(json::value_from_tag tag, json::value& value,
8✔
427
    const input::cptr& input) NOEXCEPT
428
{
429
    tag_invoke(tag, value, *input);
8✔
430
}
8✔
431

432
BC_POP_WARNING()
433
BC_POP_WARNING()
434

435
} // namespace chain
436
} // namespace system
437
} // 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