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

libbitcoin / libbitcoin-system / 19162822888

07 Nov 2025 08:37AM UTC coverage: 81.135% (+0.1%) from 80.989%
19162822888

push

github

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

Refactor stream/reader/chain object construction.

68 of 90 new or added lines in 17 files covered. (75.56%)

1 existing line in 1 file now uncovered.

10709 of 13199 relevant lines covered (81.13%)

3587823.84 hits per line

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

75.23
/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(const data_slice& data) NOEXCEPT
4✔
71
  : output(stream::in::fast(data))
4✔
72
{
73
}
4✔
74

75
// protected
76
output::output(stream::in::fast&& stream) NOEXCEPT
4✔
77
  : output(read::bytes::fast(stream))
4✔
78
{
79
}
4✔
80

NEW
81
output::output(stream::in::fast& stream) NOEXCEPT
×
NEW
82
  : output(read::bytes::fast(stream))
×
83
{
84
}
×
85

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

91
// protected
92
output::output(reader&& source) NOEXCEPT
6✔
93
  : output(source)
6✔
94
{
95
}
×
96

97
output::output(reader& source) NOEXCEPT
285✔
98
  : value_(source.read_8_bytes_little_endian()),
570✔
99
    script_(CREATE(chain::script, source.get_allocator(), source, true)),
285✔
100
    valid_(source),
285✔
101
    size_(serialized_size(*script_, value_))
570✔
102
{
103
}
285✔
104

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

115
// Operators.
116
// ----------------------------------------------------------------------------
117

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

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

129
// Deserialization.
130
// ----------------------------------------------------------------------------
131

132
// Serialization.
133
// ----------------------------------------------------------------------------
134

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

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

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

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

163
size_t output::serialized_size() const NOEXCEPT
402✔
164
{
165
    return size_;
2✔
166
}
167

168
// Properties.
169
// ----------------------------------------------------------------------------
170

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

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

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

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

191
// Methods.
192
// ----------------------------------------------------------------------------
193

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

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

211
    return *cache_;
×
212
}
213

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

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

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

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

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

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

247
BC_POP_WARNING()
248
BC_POP_WARNING()
249

250
// JSON value convertors.
251
// ----------------------------------------------------------------------------
252

253
DEFINE_JSON_TO_TAG(output)
5✔
254
{
255
    return
5✔
256
    {
257
        value.at("value").as_uint64(),
5✔
258
        value_to<script>(value.at("script"))
10✔
259
    };
10✔
260
}
261

262
DEFINE_JSON_FROM_TAG(output)
10✔
263
{
264
    value =
10✔
265
    {
266
        { "value", instance.value() },
267
        { "script", value_from(instance.script()) },
20✔
268
    };
10✔
269
}
10✔
270

271
DEFINE_JSON_TO_TAG(output::cptr)
×
272
{
273
    return to_shared(tag_invoke(to_tag<output>{}, value));
×
274
}
275

276
DEFINE_JSON_FROM_TAG(output::cptr)
8✔
277
{
278
    tag_invoke(from_tag{}, value, *instance);
8✔
279
}
8✔
280

281
} // namespace chain
282
} // namespace system
283
} // 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