Skip to content

Commit a6eeb7e

Browse files
authored
Merge pull request #1676 from evoskuil/master
Use shared_ptr to make annex a safe copyable object.
2 parents 8fe68ad + de02ea6 commit a6eeb7e

26 files changed

+400
-174
lines changed

Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -596,6 +596,7 @@ include_bitcoin_system_impl_chain_HEADERS = \
596596
include/bitcoin/system/impl/chain/compact.ipp \
597597
include/bitcoin/system/impl/chain/operation_patterns.ipp \
598598
include/bitcoin/system/impl/chain/script_patterns.ipp \
599+
include/bitcoin/system/impl/chain/transaction_patterns.ipp \
599600
include/bitcoin/system/impl/chain/witness_patterns.ipp
600601

601602
include_bitcoin_system_impl_datadir = ${includedir}/bitcoin/system/impl/data

builds/msvc/vs2022/libbitcoin-system/libbitcoin-system.vcxproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,7 @@
366366
<ClInclude Include="..\..\..\..\include\bitcoin\system\hash\sha\sha512.hpp" />
367367
<ClInclude Include="..\..\..\..\include\bitcoin\system\hash\siphash.hpp" />
368368
<ClInclude Include="..\..\..\..\include\bitcoin\system\have.hpp" />
369+
<ClInclude Include="..\..\..\..\include\bitcoin\system\impl\chain\transaction_patterns.ipp" />
369370
<ClInclude Include="..\..\..\..\include\bitcoin\system\intrinsics\arm\arm.hpp" />
370371
<ClInclude Include="..\..\..\..\include\bitcoin\system\intrinsics\arm\functional.hpp" />
371372
<ClInclude Include="..\..\..\..\include\bitcoin\system\intrinsics\arm\sha.hpp" />
@@ -655,4 +656,4 @@
655656
<ItemGroup>
656657
<Natvis Include="..\..\debug.natvis" />
657658
</ItemGroup>
658-
</Project>
659+
</Project>

builds/msvc/vs2022/libbitcoin-system/libbitcoin-system.vcxproj.filters

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1460,6 +1460,9 @@
14601460
<ClInclude Include="..\..\resource.h">
14611461
<Filter>resource</Filter>
14621462
</ClInclude>
1463+
<ClInclude Include="..\..\..\..\include\bitcoin\system\impl\chain\transaction_patterns.ipp">
1464+
<Filter>include\bitcoin\system\impl\chain</Filter>
1465+
</ClInclude>
14631466
</ItemGroup>
14641467
<ItemGroup>
14651468
<None Include="..\..\..\..\include\bitcoin\system\impl\chain\annex.ipp">
@@ -1745,4 +1748,4 @@
17451748
<Filter>resource</Filter>
17461749
</ResourceCompile>
17471750
</ItemGroup>
1748-
</Project>
1751+
</Project>

include/bitcoin/system/chain/annex.hpp

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,23 +27,28 @@ namespace libbitcoin {
2727
namespace system {
2828
namespace chain {
2929

30-
class witness;
31-
32-
/// Annex is an abstraction over a witness stack.
30+
/// Annex is an abstraction over the top witness stack element.
3331
class BC_API annex
3432
{
3533
public:
3634
DEFAULT_COPY_MOVE_DESTRUCT(annex);
3735

38-
inline annex(const witness& owner) NOEXCEPT;
36+
inline annex() NOEXCEPT;
37+
inline annex(const chunk_cptr& data) NOEXCEPT;
38+
inline annex(const chunk_cptrs& stack) NOEXCEPT;
3939

4040
inline size_t size() const NOEXCEPT;
4141
inline const data_chunk& data() const NOEXCEPT;
4242
inline const hash_digest hash() const NOEXCEPT;
4343
inline operator bool() const NOEXCEPT;
4444

45+
protected:
46+
static inline chunk_cptr from_stack(const chunk_cptrs& stack) NOEXCEPT;
47+
4548
private:
46-
std::reference_wrapper<const witness> witness_;
49+
static inline const data_chunk& empty_annex() NOEXCEPT;
50+
51+
chunk_cptr data_;
4752
};
4853

4954
} // namespace chain

include/bitcoin/system/chain/enums/magic_numbers.hpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,12 +88,10 @@ constexpr uint8_t witness_enabled = 0x01;
8888
/// ---------------------------------------------------------------------------
8989

9090
constexpr size_t signature_cost = 50;
91-
constexpr size_t control_block_base = 33;
92-
constexpr size_t control_block_node = 32;
93-
constexpr size_t control_block_range = 128;
94-
constexpr uint8_t taproot_leaf_mask = 0xfe;
95-
constexpr uint8_t taproot_leaf_tapscript = 0xc0;
91+
constexpr size_t taproot_max_nodes = 128;
9692
constexpr uint8_t taproot_annex_prefix = 0x50;
93+
constexpr uint8_t tapleaf_tapscript = 0b1100'0000; // 0xc0
94+
constexpr uint8_t tapleaf_root_mask = 0b1111'1110; // 0xfe
9795

9896
/// Policy constants.
9997
/// ---------------------------------------------------------------------------

include/bitcoin/system/chain/script.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ class BC_API script
5050
static constexpr bool is_relaxed_push_pattern(const operations& ops) NOEXCEPT;
5151
static constexpr bool is_commitment_pattern(const operations& ops) NOEXCEPT;
5252
static constexpr bool is_witness_program_pattern(const operations& ops) NOEXCEPT;
53+
static constexpr bool is_anchor_program_pattern(const operations& ops) NOEXCEPT;
5354
static constexpr bool is_pay_null_data_pattern(const operations& ops) NOEXCEPT;
5455
static constexpr bool is_pay_op_return_pattern(const operations& ops) NOEXCEPT;
5556
static constexpr bool is_pay_multisig_pattern(const operations& ops) NOEXCEPT;

include/bitcoin/system/chain/transaction.hpp

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,15 @@
2323
#include <memory>
2424
#include <optional>
2525
#include <vector>
26+
#include <bitcoin/system/chain/enums/coverage.hpp>
2627
#include <bitcoin/system/chain/context.hpp>
2728
#include <bitcoin/system/chain/input.hpp>
2829
#include <bitcoin/system/chain/output.hpp>
2930
#include <bitcoin/system/chain/point.hpp>
3031
#include <bitcoin/system/define.hpp>
3132
#include <bitcoin/system/error/error.hpp>
3233
#include <bitcoin/system/hash/hash.hpp>
34+
#include <bitcoin/system/math/math.hpp>
3335
#include <bitcoin/system/stream/stream.hpp>
3436

3537
namespace libbitcoin {
@@ -236,6 +238,20 @@ class BC_API transaction
236238

237239
private:
238240
typedef struct { size_t nominal; size_t witnessed; } sizes;
241+
typedef struct
242+
{
243+
hash_digest points;
244+
hash_digest sequences;
245+
hash_digest outputs;
246+
} v0_cache;
247+
typedef struct
248+
{
249+
hash_digest amounts;
250+
hash_digest scripts;
251+
hash_digest points;
252+
hash_digest sequences;
253+
hash_digest outputs;
254+
} v1_cache;
239255

240256
static bool segregated(const chain::inputs& inputs) NOEXCEPT;
241257
static bool segregated(const input_cptrs& inputs) NOEXCEPT;
@@ -250,24 +266,14 @@ class BC_API transaction
250266
code connect_input(const context& ctx,
251267
const input_iterator& it) const NOEXCEPT;
252268

253-
// Caching.
269+
// Patterns.
254270
// ------------------------------------------------------------------------
255271

256-
typedef struct
257-
{
258-
hash_digest points;
259-
hash_digest sequences;
260-
hash_digest outputs;
261-
} v0_cache;
272+
static constexpr coverage mask_sighash(uint8_t sighash_flags) NOEXCEPT;
273+
static constexpr bool is_anyone_can_pay(uint8_t sighash_flags) NOEXCEPT;
262274

263-
typedef struct
264-
{
265-
hash_digest amounts;
266-
hash_digest scripts;
267-
hash_digest points;
268-
hash_digest sequences;
269-
hash_digest outputs;
270-
} v1_cache;
275+
// Caching.
276+
// ------------------------------------------------------------------------
271277

272278
// Set sha256 cache if not set, so not thread safe unless cached.
273279
const hash_digest& single_hash_points() const NOEXCEPT;
@@ -293,8 +299,6 @@ class BC_API transaction
293299
// Signature hashing.
294300
// ------------------------------------------------------------------------
295301

296-
static coverage mask_sighash(uint8_t sighash_flags) NOEXCEPT;
297-
static bool is_anyone_can_pay(uint8_t sighash_flags) NOEXCEPT;
298302
static uint32_t subscript_v1(const script& script) NOEXCEPT;
299303
uint8_t spend_type_v1(bool annex, bool tapscript) const NOEXCEPT;
300304
uint32_t input_index(const input_iterator& input) const NOEXCEPT;
@@ -353,6 +357,8 @@ DECLARE_JSON_VALUE_CONVERTORS(transaction::cptr);
353357
} // namespace system
354358
} // namespace libbitcoin
355359

360+
#include <bitcoin/system/impl/chain/transaction_patterns.ipp>
361+
356362
namespace std
357363
{
358364
template<>

include/bitcoin/system/chain/witness.hpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,9 @@ class BC_API witness
103103
/// Patterns.
104104
/// -----------------------------------------------------------------------
105105

106+
/// The stack adheres to the annex pattern [bip341].
107+
static constexpr bool is_annex_pattern(const chunk_cptrs& stack) NOEXCEPT;
108+
106109
/// Verify the push size of each stack element [bip141].
107110
static constexpr bool is_push_size(const chunk_cptrs& stack) NOEXCEPT;
108111

@@ -132,20 +135,17 @@ class BC_API witness
132135
private:
133136
// TODO: move to config serialization wrapper.
134137
static witness from_string(const std::string& mnemonic) NOEXCEPT;
135-
static constexpr bool is_annex_pattern(const chunk_cptrs& stack) NOEXCEPT;
136138
static inline bool drop_annex(chunk_cptrs& stack) NOEXCEPT;
137139

138140
void assign_data(reader& source, bool prefix) NOEXCEPT;
139141

140142
// Witness should be stored as shared.
141143
chunk_cptrs stack_;
142144

143-
// Cache.
145+
// Cache/alias.
144146
bool valid_;
145147
size_t size_;
146-
147-
// Annex member should not even consume space.
148-
chain::annex annex_{ *this };
148+
chain::annex annex_;
149149
};
150150

151151
typedef std_vector<witness> witnesses;

include/bitcoin/system/data/memory.hpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,16 @@ inline std::shared_ptr<const Type> to_shared(Args&&... values) NOEXCEPT
6969
return std::make_shared<const Type>(std::forward<Args>(values)...);
7070
}
7171

72+
/// shared_ptr<non-const>
73+
/// ---------------------------------------------------------------------------
74+
75+
/// Create non-const shared pointer from copied instance.
76+
template <typename Type>
77+
inline std::shared_ptr<Type> make_shared(const Type& value) NOEXCEPT
78+
{
79+
return std::make_shared<Type>(value);
80+
}
81+
7282
/// Obtain non constant pointer from shared_ptr to const.
7383
/// This is useful when allocating objects to shared const before population.
7484
template <typename Type>

include/bitcoin/system/error/script_error_t.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ enum script_error_t : uint8_t
4747
unexpected_witness,
4848
invalid_witness,
4949
invalid_witness_stack,
50+
invalid_commitment,
5051
dirty_witness,
5152
stack_false,
5253

include/bitcoin/system/impl/chain/annex.ipp

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,32 +26,48 @@
2626
namespace libbitcoin {
2727
namespace system {
2828
namespace chain {
29+
inline annex::annex() NOEXCEPT
30+
: data_(nullptr)
31+
{
32+
}
2933

30-
static const data_chunk& empty_annex() NOEXCEPT
34+
// Witness checks is_annex_pattern() and passes data, avoiding excess copying.
35+
inline annex::annex(const chunk_cptr& data) NOEXCEPT
36+
: data_(data)
3137
{
32-
static const data_chunk empty{};
33-
return empty;
3438
}
3539

36-
inline annex::annex(const witness& owner) NOEXCEPT
37-
: witness_(owner)
40+
inline annex::annex(const chunk_cptrs& stack) NOEXCEPT
41+
: data_(from_stack(stack))
42+
{
43+
}
44+
45+
// static/protected
46+
inline chunk_cptr annex::from_stack(const chunk_cptrs& stack) NOEXCEPT
47+
{
48+
return witness::is_annex_pattern(stack) ? stack.back() : nullptr;
49+
}
50+
51+
// static/private
52+
inline const data_chunk& annex::empty_annex() NOEXCEPT
3853
{
54+
static const data_chunk empty{};
55+
return empty;
3956
}
4057

4158
inline annex::operator bool() const NOEXCEPT
4259
{
43-
return witness_.get().is_annex_pattern();
60+
return data_.operator bool();
4461
}
4562

4663
inline size_t annex::size() const NOEXCEPT
4764
{
48-
return data().size();
65+
return data_ ? data_->size() : zero;
4966
}
5067

5168
inline const data_chunk& annex::data() const NOEXCEPT
5269
{
53-
const auto& stack = witness_.get().stack();
54-
return stack.empty() ? empty_annex() : *stack.back();
70+
return data_ ? *data_ : empty_annex();
5571
}
5672

5773
inline const hash_digest annex::hash() const NOEXCEPT

include/bitcoin/system/impl/chain/script_patterns.ipp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,15 @@ constexpr bool script::is_witness_program_pattern(
9999
&& ops[1].data().size() <= max_witness_program;
100100
}
101101

102+
// A witness program used only for policy (not implemented).
103+
constexpr bool script::is_anchor_program_pattern(const operations& ops) NOEXCEPT
104+
{
105+
return is_witness_program_pattern(ops)
106+
&& ops[1].data().size() == 2
107+
&& ops[1].data()[0] == 0x4e
108+
&& ops[1].data()[1] == 0x73;
109+
}
110+
102111
// The satoshi client now enables configurable data size for policy.
103112
constexpr bool script::is_pay_null_data_pattern(const operations& ops) NOEXCEPT
104113
{
@@ -208,8 +217,7 @@ constexpr bool script::is_pay_witness_script_hash_pattern(
208217
}
209218

210219
// The first push is based on wacky satoshi op_check_multisig behavior that
211-
// we must perpetuate, though it's appearance here is policy not consensus.
212-
// Limiting to push_size_0 removes pattern ambiguity with little downside.
220+
// we must perpetuate, though this is not used in consensus validation.
213221
constexpr bool script::is_sign_multisig_pattern(const operations& ops) NOEXCEPT
214222
{
215223
const auto endorsement = [](const operation& op) NOEXCEPT
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
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+
#ifndef LIBBITCOIN_SYSTEM_CHAIN_TRANSACTION_PATTERNS_IPP
20+
#define LIBBITCOIN_SYSTEM_CHAIN_TRANSACTION_PATTERNS_IPP
21+
22+
#include <bitcoin/system/chain/enums/coverage.hpp>
23+
#include <bitcoin/system/define.hpp>
24+
#include <bitcoin/system/math/math.hpp>
25+
26+
namespace libbitcoin {
27+
namespace system {
28+
namespace chain {
29+
30+
//*****************************************************************************
31+
// CONSENSUS: Due to masking of bits 6/7 (8 is the anyone_can_pay flag), there
32+
// possible 7 bit values that can set "single" and 4 others are 4 that can set
33+
// none, and yet all other values set "all".
34+
//*****************************************************************************
35+
constexpr coverage transaction::mask_sighash(uint8_t sighash_flags) NOEXCEPT
36+
{
37+
switch (bit_and<uint8_t>(sighash_flags, coverage::mask))
38+
{
39+
case coverage::hash_single:
40+
return coverage::hash_single;
41+
case coverage::hash_none:
42+
return coverage::hash_none;
43+
default:
44+
return coverage::hash_all;
45+
}
46+
}
47+
48+
constexpr bool transaction::is_anyone_can_pay(uint8_t sighash_flags) NOEXCEPT
49+
{
50+
return get_right(sighash_flags, coverage::anyone_can_pay_bit);
51+
}
52+
53+
} // namespace chain
54+
} // namespace system
55+
} // namespace libbitcoin
56+
57+
#endif

include/bitcoin/system/impl/chain/witness_patterns.ipp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ constexpr bool witness::is_reserved_pattern(const chunk_cptrs& stack) NOEXCEPT
4545
return is_one(stack.size()) && stack.front()->size() == hash_size;
4646
}
4747

48-
// static/private
48+
// static
4949
constexpr bool witness::is_annex_pattern(const chunk_cptrs& stack) NOEXCEPT
5050
{
5151
// If at least two elements, discard annex if present.

0 commit comments

Comments
 (0)