Skip to content

Commit 14d1e65

Browse files
authored
Merge pull request #1698 from evoskuil/master
Fix v1 sighash annex serialization.
2 parents dc29f85 + 3032cab commit 14d1e65

File tree

4 files changed

+31
-27
lines changed

4 files changed

+31
-27
lines changed

include/bitcoin/system/chain/annex.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ class BC_API annex
3939

4040
inline size_t size() const NOEXCEPT;
4141
inline const data_chunk& data() const NOEXCEPT;
42-
inline const hash_digest hash() const NOEXCEPT;
42+
inline const hash_digest hash(bool prefix) const NOEXCEPT;
4343
inline operator bool() const NOEXCEPT;
4444

4545
/// The stack adheres to the annex pattern [bip341].

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

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <bitcoin/system/data/data.hpp>
2424
#include <bitcoin/system/define.hpp>
2525
#include <bitcoin/system/hash/hash.hpp>
26+
#include <bitcoin/system/stream/stream.hpp>
2627

2728
namespace libbitcoin {
2829
namespace system {
@@ -72,9 +73,18 @@ inline const data_chunk& annex::data() const NOEXCEPT
7273
return data_ ? *data_ : empty_annex();
7374
}
7475

75-
inline const hash_digest annex::hash() const NOEXCEPT
76+
inline const hash_digest annex::hash(bool prefix) const NOEXCEPT
7677
{
77-
return sha256_hash(data());
78+
if (!prefix)
79+
return sha256_hash(data());
80+
81+
hash_digest out{};
82+
stream::out::fast stream{ out };
83+
hash::sha256::fast sink{ stream };
84+
sink.write_variable(size());
85+
sink.write_bytes(data());
86+
sink.flush();
87+
return out;
7888
}
7989

8090
// static

src/chain/transaction_sighash_v0.cpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,6 @@ bool transaction::version0_sighash(hash_digest& out,
7272
stream::out::fast stream{ out };
7373
hash::sha256x2::fast sink{ stream };
7474

75-
///////////////////////////////////////////////////////////////////////////
76-
// TODO: update cache calls.
77-
///////////////////////////////////////////////////////////////////////////
78-
7975
sink.write_4_bytes_little_endian(version_);
8076
sink.write_bytes(!anyone ? double_hash_points() : null_hash);
8177
sink.write_bytes(!anyone && all ? double_hash_sequences() : null_hash);

src/chain/transaction_sighash_v1.cpp

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,15 @@ uint32_t transaction::subscript_v1(const script& script) NOEXCEPT
5757
// ext_flags and annex flag are combined into one byte, who knows why.
5858
uint8_t transaction::spend_type_v1(bool annex, bool tapscript) const NOEXCEPT
5959
{
60-
const auto ext_flags = to_value(tapscript ?
61-
extension::tapscript : extension::taproot);
60+
const auto ext_flag = to_value(tapscript ? extension::tapscript :
61+
extension::taproot);
6262

63-
return set_right(shift_left(ext_flags), zero, annex);
63+
return set_right(shift_left(ext_flag), zero, annex);
6464
}
6565

6666
// NOT THREAD SAFE
6767
// Concurrent input validation for a tx unsafe due to on-demand hash caching.
68+
// TODO: may be more optimal to not cache single output hash as use is rare.
6869
bool transaction::version1_sighash(hash_digest& out,
6970
const input_iterator& input, const script& script, uint64_t value,
7071
const hash_cptr& tapleaf, uint8_t sighash_flags) const NOEXCEPT
@@ -80,6 +81,18 @@ bool transaction::version1_sighash(hash_digest& out,
8081
const auto single = (flag == coverage::hash_single);
8182
const auto all = (flag == coverage::hash_all);
8283

84+
// ************************************************************************
85+
// CONSENSUS: Guards public interface only, node always populates prevout.
86+
// ************************************************************************
87+
if (anyone && is_null(in.prevout))
88+
return false;
89+
90+
// ************************************************************************
91+
// CONSENSUS: Taproot finally eliminates one_hash (null_hash in v0) return.
92+
// ************************************************************************
93+
if (single && output_overflow(input_index(input)))
94+
return false;
95+
8396
// Create tagged hash writer.
8497
stream::out::fast stream{ out };
8598
hash::sha256t::fast<"TapSighash"> sink{ stream };
@@ -106,10 +119,6 @@ bool transaction::version1_sighash(hash_digest& out,
106119

107120
if (anyone)
108121
{
109-
// This implies a parameterization error, and will fail the script.
110-
if (is_null(in.prevout))
111-
return false;
112-
113122
in.point().to_data(sink);
114123
sink.write_8_bytes_little_endian(value);
115124
in.prevout->script().to_data(sink, true);
@@ -122,19 +131,13 @@ bool transaction::version1_sighash(hash_digest& out,
122131

123132
if (annex)
124133
{
125-
sink.write_variable(annex.size());
126-
sink.write_bytes(annex.hash());
134+
sink.write_bytes(annex.hash(true));
127135
}
128136

129137
if (single)
130138
{
131-
const auto index = input_index(input);
132-
if (output_overflow(index))
133-
return false;
134-
135139
// Hash is cached for use with each single sigop in the same script.
136-
// TODO: it may be more optimal to not cache, since benefit is rare.
137-
sink.write_bytes(outputs_->at(index)->get_hash());
140+
sink.write_bytes(outputs_->at(input_index(input))->get_hash());
138141
}
139142

140143
// Additional for tapscript [bip342].
@@ -146,11 +149,6 @@ bool transaction::version1_sighash(hash_digest& out,
146149
sink.write_4_bytes_little_endian(subscript_v1(script));
147150
}
148151

149-
// TODO: write position pertains to the hash instance (written at flush).
150-
// Total length at most 206 bytes (!anyone, no epoch/tapscript) [bip341].
151-
////BC_ASSERT(!anyone && sink.get_write_position() == (add1(206u) + 37));
152-
////BC_ASSERT( anyone && sink.get_write_position() == (add1(157u) + 37));
153-
154152
sink.flush();
155153
return true;
156154
}

0 commit comments

Comments
 (0)