2021-06-17 11:37:04 -07:00
|
|
|
// Copyright (c) 2021 The Zcash Developers
|
|
|
|
// Distributed under the MIT software license, see the accompanying
|
|
|
|
// file COPYING or https://www.opensource.org/licenses/mit-license.php .
|
|
|
|
|
|
|
|
#ifndef ZCASH_PRIMITIVES_ORCHARD_H
|
|
|
|
#define ZCASH_PRIMITIVES_ORCHARD_H
|
|
|
|
|
2021-06-17 11:22:26 -07:00
|
|
|
#include "streams.h"
|
|
|
|
|
|
|
|
#include <amount.h>
|
2021-06-17 11:37:04 -07:00
|
|
|
#include <rust/orchard.h>
|
|
|
|
|
2021-06-17 11:22:26 -07:00
|
|
|
class OrchardMerkleTree;
|
|
|
|
|
2021-06-17 11:37:04 -07:00
|
|
|
/**
|
|
|
|
* The Orchard component of a transaction.
|
|
|
|
*/
|
|
|
|
class OrchardBundle
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
/// An optional Orchard bundle (with `nullptr` corresponding to `None`).
|
|
|
|
/// Memory is allocated by Rust.
|
|
|
|
std::unique_ptr<OrchardBundlePtr, decltype(&orchard_bundle_free)> inner;
|
|
|
|
|
2021-06-17 11:22:26 -07:00
|
|
|
friend class OrchardMerkleTree;
|
2021-06-17 11:37:04 -07:00
|
|
|
public:
|
|
|
|
OrchardBundle() : inner(nullptr, orchard_bundle_free) {}
|
|
|
|
|
|
|
|
OrchardBundle(OrchardBundle&& bundle) : inner(std::move(bundle.inner)) {}
|
2021-06-17 11:22:26 -07:00
|
|
|
|
2021-06-17 11:37:04 -07:00
|
|
|
OrchardBundle(const OrchardBundle& bundle) :
|
|
|
|
inner(orchard_bundle_clone(bundle.inner.get()), orchard_bundle_free) {}
|
2021-06-17 11:22:26 -07:00
|
|
|
|
2021-06-17 11:37:04 -07:00
|
|
|
OrchardBundle& operator=(OrchardBundle&& bundle)
|
|
|
|
{
|
|
|
|
if (this != &bundle) {
|
|
|
|
inner = std::move(bundle.inner);
|
|
|
|
}
|
|
|
|
return *this;
|
|
|
|
}
|
2021-06-17 11:22:26 -07:00
|
|
|
|
2021-06-17 11:37:04 -07:00
|
|
|
OrchardBundle& operator=(const OrchardBundle& bundle)
|
|
|
|
{
|
|
|
|
if (this != &bundle) {
|
|
|
|
inner.reset(orchard_bundle_clone(bundle.inner.get()));
|
|
|
|
}
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename Stream>
|
|
|
|
void Serialize(Stream& s) const {
|
|
|
|
RustStream rs(s);
|
|
|
|
if (!orchard_bundle_serialize(inner.get(), &rs, RustStream<Stream>::write_callback)) {
|
|
|
|
throw std::ios_base::failure("Failed to serialize v5 Orchard bundle");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename Stream>
|
|
|
|
void Unserialize(Stream& s) {
|
|
|
|
RustStream rs(s);
|
|
|
|
OrchardBundlePtr* bundle;
|
|
|
|
if (!orchard_bundle_parse(&rs, RustStream<Stream>::read_callback, &bundle)) {
|
|
|
|
throw std::ios_base::failure("Failed to parse v5 Orchard bundle");
|
|
|
|
}
|
|
|
|
inner.reset(bundle);
|
|
|
|
}
|
|
|
|
|
2021-06-17 05:05:58 -07:00
|
|
|
/// Returns true if this contains an Orchard bundle, or false if there is no
|
|
|
|
/// Orchard component.
|
|
|
|
bool IsPresent() const { return (bool)inner; }
|
|
|
|
|
2021-06-15 03:45:24 -07:00
|
|
|
/// Returns the net value entering or exiting the Orchard pool as a result of this
|
|
|
|
/// bundle.
|
|
|
|
CAmount GetValueBalance() const {
|
|
|
|
return orchard_bundle_value_balance(inner.get());
|
|
|
|
}
|
|
|
|
|
2021-06-21 05:36:44 -07:00
|
|
|
/// Returns true if this Orchard bundle satisfies the bundle-specific consensus rules,
|
|
|
|
/// or if this does not contain an Orchard bundle.
|
|
|
|
///
|
|
|
|
/// This does not validate the bundle's signatures; use `QueueSignatureValidation` for
|
|
|
|
/// those checks.
|
|
|
|
bool CheckBundleSpecificConsensusRules() const {
|
|
|
|
return orchard_bundle_validate(inner.get());
|
|
|
|
}
|
|
|
|
|
2021-06-17 11:37:04 -07:00
|
|
|
/// Queues this bundle's signatures for validation.
|
|
|
|
///
|
|
|
|
/// `txid` must be for the transaction this bundle is within.
|
|
|
|
void QueueSignatureValidation(
|
|
|
|
orchard::AuthValidator& batch, const uint256& txid) const
|
|
|
|
{
|
|
|
|
batch.Queue(inner.get(), txid.begin());
|
|
|
|
}
|
2021-06-17 11:22:26 -07:00
|
|
|
|
2021-06-29 12:52:45 -07:00
|
|
|
const size_t GetNumActions() const {
|
|
|
|
return orchard_bundle_actions_len(inner.get());
|
|
|
|
}
|
|
|
|
|
2021-06-17 11:22:26 -07:00
|
|
|
const std::vector<uint256> GetNullifiers() const {
|
|
|
|
size_t actions_len = orchard_bundle_actions_len(inner.get());
|
|
|
|
std::vector<uint256> result(actions_len);
|
2021-06-30 13:50:02 -07:00
|
|
|
auto nullifiers_ok = orchard_bundle_nullifiers(inner.get(), result.data(), actions_len);
|
|
|
|
assert(nullifiers_ok);
|
2021-06-17 11:22:26 -07:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2021-06-22 06:34:13 -07:00
|
|
|
const std::optional<uint256> GetAnchor() const {
|
2021-06-17 11:22:26 -07:00
|
|
|
uint256 result;
|
|
|
|
if (orchard_bundle_anchor(inner.get(), result.begin())) {
|
|
|
|
return result;
|
|
|
|
} else {
|
2021-06-22 06:34:13 -07:00
|
|
|
return std::nullopt;
|
2021-06-17 11:22:26 -07:00
|
|
|
}
|
|
|
|
}
|
2021-06-25 05:32:59 -07:00
|
|
|
|
|
|
|
bool OutputsEnabled() const {
|
|
|
|
return orchard_bundle_outputs_enabled(inner.get());
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SpendsEnabled() const {
|
|
|
|
return orchard_bundle_spends_enabled(inner.get());
|
|
|
|
}
|
2021-06-17 11:37:04 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
#endif // ZCASH_PRIMITIVES_ORCHARD_H
|
|
|
|
|