transaction_identifier.h
1 // Copyright (c) 2023-present The Bitcoin Core developers 2 // Distributed under the MIT software license, see the accompanying 3 // file COPYING or https://opensource.org/license/mit. 4 5 #ifndef BITCOIN_PRIMITIVES_TRANSACTION_IDENTIFIER_H 6 #define BITCOIN_PRIMITIVES_TRANSACTION_IDENTIFIER_H 7 8 #include <attributes.h> 9 #include <uint256.h> 10 #include <util/types.h> 11 12 #include <compare> 13 #include <cstddef> 14 #include <optional> 15 #include <string> 16 #include <string_view> 17 #include <tuple> 18 #include <type_traits> 19 #include <variant> 20 21 /** transaction_identifier represents the two canonical transaction identifier 22 * types (txid, wtxid).*/ 23 template <bool has_witness> 24 class transaction_identifier 25 { 26 uint256 m_wrapped; 27 28 // Note: Use FromUint256 externally instead. 29 transaction_identifier(const uint256& wrapped) : m_wrapped{wrapped} {} 30 31 constexpr int Compare(const transaction_identifier<has_witness>& other) const { return m_wrapped.Compare(other.m_wrapped); } 32 template <typename Other> 33 constexpr int Compare(const Other& other) const 34 { 35 static_assert(ALWAYS_FALSE<Other>, "Forbidden comparison type"); 36 return 0; 37 } 38 39 public: 40 transaction_identifier() : m_wrapped{} {} 41 consteval explicit transaction_identifier(std::string_view hex_str) : m_wrapped{uint256{hex_str}} {} 42 43 template <typename Other> 44 bool operator==(const Other& other) const { return Compare(other) == 0; } 45 template <typename Other> 46 std::strong_ordering operator<=>(const Other& other) const { return Compare(other) <=> 0; } 47 48 const uint256& ToUint256() const LIFETIMEBOUND { return m_wrapped; } 49 static transaction_identifier FromUint256(const uint256& id) { return {id}; } 50 51 /** Wrapped `uint256` methods. */ 52 constexpr bool IsNull() const { return m_wrapped.IsNull(); } 53 constexpr void SetNull() { m_wrapped.SetNull(); } 54 static std::optional<transaction_identifier> FromHex(std::string_view hex) 55 { 56 auto u{uint256::FromHex(hex)}; 57 if (!u) return std::nullopt; 58 return FromUint256(*u); 59 } 60 std::string GetHex() const { return m_wrapped.GetHex(); } 61 std::string ToString() const { return m_wrapped.ToString(); } 62 static constexpr auto size() { return decltype(m_wrapped)::size(); } 63 constexpr const std::byte* data() const { return reinterpret_cast<const std::byte*>(m_wrapped.data()); } 64 constexpr const std::byte* begin() const { return reinterpret_cast<const std::byte*>(m_wrapped.begin()); } 65 constexpr const std::byte* end() const { return reinterpret_cast<const std::byte*>(m_wrapped.end()); } 66 template <typename Stream> void Serialize(Stream& s) const { m_wrapped.Serialize(s); } 67 template <typename Stream> void Unserialize(Stream& s) { m_wrapped.Unserialize(s); } 68 }; 69 70 /** Txid commits to all transaction fields except the witness. */ 71 using Txid = transaction_identifier<false>; 72 /** Wtxid commits to all transaction fields including the witness. */ 73 using Wtxid = transaction_identifier<true>; 74 75 template <typename T> 76 concept TxidOrWtxid = std::is_same_v<T, Txid> || std::is_same_v<T, Wtxid>; 77 78 class GenTxid : public std::variant<Txid, Wtxid> 79 { 80 public: 81 using variant::variant; 82 83 bool IsWtxid() const { return std::holds_alternative<Wtxid>(*this); } 84 85 const uint256& ToUint256() const LIFETIMEBOUND 86 { 87 return std::visit([](const auto& id) -> const uint256& { return id.ToUint256(); }, *this); 88 } 89 90 friend auto operator<=>(const GenTxid& a, const GenTxid& b) 91 { 92 // Use a reference for read-only access to the hash, avoiding a copy that might not be optimized away. 93 return std::tuple<bool, const uint256&>(a.IsWtxid(), a.ToUint256()) <=> std::tuple<bool, const uint256&>(b.IsWtxid(), b.ToUint256()); 94 } 95 }; 96 97 #endif // BITCOIN_PRIMITIVES_TRANSACTION_IDENTIFIER_H