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

libbitcoin / libbitcoin-system / 23131564199

16 Mar 2026 06:52AM UTC coverage: 81.533% (+0.02%) from 81.516%
23131564199

push

github

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

Expand address parse for taproot, patterns for witness/taproot.

39 of 40 new or added lines in 5 files covered. (97.5%)

2 existing lines in 1 file now uncovered.

11161 of 13689 relevant lines covered (81.53%)

3462132.56 hits per line

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

64.15
/src/chain/script_extract.cpp
1
/**
2
 * Copyright (c) 2011-2026 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 <bitcoin/system/chain/enums/script_pattern.hpp>
22
#include <bitcoin/system/chain/enums/script_version.hpp>
23
#include <bitcoin/system/chain/enums/magic_numbers.hpp>
24
#include <bitcoin/system/chain/enums/opcode.hpp>
25
#include <bitcoin/system/chain/operation.hpp>
26
#include <bitcoin/system/data/data.hpp>
27
#include <bitcoin/system/define.hpp>
28

29
namespace libbitcoin {
30
namespace system {
31
namespace chain {
32

33
// Extraction.
34
// ----------------------------------------------------------------------------
35

36
const chunk_cptr& script::witness_program() const NOEXCEPT
24✔
37
{
38
    static const auto empty = to_shared<const data_chunk>();
25✔
39
    return is_witness_program_pattern(ops()) ? ops().at(1).data_ptr() : empty;
24✔
40
}
41

42
script_version script::version() const NOEXCEPT
24✔
43
{
44
    if (!is_witness_program_pattern(ops()))
24✔
45
        return script_version::unversioned;
46

47
    switch (ops_.front().code())
24✔
48
    {
49
        case opcode::push_size_0:
50
            return script_version::segwit;
51
        case opcode::push_positive_1:
×
52
            return script_version::taproot;
×
53
        default:
×
54
            return script_version::reserved;
×
55
    }
56
}
57

58
// Caller should test for is_sign_script_hash_pattern when sign_key_hash result
59
// as it is possible for an input script to match both patterns.
60
script_pattern script::pattern() const NOEXCEPT
12✔
61
{
62
    const auto input = output_pattern();
12✔
63
    return input == script_pattern::non_standard ? input_pattern() : input;
12✔
64
}
65

66
// Output patterns are mutually and input unambiguous.
67
// The bip141 coinbase pattern is not tested here, must test independently.
68
script_pattern script::output_pattern() const NOEXCEPT
24✔
69
{
70
    if (is_pay_key_hash_pattern(ops()))
24✔
71
        return script_pattern::pay_key_hash;
72

73
    if (is_pay_script_hash_pattern(ops()))
24✔
74
        return script_pattern::pay_script_hash;
75

76
    if (is_pay_null_data_pattern(ops()))
24✔
77
        return script_pattern::pay_null_data;
78

79
    if (is_pay_public_key_pattern(ops()))
20✔
80
        return script_pattern::pay_public_key;
81

82
    if (is_pay_multisig_pattern(ops()))
20✔
83
        return script_pattern::pay_multisig;
84

85
    if (is_pay_witness_key_hash_pattern(ops()))
10✔
86
        return script_pattern::pay_witness_key_hash;
87

88
    if (is_pay_witness_script_hash_pattern(ops()))
10✔
89
        return script_pattern::pay_witness_script_hash;
90

91
    if (is_pay_witness_taproot_pattern(ops()))
10✔
NEW
92
        return script_pattern::pay_witness_v1_taproot;
×
93

94
    return script_pattern::non_standard;
95
}
96

97
// A sign_key_hash result always implies sign_script_hash as well.
98
// The bip34 coinbase pattern is not tested here, must test independently.
99
script_pattern script::input_pattern() const NOEXCEPT
17✔
100
{
101
    if (is_sign_key_hash_pattern(ops()))
17✔
102
        return script_pattern::sign_key_hash;
103

104
    // This must follow is_sign_key_hash_pattern for ambiguity comment to hold.
105
    if (is_sign_script_hash_pattern(ops()))
17✔
106
        return script_pattern::sign_script_hash;
107

108
    if (is_sign_public_key_pattern(ops()))
17✔
109
        return script_pattern::sign_public_key;
110

111
    if (is_sign_multisig_pattern(ops()))
17✔
112
        return script_pattern::sign_multisig;
×
113

114
    return script_pattern::non_standard;
115
}
116

117
// prevout_script is only used to determine is_pay_script_hash_pattern.
118
bool script::extract_sigop_script(script& embedded,
×
119
    const chain::script& prevout_script) const NOEXCEPT
120
{
121
    // There are no embedded sigops when the prevout script is not p2sh.
122
    if (!is_pay_script_hash_pattern(prevout_script.ops()))
×
123
        return false;
124

125
    // There are no embedded sigops when the input script is not push only.
126
    if (ops().empty() || !is_relaxed_push_pattern(ops()))
×
127
        return false;
×
128

129
    // Parse the embedded script from the last input script item (data).
130
    // This cannot fail because there is no prefix to invalidate the length.
131
    embedded = { ops().back().data(), false };
×
132
    return true;
×
133
}
134

135
// Count 1..16 multisig accurately for embedded [bip16] and witness [bip141].
136
constexpr size_t multisig_sigops(bool accurate, opcode code) NOEXCEPT
×
137
{
138
    return accurate && operation::is_positive(code) ?
×
139
        operation::opcode_to_positive(code) : multisig_default_sigops;
×
140
}
141

142
constexpr bool is_single_sigop(opcode code) NOEXCEPT
24✔
143
{
144
    return code == opcode::checksig || code == opcode::checksigverify;
24✔
145
}
146

147
constexpr bool is_multiple_sigop(opcode code) NOEXCEPT
×
148
{
149
    return code == opcode::checkmultisig || code == opcode::checkmultisigverify;
×
150
}
151

152
// TODO: compute in or at script evaluation and add coinbase input scripts?
153
// TODO: this would avoid second deserialization of script for sigop counting.
154
size_t script::signature_operations(bool accurate) const NOEXCEPT
12✔
155
{
156
    size_t total{};
12✔
157
    auto last = opcode::push_negative_1;
12✔
158

159
    for (const auto& op: ops())
36✔
160
    {
161
        const auto code = op.code();
24✔
162

163
        if (is_single_sigop(code))
24✔
164
        {
165
            total = ceilinged_add(total, one);
24✔
166
        }
167
        else if (is_multiple_sigop(code))
×
168
        {
169
            total = ceilinged_add(total, multisig_sigops(accurate, last));
×
170
        }
171

172
        last = code;
24✔
173
    }
174

175
    return total;
12✔
176
}
177

178
} // namespace chain
179
} // namespace system
180
} // 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