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

libbitcoin / libbitcoin-system / 15176684817

22 May 2025 02:25AM UTC coverage: 81.258% (+0.02%) from 81.241%
15176684817

push

github

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

Implement on-demand signature hash caching on three pointers.

97 of 135 new or added lines in 8 files covered. (71.85%)

5 existing lines in 4 files now uncovered.

10423 of 12827 relevant lines covered (81.26%)

3731415.67 hits per line

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

72.22
/src/chain/output.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/output.hpp>
20

21
#include <algorithm>
22
#include <iterator>
23
#include <memory>
24
#include <bitcoin/system/chain/enums/magic_numbers.hpp>
25
#include <bitcoin/system/define.hpp>
26
#include <bitcoin/system/hash/hash.hpp>
27
#include <bitcoin/system/math/math.hpp>
28
#include <bitcoin/system/stream/stream.hpp>
29

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

34
BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
35
BC_PUSH_WARNING(NO_ARRAY_INDEXING)
36

37
// Product overflows guarded by script size limit.
38
static_assert(max_script_size <
39
    max_size_t / multisig_default_sigops / heavy_sigops_factor,
40
    "output sigop overflow guard");
41

42
// This is a consensus critical value that must be set on reset.
43
const uint64_t output::not_found = sighash_null_value;
44

45
// Constructors.
46
// ----------------------------------------------------------------------------
47

48
// Invalid default used in signature hashing (validity ignored).
49
// Invalidity is also used to determine that a prevout is not found.
50
output::output() NOEXCEPT
10✔
51
  : output(output::not_found, to_shared<chain::script>(), false)
10✔
52
{
53
}
10✔
54

55
output::output(uint64_t value, chain::script&& script) NOEXCEPT
196✔
56
  : output(value, to_shared(std::move(script)), true)
196✔
57
{
58
}
196✔
59

60
output::output(uint64_t value, const chain::script& script) NOEXCEPT
734✔
61
  : output(value, to_shared(script), true)
734✔
62
{
63
}
734✔
64

65
output::output(uint64_t value, const chain::script::cptr& script) NOEXCEPT
×
66
  : output(value, script ? script : to_shared<chain::script>(), true)
×
67
{
68
}
×
69

70
output::output(stream::in::fast&& stream) NOEXCEPT
4✔
71
  : output(read::bytes::fast(stream))
4✔
72
{
73
}
4✔
74

75
output::output(stream::in::fast& stream) NOEXCEPT
×
76
  : output(read::bytes::fast(stream))
×
77
{
78
}
×
79

80
output::output(std::istream&& stream) NOEXCEPT
×
81
  : output(read::bytes::istream(stream))
×
82
{
83
}
×
84

85
output::output(std::istream& stream) NOEXCEPT
2✔
86
  : output(read::bytes::istream(stream))
2✔
87
{
88
}
2✔
89

90
output::output(reader&& source) NOEXCEPT
6✔
91
  : output(source)
6✔
92
{
93
}
×
94

95
output::output(reader& source) NOEXCEPT
281✔
96
  : value_(source.read_8_bytes_little_endian()),
562✔
97
    script_(CREATE(chain::script, source.get_allocator(), source, true)),
281✔
98
    valid_(source),
281✔
99
    size_(serialized_size(*script_, value_))
562✔
100
{
101
}
281✔
102

103
// protected
104
output::output(uint64_t value, const chain::script::cptr& script,
940✔
105
    bool valid) NOEXCEPT
940✔
106
  : value_(value),
940✔
107
    script_(script),
108
    valid_(valid),
940✔
109
    size_(serialized_size(*script, value))
940✔
110
{
111
}
940✔
112

113
// Operators.
114
// ----------------------------------------------------------------------------
115

116
bool output::operator==(const output& other) const NOEXCEPT
45✔
117
{
118
    return (value_ == other.value_)
45✔
119
        && (script_ == other.script_ || *script_ == *other.script_);
45✔
120
}
121

122
bool output::operator!=(const output& other) const NOEXCEPT
2✔
123
{
124
    return !(*this == other);
2✔
125
}
126

127
// Deserialization.
128
// ----------------------------------------------------------------------------
129

130
// Serialization.
131
// ----------------------------------------------------------------------------
132

133
data_chunk output::to_data() const NOEXCEPT
2✔
134
{
135
    data_chunk data(serialized_size());
2✔
136
    stream::out::fast ostream(data);
2✔
137
    write::bytes::fast out(ostream);
2✔
138
    to_data(out);
2✔
139
    return data;
4✔
140
}
2✔
141

142
void output::to_data(std::ostream& stream) const NOEXCEPT
1✔
143
{
144
    write::bytes::ostream out(stream);
1✔
145
    to_data(out);
1✔
146
}
1✔
147

148
void output::to_data(writer& sink) const NOEXCEPT
1,712✔
149
{
150
    sink.write_8_bytes_little_endian(value_);
1,712✔
151
    script_->to_data(sink, true);
1,712✔
152
}
1,712✔
153

154
// static/private
155
size_t output::serialized_size(const chain::script& script,
1,221✔
156
    uint64_t value) NOEXCEPT
157
{
158
    return ceilinged_add(sizeof(value), script.serialized_size(true));
1,221✔
159
}
160

161
size_t output::serialized_size() const NOEXCEPT
398✔
162
{
163
    return size_;
2✔
164
}
165

166
// Properties.
167
// ----------------------------------------------------------------------------
168

169
bool output::is_valid() const NOEXCEPT
9✔
170
{
171
    return valid_;
9✔
172
}
173

174
uint64_t output::value() const NOEXCEPT
55✔
175
{
176
    return value_;
10✔
177
}
178

179
const chain::script& output::script() const NOEXCEPT
174✔
180
{
181
    return *script_;
10✔
182
}
183

184
const chain::script::cptr& output::script_ptr() const NOEXCEPT
1,496✔
185
{
186
    return script_;
1,496✔
187
}
188

189
// Methods.
190
// ----------------------------------------------------------------------------
191

192
hash_digest output::hash() const NOEXCEPT
×
193
{
194
    hash_digest out{};
×
195
    stream::out::fast stream{ out };
×
196
    hash::sha256::fast sink{ stream };
×
197
    to_data(sink);
×
198
    sink.flush();
×
199
    return out;
×
200
}
×
201

202
// NOT THREAD SAFE
203
// Proves benefit only with multiple tapscript hash_single per input script.
NEW
204
const hash_digest& output::get_hash() const NOEXCEPT
×
205
{
NEW
206
    if (!cache_)
×
NEW
207
        cache_ = std::make_shared<const hash_digest>(hash());
×
208

NEW
209
    return *cache_;
×
210
}
211

UNCOV
212
bool output::committed_hash(hash_cref& out) const NOEXCEPT
×
213
{
214
    const auto& ops = script_->ops();
×
215
    if (!script::is_commitment_pattern(ops))
×
216
        return false;
217

218
    // Offset four bytes for witness commitment head [bip141].
219
    const auto start = std::next(ops[1].data().data(), sizeof(witness_head));
×
220

221
    // Guarded by is_commitment_pattern.
222
    out = unsafe_array_cast<uint8_t, hash_size>(start);
×
223
    return true;
×
224
}
225

226
size_t output::signature_operations(bool bip141) const NOEXCEPT
1✔
227
{
228
    // Sigops in the current output script, input script, and P2SH embedded
229
    // script are counted at four times their previous value (heavy) [bip141].
230
    const auto factor = bip141 ? heavy_sigops_factor : one;
1✔
231

232
    // Count heavy sigops in the output script (inaccurate).
233
    return script_->signature_operations(false) * factor;
1✔
234
}
235

236
bool output::is_dust(uint64_t minimum_value) const NOEXCEPT
9✔
237
{
238
    // If provably unspendable it does not expand the unspent output set. Dust
239
    // is all about prunability. Miners can be expected take the largest fee
240
    // independent of dust, so this is an attempt to prevent miners from seeing
241
    // transactions with unprunable outputs.
242
    return value_ < minimum_value && !script_->is_unspendable();
9✔
243
}
244

245
BC_POP_WARNING()
246
BC_POP_WARNING()
247

248
// JSON value convertors.
249
// ----------------------------------------------------------------------------
250

251
namespace json = boost::json;
252

253
// boost/json will soon have NOEXCEPT: github.com/boostorg/json/pull/636
254
BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
255

256
output tag_invoke(json::value_to_tag<output>,
5✔
257
    const json::value& value) NOEXCEPT
258
{
259
    return
5✔
260
    {
261
        value.at("value").to_number<uint64_t>(),
5✔
262
        json::value_to<chain::script>(value.at("script"))
10✔
263
    };
10✔
264
}
265

266
void tag_invoke(json::value_from_tag, json::value& value,
10✔
267
    const output& output) NOEXCEPT
268
{
269
    value =
10✔
270
    {
271
        { "value", output.value() },
272
        { "script", output.script() },
273
    };
10✔
274
}
10✔
275

276
BC_POP_WARNING()
277

278
output::cptr tag_invoke(json::value_to_tag<output::cptr>,
×
279
    const json::value& value) NOEXCEPT
280
{
281
    return to_shared(tag_invoke(json::value_to_tag<output>{}, value));
×
282
}
283

284
// Shared pointer overload is required for navigation.
285
BC_PUSH_WARNING(SMART_PTR_NOT_NEEDED)
286
BC_PUSH_WARNING(NO_VALUE_OR_CONST_REF_SHARED_PTR)
287

288
void tag_invoke(json::value_from_tag tag, json::value& value,
8✔
289
    const output::cptr& output) NOEXCEPT
290
{
291
    tag_invoke(tag, value, *output);
8✔
292
}
8✔
293

294
BC_POP_WARNING()
295
BC_POP_WARNING()
296

297
} // namespace chain
298
} // namespace system
299
} // 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