Skip to content

Commit

Permalink
Merge pull request #1518 from evoskuil/master
Browse files Browse the repository at this point in the history
Use std::optional for cache, and default tx copy/assign.
  • Loading branch information
evoskuil authored Aug 14, 2024
2 parents d55a8e7 + ffd7d56 commit 773c958
Show file tree
Hide file tree
Showing 9 changed files with 29 additions and 90 deletions.
5 changes: 3 additions & 2 deletions include/bitcoin/system/chain/header.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

#include <istream>
#include <memory>
#include <optional>
#include <vector>
#include <bitcoin/system/chain/chain_state.hpp>
#include <bitcoin/system/data/data.hpp>
Expand Down Expand Up @@ -103,7 +104,7 @@ class BC_API header
uint256_t proof() const NOEXCEPT;

/// Cache (this overrides hash() computation).
void set_hash(hash_digest&& hash) const NOEXCEPT;
void set_hash(const hash_digest& hash) const NOEXCEPT;

/// Reference used to avoid copy, sets cache if not set (not thread safe).
const hash_digest& get_hash() const NOEXCEPT;
Expand Down Expand Up @@ -152,7 +153,7 @@ class BC_API header
bool valid_;

// Identity hash caching.
mutable std::shared_ptr<const hash_digest> hash_{};
mutable std::optional<hash_digest> hash_{};
};

typedef std_vector<header> headers;
Expand Down
1 change: 1 addition & 0 deletions include/bitcoin/system/chain/input.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ class BC_API input
sizes size_;

public:
/// TODO: prevout destruct requires input destruct.
/// Public mutable metadata access, copied but not compared for equality.
mutable chain::output::cptr prevout{};
mutable chain::prevout metadata{ zero, max_uint32, false, false };
Expand Down
23 changes: 9 additions & 14 deletions include/bitcoin/system/chain/transaction.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

#include <istream>
#include <memory>
#include <optional>
#include <vector>
#include <bitcoin/system/chain/context.hpp>
#include <bitcoin/system/chain/input.hpp>
Expand All @@ -38,6 +39,9 @@ namespace chain {
class BC_API transaction
{
public:
/// Cache is copied/moved on copy/assign.
DEFAULT_COPY_MOVE_DESTRUCT(transaction);

typedef std::shared_ptr<const transaction> cptr;
typedef input_cptrs::const_iterator input_iterator;

Expand All @@ -49,11 +53,6 @@ class BC_API transaction

/// Default transaction is an invalid object.
transaction() NOEXCEPT;
virtual ~transaction() NOEXCEPT;

/// Cache is defaulted on copy/assign.
transaction(transaction&& other) NOEXCEPT;
transaction(const transaction& other) NOEXCEPT;

transaction(uint32_t version, chain::inputs&& inputs,
chain::outputs&& outputs, uint32_t locktime) NOEXCEPT;
Expand All @@ -73,10 +72,6 @@ class BC_API transaction
/// Operators.
/// -----------------------------------------------------------------------

/// Cache is defaulted on copy/assign.
transaction& operator=(transaction&& other) NOEXCEPT;
transaction& operator=(const transaction& other) NOEXCEPT;

bool operator==(const transaction& other) const NOEXCEPT;
bool operator!=(const transaction& other) const NOEXCEPT;

Expand Down Expand Up @@ -113,11 +108,11 @@ class BC_API transaction
/// -----------------------------------------------------------------------

/// Initialize with externally-produced nominal hash value, as from store.
void set_nominal_hash(hash_digest&& hash) const NOEXCEPT;
void set_nominal_hash(const hash_digest& hash) const NOEXCEPT;

/// Initialize with externally-produced witness hash value, as from store.
/// This need not be set if the transaction is not segmented.
void set_witness_hash(hash_digest&& hash) const NOEXCEPT;
void set_witness_hash(const hash_digest& hash) const NOEXCEPT;

/// Reference used to avoid copy, sets cache if not set (not thread safe).
const hash_digest& get_hash(bool witness) const NOEXCEPT;
Expand Down Expand Up @@ -275,9 +270,9 @@ class BC_API transaction
sizes size_;

// Signature and identity hash caching (witness hash if witnessed).
mutable std::unique_ptr<const hash_digest> nominal_hash_{};
mutable std::unique_ptr<const hash_digest> witness_hash_{};
mutable std::unique_ptr<const sighash_cache> sighash_cache_{};
mutable std::optional<hash_digest> nominal_hash_{};
mutable std::optional<hash_digest> witness_hash_{};
mutable std::optional<sighash_cache> sighash_cache_{};
};

typedef std_vector<transaction> transactions;
Expand Down
1 change: 1 addition & 0 deletions include/bitcoin/system/data/memory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ inline std::unique_ptr<const Type> to_unique(const Type& value) NOEXCEPT
template <typename Type, typename ...Args>
inline std::unique_ptr<const Type> to_unique(Args&&... values) NOEXCEPT
{
// Type{} required due to CLang bug.
return std::make_unique<const Type>(Type{ std::forward<Args>(values)... });
}

Expand Down
3 changes: 1 addition & 2 deletions include/bitcoin/system/impl/stream/streamers/byte_reader.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -615,8 +615,7 @@ byte_reader<IStream>::get_arena() const NOEXCEPT
}

template <typename IStream>
typename byte_reader<IStream>::memory_allocator&
byte_reader<IStream>::get_allocator() const NOEXCEPT
byte_allocator& byte_reader<IStream>::get_allocator() const NOEXCEPT
{
return allocator_;
}
Expand Down
4 changes: 2 additions & 2 deletions include/bitcoin/system/stream/streamers/byte_reader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ class byte_reader
memory_arena get_arena() const NOEXCEPT override;

/// Memory allocator used to construct objects.
memory_allocator& get_allocator() const NOEXCEPT override;
byte_allocator& get_allocator() const NOEXCEPT override;

/// The stream is valid.
operator bool() const NOEXCEPT override;
Expand Down Expand Up @@ -219,7 +219,7 @@ class byte_reader

IStream& stream_;
size_t remaining_;
mutable memory_allocator allocator_;
mutable byte_allocator allocator_;
};

} // namespace system
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ class bytereader
{
public:
using memory_arena = arena*;
using memory_allocator = allocator<uint8_t>;

/// Integrals.
/// -----------------------------------------------------------------------
Expand Down Expand Up @@ -152,7 +151,7 @@ class bytereader
virtual memory_arena get_arena() const NOEXCEPT = 0;

/// Memory allocator used to construct objects.
virtual memory_allocator& get_allocator() const NOEXCEPT = 0;
virtual byte_allocator& get_allocator() const NOEXCEPT = 0;

/// The stream is valid.
virtual operator bool() const NOEXCEPT = 0;
Expand Down
4 changes: 2 additions & 2 deletions src/chain/header.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -228,9 +228,9 @@ uint32_t header::nonce() const NOEXCEPT
return nonce_;
}

void header::set_hash(hash_digest&& hash) const NOEXCEPT
void header::set_hash(const hash_digest& hash) const NOEXCEPT
{
hash_ = to_shared(std::move(hash));
hash_ = hash;
}

// computed
Expand Down
75 changes: 9 additions & 66 deletions src/chain/transaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,33 +79,6 @@ transaction::transaction() NOEXCEPT
{
}

transaction::~transaction() NOEXCEPT
{
}

transaction::transaction(transaction&& other) NOEXCEPT
: transaction(other)
{
}

transaction::transaction(const transaction& other) NOEXCEPT
: transaction(
other.version_,
other.inputs_,
other.outputs_,
other.locktime_,
other.segregated_,
other.valid_)
{
// Optimized for faster optional, not for copy.
if (other.nominal_hash_)
nominal_hash_ = to_unique(*other.nominal_hash_);
if (other.witness_hash_)
witness_hash_ = to_unique(*other.witness_hash_);
if (other.sighash_cache_)
sighash_cache_ = to_unique(*other.sighash_cache_);
}

transaction::transaction(uint32_t version, chain::inputs&& inputs,
chain::outputs&& outputs, uint32_t locktime) NOEXCEPT
: transaction(version, to_shareds(std::move(inputs)),
Expand Down Expand Up @@ -183,37 +156,6 @@ transaction::transaction(uint32_t version,
// Operators.
// ----------------------------------------------------------------------------

transaction& transaction::operator=(transaction&& other) NOEXCEPT
{
*this = other;
return *this;
}

transaction& transaction::operator=(const transaction& other) NOEXCEPT
{
version_ = other.version_;
inputs_ = other.inputs_;
outputs_ = other.outputs_;
locktime_ = other.locktime_;
segregated_ = other.segregated_;
valid_ = other.valid_;
size_ = other.size_;

nominal_hash_.reset();
witness_hash_.reset();
sighash_cache_.reset();

// Optimized for faster optional, not for copy.
if (other.nominal_hash_)
nominal_hash_ = to_unique(*other.nominal_hash_);
if (other.witness_hash_)
witness_hash_ = to_unique(*other.witness_hash_);
if (other.sighash_cache_)
sighash_cache_ = to_unique(*other.sighash_cache_);

return *this;
}

bool transaction::operator==(const transaction& other) const NOEXCEPT
{
// Compares input/output elements, not pointers, cache not compared.
Expand Down Expand Up @@ -452,14 +394,14 @@ uint64_t transaction::fee() const NOEXCEPT
return floored_subtract(value(), claim());
}

void transaction::set_nominal_hash(hash_digest&& hash) const NOEXCEPT
void transaction::set_nominal_hash(const hash_digest& hash) const NOEXCEPT
{
nominal_hash_ = to_unique(std::move(hash));
nominal_hash_ = hash;
}

void transaction::set_witness_hash(hash_digest&& hash) const NOEXCEPT
void transaction::set_witness_hash(const hash_digest& hash) const NOEXCEPT
{
witness_hash_ = to_unique(std::move(hash));
witness_hash_ = hash;
}

const hash_digest& transaction::get_hash(bool witness) const NOEXCEPT
Expand Down Expand Up @@ -844,16 +786,17 @@ hash_digest transaction::unversioned_signature_hash(
// TODO: taproot requires both single and double hash of each.
void transaction::initialize_sighash_cache() const NOEXCEPT
{
// This overconstructs the cache (anyone or !all), however it is simple.
// C++23: std::optional<T>::or_else.
if (!segregated_)
return;

sighash_cache_ = to_unique<sighash_cache>
(
// This overconstructs the cache (anyone or !all), however it is simple.
sighash_cache_ =
{
outputs_hash(),
points_hash(),
sequences_hash()
);
};
}

// private
Expand Down

0 comments on commit 773c958

Please sign in to comment.