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

libbitcoin / libbitcoin-system / 9310800761

31 May 2024 12:08AM UTC coverage: 82.732% (-0.01%) from 82.746%
9310800761

push

github

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

Performance optimizations, style, comments.

233 of 289 new or added lines in 11 files covered. (80.62%)

8 existing lines in 4 files now uncovered.

9812 of 11860 relevant lines covered (82.73%)

4808594.09 hits per line

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

85.09
/include/bitcoin/system/impl/chain/script.ipp
1
/**
2
 * Copyright (c) 2011-2024 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_CHAIN_SCRIPT_IPP
20
#define LIBBITCOIN_SYSTEM_CHAIN_SCRIPT_IPP
21

22
#include <algorithm>
23
#include <bitcoin/system/define.hpp>
24
#include <bitcoin/system/crypto/crypto.hpp>
25
#include <bitcoin/system/chain/enums/coverage.hpp>
26
#include <bitcoin/system/chain/enums/flags.hpp>
27
#include <bitcoin/system/chain/enums/magic_numbers.hpp>
28
#include <bitcoin/system/chain/operation.hpp>
29
#include <bitcoin/system/endian/endian.hpp>
30

31
namespace libbitcoin {
32
namespace system {
33
namespace chain {
34

35
// More efficient [] dereferences are all guarded here.
36
BC_PUSH_WARNING(NO_ARRAY_INDEXING)
37

38
constexpr bool script::is_enabled(uint32_t active_flags, flags flag) NOEXCEPT
1,944✔
39
{
40
    return to_bool(flag & active_flags);
1,944✔
41
}
42

43
VCONSTEXPR bool script::is_push_only_pattern(const operations& ops) NOEXCEPT
16✔
44
{
45
    const auto push = [](const operation& op) NOEXCEPT
123✔
46
    {
47
        return operation::is_push(op.code());
107✔
48
    };
49

50
    return std::all_of(ops.begin(), ops.end(), push);
16✔
51
}
52

53
// ****************************************************************************
54
// CONSENSUS: this pattern is used to activate bip16 validation rules.
55
// ****************************************************************************
56
VCONSTEXPR bool script::is_relaxed_push_pattern(const operations& ops) NOEXCEPT
21✔
57
{
58
    const auto push = [&](const operation& op) NOEXCEPT
58✔
59
    {
60
        return operation::is_relaxed_push(op.code());
37✔
61
    };
62

63
    return std::all_of(ops.begin(), ops.end(), push);
21✔
64
}
65

66
// ****************************************************************************
67
// CONSENSUS: this pattern is used to commit to bip141 witness data.
68
// ****************************************************************************
NEW
69
VCONSTEXPR bool script::is_commitment_pattern(const operations& ops) NOEXCEPT
×
70
{
NEW
71
    constexpr auto header = to_big_endian(chain::witness_head);
×
72

73
    // C++14: remove && ops[1].data().size() >= header.size() guard.
74
    // Bytes after commitment optional with no consensus meaning (bip141).
75
    // Commitment not executable so invalid trailing operations are allowed.
NEW
76
    return ops.size() > 1
×
NEW
77
        && ops[0].code() == opcode::op_return
×
NEW
78
        && ops[1].code() == opcode::push_size_36
×
NEW
79
        && ops[1].data().size() >= header.size()
×
NEW
80
        && std::equal(header.begin(), header.end(), ops[1].data().begin());
×
81
}
82

83
// ****************************************************************************
84
// CONSENSUS: this pattern is used in bip141 validation rules.
85
// ****************************************************************************
86
VCONSTEXPR bool script::is_witness_program_pattern(
528✔
87
    const operations& ops) NOEXCEPT
88
{
89
    return ops.size() == 2
528✔
90
        && ops[0].is_version()
204✔
91
        && ops[1].data().size() >= min_witness_program
120✔
92
        && ops[1].data().size() <= max_witness_program;
624✔
93
}
94

95
// The satoshi client now enables configurable data size for policy.
96
VCONSTEXPR bool script::is_pay_null_data_pattern(const operations& ops) NOEXCEPT
24✔
97
{
98
    return ops.size() == 2
24✔
99
        && ops[0].code() == opcode::op_return
8✔
100
        && ops[1].is_minimal_push()
8✔
101
        && ops[1].data().size() <= max_null_data_size;
32✔
102
}
103

104
// Used by neutrino.
105
VCONSTEXPR bool script::is_pay_op_return_pattern(const operations& ops) NOEXCEPT
87✔
106
{
107
    return !ops.empty()
87✔
108
        && ops[0].code() == opcode::op_return;
87✔
109
}
110

111
// The current 16 (or 20) limit does not affect server indexing because bare
112
// multisig is not indexable and p2sh multisig is byte-limited to 15 sigs.
113
// The satoshi client policy limit is 3 signatures for bare multisig.
114
VCONSTEXPR bool script::is_pay_multisig_pattern(const operations& ops) NOEXCEPT
18✔
115
{
116
    constexpr auto op_1 = static_cast<uint8_t>(opcode::push_positive_1);
18✔
117
    constexpr auto op_16 = static_cast<uint8_t>(opcode::push_positive_16);
18✔
118

119
    const auto op_count = ops.size();
18✔
120

121
    if (op_count < 4 || ops[op_count - 1].code() != opcode::checkmultisig)
18✔
122
        return false;
4✔
123

124
    const auto op_m = static_cast<uint8_t>(ops[0].code());
14✔
125
    const auto op_n = static_cast<uint8_t>(ops[op_count - 2].code());
14✔
126

127
    if (op_m < op_1 || op_m > op_n || op_n < op_1 || op_n > op_16)
14✔
128
        return false;
129

130
    const auto number = op_n - op_1 + 1u;
8✔
131
    const auto points = op_count - 3u;
8✔
132

133
    if (number != points)
8✔
134
        return false;
135

136
    for (auto op = std::next(ops.begin());
58✔
137
        op != std::prev(ops.end(), 2); ++op)
58✔
138
    {
139
        if (!is_public_key(op->data()))
50✔
140
            return false;
141
    }
142

143
    return true;
144
}
145

146
// The satoshi client considers this non-standard for policy.
147
VCONSTEXPR bool script::is_pay_public_key_pattern(
18✔
148
    const operations& ops) NOEXCEPT
149
{
150
    return ops.size() == 2
18✔
151
        && is_public_key(ops[0].data())
18✔
152
        && ops[1].code() == opcode::checksig;
18✔
153
}
154

155
VCONSTEXPR bool script::is_pay_key_hash_pattern(const operations& ops) NOEXCEPT
22✔
156
{
157
    return ops.size() == 5
22✔
NEW
158
        && ops[0].code() == opcode::dup
×
NEW
159
        && ops[1].code() == opcode::hash160
×
NEW
160
        && ops[2].data().size() == short_hash_size
×
NEW
161
        && ops[3].code() == opcode::equalverify
×
162
        && ops[4].code() == opcode::checksig;
22✔
163
}
164

165
// ****************************************************************************
166
// CONSENSUS: this pattern is used to activate bip16 validation rules.
167
// ****************************************************************************
168
VCONSTEXPR bool script::is_pay_script_hash_pattern(
475✔
169
    const operations& ops) NOEXCEPT
170
{
171
    return ops.size() == 3
475✔
172
        && ops[0].code() == opcode::hash160
77✔
173
        && ops[1].code() == opcode::push_size_20
22✔
174
        && ops[2].code() == opcode::equal;
496✔
175
}
176

177
VCONSTEXPR bool script::is_pay_witness_pattern(const operations& ops) NOEXCEPT
1✔
178
{
179
    return ops.size() == 2
1✔
180
        && ops[0].is_version()
1✔
181
        && ops[1].is_push();
2✔
182
}
183

184
VCONSTEXPR bool script::is_pay_witness_key_hash_pattern(
1✔
185
    const operations& ops) NOEXCEPT
186
{
187
    return ops.size() == 2
1✔
188
        && ops[0].code() == opcode::push_size_0
1✔
189
        && ops[1].code() == opcode::push_size_20;
2✔
190
}
191

192
// ****************************************************************************
193
// CONSENSUS: this pattern is used to activate bip141 validation rules.
194
// ****************************************************************************
195
VCONSTEXPR bool script::is_pay_witness_script_hash_pattern(
2✔
196
    const operations& ops) NOEXCEPT
197
{
198
    return ops.size() == 2
2✔
199
        && ops[0].code() == opcode::push_size_0
2✔
200
        && ops[1].code() == opcode::push_size_32;
4✔
201
}
202

203
// The first push is based on wacky satoshi op_check_multisig behavior that
204
// we must perpetuate, though it's appearance here is policy not consensus.
205
// Limiting to push_size_0 removes pattern ambiguity with little downside.
206
VCONSTEXPR bool script::is_sign_multisig_pattern(const operations& ops) NOEXCEPT
16✔
207
{
208
    const auto endorsement = [](const operation& op) NOEXCEPT
24✔
209
    {
210
        return is_endorsement(op.data());
8✔
211
    };
212

213
    return ops.size() >= 2
16✔
214
        && ops[0].code() == opcode::push_size_0
14✔
215
        && std::all_of(std::next(ops.begin()), ops.end(), endorsement);
18✔
216
}
217

218
VCONSTEXPR bool script::is_sign_public_key_pattern(
16✔
219
    const operations& ops) NOEXCEPT
220
{
221
    return ops.size() == 1
16✔
222
        && is_endorsement(ops[0].data());
16✔
223
}
224

225
// ****************************************************************************
226
// CONSENSUS: this pattern is used to activate bip141 validation rules.
227
// ****************************************************************************
228
VCONSTEXPR bool script::is_sign_key_hash_pattern(const operations& ops) NOEXCEPT
16✔
229
{
230
    return ops.size() == 2
16✔
231
        && is_endorsement(ops[0].data())
4✔
232
        && is_public_key(ops[1].data());
20✔
233
}
234

235

236
// Ambiguous with is_sign_key_hash when second/last op is a public key.
237
// Ambiguous with is_sign_public_key_pattern when only op is endorsement.
238
VCONSTEXPR bool script::is_sign_script_hash_pattern(
16✔
239
    const operations& ops) NOEXCEPT
240
{
241
    return !ops.empty()
16✔
242
        && is_push_only_pattern(ops)
16✔
243
        && !ops.back().data().empty();
16✔
244
}
245

246
inline operations script::to_pay_null_data_pattern(
11✔
247
    const data_slice& data) NOEXCEPT
248
{
249
    if (data.size() > max_null_data_size)
11✔
NEW
250
        return {};
×
251
    
252
    return
11✔
253
    {
254
        { opcode::op_return },
255
        { to_chunk(data), false }
22✔
256
    };
44✔
257
}
258

259
inline operations script::to_pay_public_key_pattern(
1✔
260
    const data_slice& point) NOEXCEPT
261
{
262
    if (!is_public_key(point))
1✔
NEW
263
        return {};
×
264
    
265
    return
1✔
266
    {
267
        { to_chunk(point), false },
2✔
268
        { opcode::checksig }
269
    };
3✔
270
}
271

272
inline operations script::to_pay_key_hash_pattern(
5✔
273
    const short_hash& hash) NOEXCEPT
274
{
275
    return
5✔
276
    {
277
        { opcode::dup },
278
        { opcode::hash160 },
279
        { to_chunk(hash), false },
5✔
280
        { opcode::equalverify },
281
        { opcode::checksig }
282
    };
35✔
283
}
284

NEW
285
inline operations script::to_pay_script_hash_pattern(
×
286
    const short_hash& hash) NOEXCEPT
287
{
NEW
288
    return
×
289
    {
290
        { opcode::hash160 },
NEW
291
        { to_chunk(hash), false },
×
292
        { opcode::equal }
NEW
293
    };
×
294
}
295

296
inline operations script::to_pay_multisig_pattern(uint8_t signatures,
297
    const compressed_list& points) NOEXCEPT
298
{
299
    return to_pay_multisig_pattern(signatures,
300
        to_stack<ec_compressed_size>(points));
301
}
302

303
// This supports up to 16 signatures, but check_multisig is limited to 20.
304
// The embedded script is limited to 520 bytes, an effective limit of 15
305
// for p2sh multisig, which can be as low as 7 with all uncompressed keys.
306
inline operations script::to_pay_multisig_pattern(uint8_t signatures,
307
    const data_stack& points) NOEXCEPT
308
{
309
    constexpr auto op_81 = static_cast<uint8_t>(opcode::push_positive_1);
310
    constexpr auto op_96 = static_cast<uint8_t>(opcode::push_positive_16);
311
    constexpr auto base = sub1(op_81);
312
    constexpr auto max = op_96 - base;
313

314
    const auto m = signatures;
315
    const auto n = points.size();
316

317
    if (m < 1 || m > n || n < 1 || n > max)
318
        return {};
319

320
    const auto op_m = static_cast<opcode>(m + base);
321
    const auto op_n = static_cast<opcode>(points.size() + base);
322

323
    operations ops{};
324
    ops.reserve(points.size() + 3);
325
    ops.emplace_back(op_m);
326

327
    for (const auto& point: points)
328
    {
329
        if (!is_public_key(point))
330
            return {};
331

332
        ops.emplace_back(point, false);
333
    }
334

335
    ops.emplace_back(op_n);
336
    ops.emplace_back(opcode::checkmultisig);
337
    return ops;
338
}
339

340
inline operations script::to_pay_witness_pattern(uint8_t version,
10✔
341
    const data_slice& data) NOEXCEPT
342
{
343
    return
10✔
344
    {
345
        { operation::opcode_from_version(version) },
346
        { to_chunk(data), false },
10✔
347
    };
40✔
348
}
349

350
inline operations script::to_pay_witness_key_hash_pattern(
351
    const short_hash& hash) NOEXCEPT
352
{
353
    return
354
    {
355
        { opcode::push_size_0 },
356
        { to_chunk(hash), false },
357
    };
358
}
359

360
inline operations script::to_pay_witness_script_hash_pattern(
361
    const hash_digest& hash) NOEXCEPT
362
{
363
    return
364
    {
365
        { opcode::push_size_0 },
366
        { to_chunk(hash), false }
367
    };
368
}
369

370
BC_POP_WARNING()
371

372
} // namespace chain
373
} // namespace system
374
} // namespace libbitcoin
375

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