• 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

63.91
/src/chain/transaction_cache.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/transaction.hpp>
20

21
#include <iterator>
22
#include <bitcoin/system/chain/input.hpp>
23
#include <bitcoin/system/chain/output.hpp>
24
#include <bitcoin/system/chain/script.hpp>
25
#include <bitcoin/system/data/data.hpp>
26
#include <bitcoin/system/endian/endian.hpp>
27
#include <bitcoin/system/define.hpp>
28
#include <bitcoin/system/hash/hash.hpp>
29
#include <bitcoin/system/stream/stream.hpp>
30

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

35
// Identity hashing.
36
// ----------------------------------------------------------------------------
37

38
// static
39
// Compute the desegregated hash from a segregated buffer (used by network).
40
hash_digest transaction::desegregated_hash(size_t witnessed,
×
41
    size_t unwitnessed, const uint8_t* data) NOEXCEPT
42
{
43
    if (is_null(data))
×
44
        return null_hash;
×
45

46
    constexpr auto preamble = sizeof(uint32_t) + two * sizeof(uint8_t);
×
47
    const auto puts = floored_subtract(unwitnessed, two * sizeof(uint32_t));
×
48
    const auto locktime = floored_subtract(witnessed, sizeof(uint32_t));
×
49

50
    hash_digest digest{};
×
51
    stream::out::fast stream{ digest };
×
52
    hash::sha256x2::fast sink{ stream };
×
53
    sink.write_bytes(data, sizeof(uint32_t));
×
54
    sink.write_bytes(std::next(data, preamble), puts);
×
55
    sink.write_bytes(std::next(data, locktime), sizeof(uint32_t));
×
56
    sink.flush();
×
57
    return digest;
×
58
}
×
59

60
// Canonical hash, recomputes if not cached, returns copy if cached.
61
hash_digest transaction::hash(bool witness) const NOEXCEPT
934✔
62
{
63
    if (segregated_)
934✔
64
    {
65
        if (witness)
23✔
66
        {
67
            // Witness coinbase tx hash is assumed to be null_hash [bip141].
NEW
68
            if (witness_hash_) return *witness_hash_;
×
NEW
69
            if (is_coinbase()) return null_hash;
×
70
        }
71
        else
72
        {
73
            if (nominal_hash_) return *nominal_hash_;
23✔
74
        }
75
    }
76
    else
77
    {
78
        if (nominal_hash_) return *nominal_hash_;
911✔
79
    }
80

81
    hash_digest digest{};
927✔
82
    stream::out::fast stream{ digest };
927✔
83
    hash::sha256x2::fast sink{ stream };
927✔
84
    to_data(sink, witness);
927✔
85
    sink.flush();
927✔
86
    return digest;
927✔
87
}
927✔
88

89
// Cached identity hashing (not thead safe).
90
// ----------------------------------------------------------------------------
91

92
// Used to populate nominal hash after wire deserialization and store read.
93
void transaction::set_nominal_hash(const hash_digest& hash) const NOEXCEPT
20✔
94
{
95
    nominal_hash_ = hash;
20✔
96
}
1✔
97

98
// Used to populate witness hash after wire deserialization (not stored).
99
void transaction::set_witness_hash(const hash_digest& hash) const NOEXCEPT
2✔
100
{
101
    witness_hash_ = hash;
2✔
102
}
1✔
103

104
// Efficient because always returns a reference and never recomputes.
105
const hash_digest& transaction::get_hash(bool witness) const NOEXCEPT
26✔
106
{
107
    if (witness)
26✔
108
    {
109
        if (!witness_hash_) set_witness_hash(hash(witness));
4✔
110
        return *witness_hash_;
3✔
111
    }
112
    else
113
    {
114
        if (!nominal_hash_) set_nominal_hash(hash(witness));
42✔
115
        return *nominal_hash_;
23✔
116
    }
117
}
118

119
// Cached signature hashing (not thead safe).
120
// ----------------------------------------------------------------------------
121

122
hash_digest transaction::x1_base_hash_points() const NOEXCEPT
6✔
123
{
124
    hash_digest digest{};
6✔
125
    stream::out::fast stream{ digest };
6✔
126
    hash::sha256::fast sink{ stream };
6✔
127
    for (const auto& input: *inputs_)
14✔
128
        input->point().to_data(sink);
8✔
129

130
    sink.flush();
6✔
131
    return digest;
12✔
132
}
6✔
133

134
hash_digest transaction::x1_base_hash_sequences() const NOEXCEPT
6✔
135
{
136
    hash_digest digest{};
6✔
137
    stream::out::fast stream{ digest };
6✔
138
    hash::sha256::fast sink{ stream };
6✔
139
    for (const auto& input: *inputs_)
14✔
140
        sink.write_4_bytes_little_endian(input->sequence());
8✔
141

142
    sink.flush();
6✔
143
    return digest;
12✔
144
}
6✔
145

146
hash_digest transaction::x1_base_hash_outputs() const NOEXCEPT
6✔
147
{
148
    hash_digest digest{};
6✔
149
    stream::out::fast stream{ digest };
6✔
150
    hash::sha256::fast sink{ stream };
6✔
151
    for (const auto& output : *outputs_)
15✔
152
        output->to_data(sink);
9✔
153

154
    sink.flush();
6✔
155
    return digest;
12✔
156
}
6✔
157

158
// This requires ALL prevouts of the tx are populated (new in taproot).
NEW
159
hash_digest transaction::v1_only_hash_amounts() const NOEXCEPT
×
160
{
NEW
161
    hash_digest digest{};
×
NEW
162
    stream::out::fast stream{ digest };
×
NEW
163
    hash::sha256::fast sink{ stream };
×
NEW
164
    for (const auto& input : *inputs_)
×
NEW
165
        sink.write_8_bytes_little_endian(input->prevout->value());
×
166

NEW
167
    sink.flush();
×
NEW
168
    return digest;
×
UNCOV
169
}
×
170

171
// This requires ALL prevouts of the tx are populated (new in taproot).
NEW
172
hash_digest transaction::v1_only_hash_scripts() const NOEXCEPT
×
173
{
NEW
174
    hash_digest digest{};
×
NEW
175
    stream::out::fast stream{ digest };
×
NEW
176
    hash::sha256::fast sink{ stream };
×
NEW
177
    for (const auto& input : *inputs_)
×
NEW
178
        input->prevout->script().to_data(sink, true);
×
179

NEW
180
    sink.flush();
×
NEW
181
    return digest;
×
UNCOV
182
}
×
183

184
BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
185

186
void transaction::set_x1_base_hash() const NOEXCEPT
18✔
187
{
188
    if (!x1_base_cache_)
18✔
189
        x1_base_cache_ = std::make_shared<base_cache>
6✔
190
        (
6✔
191
            x1_base_hash_points(),
6✔
192
            x1_base_hash_sequences(),
6✔
193
            x1_base_hash_outputs()
12✔
194
        );
195
}
18✔
196

197
void transaction::set_x2_base_hash() const NOEXCEPT
20✔
198
{
199
    if (!x2_base_cache_)
20✔
200
        x2_base_cache_ = std::make_shared<base_cache>
6✔
201
        (
6✔
202
            sha256_hash(single_hash_points()),
6✔
203
            sha256_hash(single_hash_sequences()),
6✔
204
            sha256_hash(single_hash_outputs())
6✔
205
        );
206
}
20✔
207

NEW
208
void transaction::set_v1_only_hash() const NOEXCEPT
×
209
{
NEW
210
    if (!v1_only_cache_)
×
NEW
211
        v1_only_cache_ = std::make_shared<only_cache>
×
NEW
212
        (
×
NEW
213
            v1_only_hash_amounts(),
×
NEW
214
            v1_only_hash_scripts()
×
215
        );
NEW
216
}
×
217

218
BC_POP_WARNING()
219

220
// sha256x1 (script verson 1)
221
// ----------------------------------------------------------------------------
222

223
const hash_digest& transaction::single_hash_points() const NOEXCEPT
6✔
224
{
225
    set_x1_base_hash();
6✔
226
    return x1_base_cache_->points;
6✔
227
}
228

229
const hash_digest& transaction::single_hash_sequences() const NOEXCEPT
6✔
230
{
231
    set_x1_base_hash();
6✔
232
    return x1_base_cache_->sequences;
6✔
233
}
234

235
const hash_digest& transaction::single_hash_outputs() const NOEXCEPT
6✔
236
{
237
    set_x1_base_hash();
6✔
238
    return x1_base_cache_->outputs;
6✔
239
}
240

NEW
241
const hash_digest& transaction::single_hash_amounts() const NOEXCEPT
×
242
{
NEW
243
    set_v1_only_hash();
×
NEW
244
    return v1_only_cache_->amounts;
×
245
}
246

NEW
247
const hash_digest& transaction::single_hash_scripts() const NOEXCEPT
×
248
{
NEW
249
    set_v1_only_hash();
×
NEW
250
    return v1_only_cache_->scripts;
×
251
}
252

253
// sha256x2 (script verson 0)
254
// ----------------------------------------------------------------------------
255

256
const hash_digest& transaction::double_hash_points() const NOEXCEPT
9✔
257
{
258
    set_x2_base_hash();
9✔
259
    return x2_base_cache_->points;
9✔
260
}
261

262
const hash_digest& transaction::double_hash_sequences() const NOEXCEPT
5✔
263
{
264
    set_x2_base_hash();
5✔
265
    return x2_base_cache_->sequences;
5✔
266
}
267

268
const hash_digest& transaction::double_hash_outputs() const NOEXCEPT
6✔
269
{
270
    set_x2_base_hash();
6✔
271
    return x2_base_cache_->outputs;
6✔
272
}
273

274
} // namespace chain
275
} // namespace system
276
} // 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