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

libbitcoin / libbitcoin-system / 15078892484

16 May 2025 11:04PM UTC coverage: 81.885% (-0.3%) from 82.18%
15078892484

push

github

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

Refactor all signature_hash methods to return bool (tapscript).

293 of 491 new or added lines in 17 files covered. (59.67%)

5 existing lines in 3 files now uncovered.

10365 of 12658 relevant lines covered (81.88%)

3781254.62 hits per line

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

64.0
/src/chain/script_extract.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/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
48✔
43
{
44
    if (!is_witness_program_pattern(ops()))
48✔
45
        return script_version::unversioned;
46

47
    switch (ops_.front().code())
48✔
48
    {
49
        case opcode::push_size_0:
50
            return script_version::segwit;
NEW
51
        case opcode::push_size_1:
×
NEW
52
            return script_version::taproot;
×
NEW
53
        default:
×
NEW
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
11✔
61
{
62
    const auto input = output_pattern();
11✔
63
    return input == script_pattern::non_standard ? input_pattern() : input;
11✔
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
22✔
69
{
70
    if (is_pay_key_hash_pattern(ops()))
22✔
71
        return script_pattern::pay_key_hash;
72

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

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

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

82
    // Limited to 16 signatures though op_check_multisig allows 20.
83
    if (is_pay_multisig_pattern(ops()))
18✔
84
        return script_pattern::pay_multisig;
8✔
85

86
    return script_pattern::non_standard;
87
}
88

89
// A sign_key_hash result always implies sign_script_hash as well.
90
// The bip34 coinbase pattern is not tested here, must test independently.
91
script_pattern script::input_pattern() const NOEXCEPT
16✔
92
{
93
    if (is_sign_key_hash_pattern(ops()))
16✔
94
        return script_pattern::sign_key_hash;
95

96
    // This must follow is_sign_key_hash_pattern for ambiguity comment to hold.
97
    if (is_sign_script_hash_pattern(ops()))
16✔
98
        return script_pattern::sign_script_hash;
99

100
    if (is_sign_public_key_pattern(ops()))
16✔
101
        return script_pattern::sign_public_key;
102

103
    if (is_sign_multisig_pattern(ops()))
16✔
NEW
104
        return script_pattern::sign_multisig;
×
105

106
    return script_pattern::non_standard;
107
}
108

109
// prevout_script is only used to determine is_pay_script_hash_pattern.
NEW
110
bool script::extract_sigop_script(script& embedded,
×
111
    const chain::script& prevout_script) const NOEXCEPT
112
{
113
    // There are no embedded sigops when the prevout script is not p2sh.
NEW
114
    if (!is_pay_script_hash_pattern(prevout_script.ops()))
×
115
        return false;
116

117
    // There are no embedded sigops when the input script is not push only.
NEW
118
    if (ops().empty() || !is_relaxed_push_pattern(ops()))
×
NEW
119
        return false;
×
120

121
    // Parse the embedded script from the last input script item (data).
122
    // This cannot fail because there is no prefix to invalidate the length.
NEW
123
    embedded = { ops().back().data(), false };
×
NEW
124
    return true;
×
125
}
126

127
// Count 1..16 multisig accurately for embedded [bip16] and witness [bip141].
NEW
128
constexpr size_t multisig_sigops(bool accurate, opcode code) NOEXCEPT
×
129
{
NEW
130
    return accurate && operation::is_positive(code) ?
×
NEW
131
        operation::opcode_to_positive(code) : multisig_default_sigops;
×
132
}
133

134
constexpr bool is_single_sigop(opcode code) NOEXCEPT
24✔
135
{
136
    return code == opcode::checksig || code == opcode::checksigverify;
24✔
137
}
138

NEW
139
constexpr bool is_multiple_sigop(opcode code) NOEXCEPT
×
140
{
NEW
141
    return code == opcode::checkmultisig || code == opcode::checkmultisigverify;
×
142
}
143

144
// TODO: compute in or at script evaluation and add coinbase input scripts?
145
// TODO: this would avoid second deserialization of script for sigop counting.
146
size_t script::signature_operations(bool accurate) const NOEXCEPT
12✔
147
{
148
    size_t total{};
12✔
149
    auto last = opcode::push_negative_1;
12✔
150

151
    for (const auto& op: ops())
36✔
152
    {
153
        const auto code = op.code();
24✔
154

155
        if (is_single_sigop(code))
24✔
156
        {
157
            total = ceilinged_add(total, one);
24✔
158
        }
NEW
159
        else if (is_multiple_sigop(code))
×
160
        {
NEW
161
            total = ceilinged_add(total, multisig_sigops(accurate, last));
×
162
        }
163

164
        last = code;
24✔
165
    }
166

167
    return total;
12✔
168
}
169

170
} // namespace chain
171
} // namespace system
172
} // 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