rust: Migrate `OrchardMerkleFrontier` to `cxx`
Closes zcash/zcash#6333.
This commit is contained in:
parent
908675b5b9
commit
817276c02f
|
@ -54,6 +54,7 @@ CXXBRIDGE_RS = \
|
|||
rust/src/blake2b.rs \
|
||||
rust/src/bundlecache.rs \
|
||||
rust/src/equihash.rs \
|
||||
rust/src/merkle_frontier.rs \
|
||||
rust/src/orchard_bundle.rs \
|
||||
rust/src/sapling.rs \
|
||||
rust/src/streams.rs \
|
||||
|
@ -62,6 +63,7 @@ CXXBRIDGE_H = \
|
|||
rust/gen/include/rust/blake2b.h \
|
||||
rust/gen/include/rust/bundlecache.h \
|
||||
rust/gen/include/rust/equihash.h \
|
||||
rust/gen/include/rust/merkle_frontier.h \
|
||||
rust/gen/include/rust/orchard_bundle.h \
|
||||
rust/gen/include/rust/sapling.h \
|
||||
rust/gen/include/rust/streams.h \
|
||||
|
@ -70,6 +72,7 @@ CXXBRIDGE_CPP = \
|
|||
rust/gen/src/blake2b.cpp \
|
||||
rust/gen/src/bundlecache.cpp \
|
||||
rust/gen/src/equihash.cpp \
|
||||
rust/gen/src/merkle_frontier.cpp \
|
||||
rust/gen/src/orchard_bundle.cpp \
|
||||
rust/gen/src/sapling.cpp \
|
||||
rust/gen/src/streams.cpp \
|
||||
|
|
|
@ -1,96 +0,0 @@
|
|||
// Copyright (c) 2021-2022 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_RUST_INCLUDE_RUST_ORCHARD_INCREMENTAL_MERKLE_TREE_H
|
||||
#define ZCASH_RUST_INCLUDE_RUST_ORCHARD_INCREMENTAL_MERKLE_TREE_H
|
||||
|
||||
#include "rust/streams.h"
|
||||
#include "rust/orchard.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define SINSEMILLA_DIGEST_LEN 32U
|
||||
|
||||
/// Pointer to an Orchard incremental merkle tree frontier
|
||||
struct OrchardMerkleFrontierPtr;
|
||||
typedef struct OrchardMerkleFrontierPtr OrchardMerkleFrontierPtr;
|
||||
|
||||
// Create an empty Orchard Merkle frontier.
|
||||
//
|
||||
// Memory allocated to the resulting value must be manually freed.
|
||||
OrchardMerkleFrontierPtr* orchard_merkle_frontier_empty();
|
||||
|
||||
// Clones the given Orchard Merkle frontier and returns
|
||||
// a pointer to the newly created tree. Both the original
|
||||
// tree's memory and the newly allocated one need to be freed
|
||||
// independently.
|
||||
OrchardMerkleFrontierPtr* orchard_merkle_frontier_clone(
|
||||
const OrchardMerkleFrontierPtr* tree_ptr);
|
||||
|
||||
// Free the memory allocated for the given Orchard Merkle frontier.
|
||||
void orchard_merkle_frontier_free(
|
||||
OrchardMerkleFrontierPtr* tree_ptr);
|
||||
|
||||
// Parses an Orchard Merkle frontier from a stream. If parsing
|
||||
// fails, this will return the null pointer.
|
||||
//
|
||||
// Memory allocated to the resulting value must be manually freed.
|
||||
OrchardMerkleFrontierPtr* orchard_merkle_frontier_parse(
|
||||
void* stream,
|
||||
read_callback_t read_cb);
|
||||
|
||||
// Serializes an Orchard Merkle frontier to a stream.
|
||||
//
|
||||
// Returns `false` if an error occurs while writing to the stream.
|
||||
bool orchard_merkle_frontier_serialize(
|
||||
const OrchardMerkleFrontierPtr* tree_ptr,
|
||||
void* stream,
|
||||
write_callback_t write_cb);
|
||||
|
||||
// Serializes an Orchard Merkle frontier to a stream using the
|
||||
// zcash_primitives::merkle_tree::CommitmentTree sparse encoding.
|
||||
//
|
||||
// Returns `false` if an error occurs while writing to the stream.
|
||||
bool orchard_merkle_frontier_serialize_legacy(
|
||||
const OrchardMerkleFrontierPtr* tree_ptr,
|
||||
void* stream,
|
||||
write_callback_t write_cb);
|
||||
|
||||
// For each action in the provided bundle, append its
|
||||
// commitment to the frontier.
|
||||
//
|
||||
// Returns `true` if the append succeeds, `false` if the
|
||||
// tree is full.
|
||||
bool orchard_merkle_frontier_append_bundle(
|
||||
OrchardMerkleFrontierPtr* tree_ptr,
|
||||
const OrchardBundlePtr* bundle);
|
||||
|
||||
// Computes the root of the provided orchard Merkle frontier
|
||||
void orchard_merkle_frontier_root(
|
||||
const OrchardMerkleFrontierPtr* tree_ptr,
|
||||
unsigned char* digest_ret);
|
||||
|
||||
// The total number of leaves that have been appended to obtain
|
||||
// the current state of the frontier. Subtract 1 from this value
|
||||
// to obtain the position of the most recently appended leaf.
|
||||
uint64_t orchard_merkle_frontier_num_leaves(
|
||||
const OrchardMerkleFrontierPtr* tree_ptr);
|
||||
|
||||
// Estimate the amount of memory consumed by the merkle frontier.
|
||||
size_t orchard_merkle_frontier_dynamic_mem_usage(
|
||||
const OrchardMerkleFrontierPtr* tree_ptr);
|
||||
|
||||
// Computes the empty leaf value for the incremental Merkle tree.
|
||||
void orchard_merkle_tree_empty_root(
|
||||
unsigned char* digest_ret);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // ZCASH_RUST_INCLUDE_RUST_ORCHARD_INCREMENTAL_MERKLE_TREE_H
|
|
@ -5,7 +5,6 @@
|
|||
#ifndef ZCASH_RUST_INCLUDE_RUST_ORCHARD_WALLET_H
|
||||
#define ZCASH_RUST_INCLUDE_RUST_ORCHARD_WALLET_H
|
||||
|
||||
#include "rust/orchard/incremental_merkle_tree.h"
|
||||
#include "rust/orchard/keys.h"
|
||||
#include "rust/builder.h"
|
||||
|
||||
|
@ -19,6 +18,10 @@ extern "C" {
|
|||
struct OrchardWalletPtr;
|
||||
typedef struct OrchardWalletPtr OrchardWalletPtr;
|
||||
|
||||
/// Pointer to an Orchard incremental merkle tree frontier
|
||||
struct OrchardMerkleFrontierPtr;
|
||||
typedef struct OrchardMerkleFrontierPtr OrchardMerkleFrontierPtr;
|
||||
|
||||
/**
|
||||
* Constructs a new empty Orchard wallet and return a pointer to it.
|
||||
* Memory is allocated by Rust and must be manually freed using
|
||||
|
|
|
@ -1,186 +0,0 @@
|
|||
use incrementalmerkletree::{bridgetree, Altitude, Frontier, Hashable};
|
||||
use std::mem::size_of_val;
|
||||
use std::ptr;
|
||||
|
||||
use orchard::{bundle::Authorized, tree::MerkleHashOrchard};
|
||||
use tracing::error;
|
||||
use zcash_primitives::{
|
||||
merkle_tree::{
|
||||
incremental::{read_frontier_v1, write_frontier_v1},
|
||||
CommitmentTree,
|
||||
},
|
||||
transaction::components::Amount,
|
||||
};
|
||||
|
||||
use crate::streams_ffi::{CppStreamReader, CppStreamWriter, ReadCb, StreamObj, WriteCb};
|
||||
|
||||
pub const MERKLE_DEPTH: u8 = 32;
|
||||
|
||||
//
|
||||
// Operations on Merkle frontiers.
|
||||
//
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn orchard_merkle_frontier_empty(
|
||||
) -> *mut bridgetree::Frontier<MerkleHashOrchard, MERKLE_DEPTH> {
|
||||
let empty_tree = bridgetree::Frontier::<MerkleHashOrchard, MERKLE_DEPTH>::empty();
|
||||
Box::into_raw(Box::new(empty_tree))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn orchard_merkle_frontier_clone(
|
||||
tree: *const bridgetree::Frontier<MerkleHashOrchard, MERKLE_DEPTH>,
|
||||
) -> *mut bridgetree::Frontier<MerkleHashOrchard, MERKLE_DEPTH> {
|
||||
unsafe { tree.as_ref() }
|
||||
.map(|tree| Box::into_raw(Box::new(tree.clone())))
|
||||
.unwrap_or(std::ptr::null_mut())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn orchard_merkle_frontier_free(
|
||||
tree: *mut bridgetree::Frontier<MerkleHashOrchard, MERKLE_DEPTH>,
|
||||
) {
|
||||
if !tree.is_null() {
|
||||
drop(unsafe { Box::from_raw(tree) });
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn orchard_merkle_frontier_parse(
|
||||
stream: Option<StreamObj>,
|
||||
read_cb: Option<ReadCb>,
|
||||
) -> *mut bridgetree::Frontier<MerkleHashOrchard, MERKLE_DEPTH> {
|
||||
let reader = CppStreamReader::from_raw_parts(stream, read_cb.unwrap());
|
||||
|
||||
match read_frontier_v1(reader) {
|
||||
Ok(parsed) => Box::into_raw(Box::new(parsed)),
|
||||
Err(e) => {
|
||||
error!("Failed to parse Orchard bundle: {}", e);
|
||||
ptr::null_mut()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn orchard_merkle_frontier_serialize(
|
||||
frontier: *const bridgetree::Frontier<MerkleHashOrchard, MERKLE_DEPTH>,
|
||||
stream: Option<StreamObj>,
|
||||
write_cb: Option<WriteCb>,
|
||||
) -> bool {
|
||||
let frontier = unsafe {
|
||||
frontier
|
||||
.as_ref()
|
||||
.expect("Orchard note commitment tree pointer may not be null.")
|
||||
};
|
||||
|
||||
let writer = CppStreamWriter::from_raw_parts(stream, write_cb.unwrap());
|
||||
match write_frontier_v1(writer, frontier) {
|
||||
Ok(()) => true,
|
||||
Err(e) => {
|
||||
error!("{}", e);
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn orchard_merkle_frontier_serialize_legacy(
|
||||
frontier: *const bridgetree::Frontier<MerkleHashOrchard, MERKLE_DEPTH>,
|
||||
stream: Option<StreamObj>,
|
||||
write_cb: Option<WriteCb>,
|
||||
) -> bool {
|
||||
let frontier = unsafe {
|
||||
frontier
|
||||
.as_ref()
|
||||
.expect("Orchard note commitment tree pointer may not be null.")
|
||||
};
|
||||
|
||||
let writer = CppStreamWriter::from_raw_parts(stream, write_cb.unwrap());
|
||||
let commitment_tree = CommitmentTree::from_frontier(frontier);
|
||||
match commitment_tree.write(writer) {
|
||||
Ok(()) => true,
|
||||
Err(e) => {
|
||||
error!("{}", e);
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn orchard_merkle_frontier_append_bundle(
|
||||
tree: *mut bridgetree::Frontier<MerkleHashOrchard, MERKLE_DEPTH>,
|
||||
bundle: *const orchard::Bundle<Authorized, Amount>,
|
||||
) -> bool {
|
||||
let tree = unsafe {
|
||||
tree.as_mut()
|
||||
.expect("Orchard note commitment tree pointer may not be null.")
|
||||
};
|
||||
if let Some(bundle) = unsafe { bundle.as_ref() } {
|
||||
for action in bundle.actions().iter() {
|
||||
if !tree.append(&MerkleHashOrchard::from_cmx(action.cmx())) {
|
||||
error!("Orchard note commitment tree is full.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn orchard_merkle_frontier_root(
|
||||
tree: *const bridgetree::Frontier<MerkleHashOrchard, MERKLE_DEPTH>,
|
||||
root_ret: *mut [u8; 32],
|
||||
) {
|
||||
let tree = unsafe {
|
||||
tree.as_ref()
|
||||
.expect("Orchard note commitment tree pointer may not be null.")
|
||||
};
|
||||
|
||||
let root_ret = unsafe {
|
||||
root_ret
|
||||
.as_mut()
|
||||
.expect("Cannot return to the null pointer.")
|
||||
};
|
||||
|
||||
*root_ret = tree.root().to_bytes();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn orchard_merkle_frontier_num_leaves(
|
||||
tree: *const bridgetree::Frontier<MerkleHashOrchard, MERKLE_DEPTH>,
|
||||
) -> u64 {
|
||||
let tree = unsafe {
|
||||
tree.as_ref()
|
||||
.expect("Orchard note commitment tree pointer may not be null.")
|
||||
};
|
||||
|
||||
tree.position().map_or(0, |p| <u64>::from(p) + 1)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn orchard_merkle_frontier_dynamic_mem_usage(
|
||||
tree: *const bridgetree::Frontier<MerkleHashOrchard, MERKLE_DEPTH>,
|
||||
) -> usize {
|
||||
let tree = unsafe {
|
||||
tree.as_ref()
|
||||
.expect("Orchard note commitment tree pointer may not be null.")
|
||||
};
|
||||
|
||||
size_of_val(tree) + tree.dynamic_memory_usage()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn orchard_merkle_tree_empty_root(root_ret: *mut [u8; 32]) {
|
||||
let root_ret = unsafe {
|
||||
root_ret
|
||||
.as_mut()
|
||||
.expect("Cannot return to the null pointer.")
|
||||
};
|
||||
|
||||
let altitude = Altitude::from(MERKLE_DEPTH);
|
||||
|
||||
let digest = MerkleHashOrchard::empty_root(altitude).to_bytes();
|
||||
|
||||
*root_ret = digest;
|
||||
}
|
|
@ -0,0 +1,161 @@
|
|||
use core::mem::size_of_val;
|
||||
use core::pin::Pin;
|
||||
|
||||
use incrementalmerkletree::{bridgetree, Altitude, Frontier, Hashable};
|
||||
use orchard::{bundle::Authorized, tree::MerkleHashOrchard};
|
||||
use tracing::error;
|
||||
use zcash_primitives::{
|
||||
merkle_tree::{
|
||||
incremental::{read_frontier_v1, write_frontier_v1},
|
||||
CommitmentTree, HashSer,
|
||||
},
|
||||
transaction::components::Amount,
|
||||
};
|
||||
|
||||
use crate::{streams::CppStream, wallet::Wallet};
|
||||
|
||||
pub const MERKLE_DEPTH: u8 = 32;
|
||||
|
||||
#[cxx::bridge]
|
||||
mod ffi {
|
||||
extern "C++" {
|
||||
include!("streams.h");
|
||||
|
||||
#[cxx_name = "RustDataStream"]
|
||||
type RustStream = crate::streams::ffi::RustStream;
|
||||
}
|
||||
|
||||
#[namespace = "merkle_frontier"]
|
||||
extern "Rust" {
|
||||
type Orchard;
|
||||
type OrchardBundle;
|
||||
type OrchardWallet;
|
||||
|
||||
fn orchard_empty_root() -> [u8; 32];
|
||||
fn new_orchard() -> Box<Orchard>;
|
||||
fn box_clone(self: &Orchard) -> Box<Orchard>;
|
||||
fn parse_orchard(stream: Pin<&mut RustStream>) -> Result<Box<Orchard>>;
|
||||
fn serialize(self: &Orchard, stream: Pin<&mut RustStream>) -> Result<()>;
|
||||
fn serialize_legacy(self: &Orchard, stream: Pin<&mut RustStream>) -> Result<()>;
|
||||
fn dynamic_memory_usage(self: &Orchard) -> usize;
|
||||
fn root(self: &Orchard) -> [u8; 32];
|
||||
fn size(self: &Orchard) -> u64;
|
||||
unsafe fn append_bundle(self: &mut Orchard, bundle: *const OrchardBundle) -> bool;
|
||||
unsafe fn init_wallet(self: &Orchard, wallet: *mut OrchardWallet) -> bool;
|
||||
}
|
||||
}
|
||||
|
||||
type Inner<H> = bridgetree::Frontier<H, MERKLE_DEPTH>;
|
||||
|
||||
/// A incremental Merkle frontier.
|
||||
#[derive(Clone)]
|
||||
struct MerkleFrontier<H>(Inner<H>);
|
||||
|
||||
impl<H: Copy + Hashable + HashSer> MerkleFrontier<H> {
|
||||
/// Returns a copy of the value.
|
||||
fn box_clone(&self) -> Box<Self> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
|
||||
/// Attempts to parse a Merkle frontier from the given C++ stream.
|
||||
fn parse(stream: Pin<&mut ffi::RustStream>) -> Result<Box<Self>, String> {
|
||||
let reader = CppStream::from(stream);
|
||||
|
||||
match read_frontier_v1(reader) {
|
||||
Ok(parsed) => Ok(Box::new(MerkleFrontier(parsed))),
|
||||
Err(e) => Err(format!("Failed to parse v5 Merkle frontier: {}", e)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Serializes the frontier to the given C++ stream.
|
||||
fn serialize(&self, stream: Pin<&mut ffi::RustStream>) -> Result<(), String> {
|
||||
let writer = CppStream::from(stream);
|
||||
write_frontier_v1(writer, &self.0)
|
||||
.map_err(|e| format!("Failed to serialize v5 Merkle frontier: {}", e))
|
||||
}
|
||||
|
||||
/// Serializes the frontier to the given C++ stream in the legacy frontier encoding.
|
||||
fn serialize_legacy(&self, stream: Pin<&mut ffi::RustStream>) -> Result<(), String> {
|
||||
let writer = CppStream::from(stream);
|
||||
let commitment_tree = CommitmentTree::from_frontier(&self.0);
|
||||
commitment_tree.write(writer).map_err(|e| {
|
||||
format!(
|
||||
"Failed to serialize Merkle frontier in legacy format: {}",
|
||||
e,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the amount of memory dynamically allocated for the frontier.
|
||||
///
|
||||
/// Includes `self` because this type is stored on the heap when passed to C++.
|
||||
fn dynamic_memory_usage(&self) -> usize {
|
||||
size_of_val(&self.0) + self.0.dynamic_memory_usage()
|
||||
}
|
||||
|
||||
/// Obtains the current root of this Merkle frontier by hashing against empty nodes up
|
||||
/// to the maximum height of the pruned tree that the frontier represents.
|
||||
fn root(&self) -> [u8; 32] {
|
||||
let mut root = [0; 32];
|
||||
self.0
|
||||
.root()
|
||||
.write(&mut root[..])
|
||||
.expect("root is 32 bytes");
|
||||
root
|
||||
}
|
||||
|
||||
/// Returns the number of leaves appended to the frontier.
|
||||
fn size(&self) -> u64 {
|
||||
self.0.position().map_or(0, |p| <u64>::from(p) + 1)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the root of an empty Orchard Merkle tree.
|
||||
fn orchard_empty_root() -> [u8; 32] {
|
||||
let altitude = Altitude::from(MERKLE_DEPTH);
|
||||
MerkleHashOrchard::empty_root(altitude).to_bytes()
|
||||
}
|
||||
|
||||
/// An Orchard incremental Merkle frontier.
|
||||
type Orchard = MerkleFrontier<MerkleHashOrchard>;
|
||||
|
||||
/// Constructs a new empty Orchard Merkle frontier.
|
||||
fn new_orchard() -> Box<Orchard> {
|
||||
Box::new(MerkleFrontier(Inner::empty()))
|
||||
}
|
||||
|
||||
/// Attempts to parse an Orchard Merkle frontier from the given C++ stream.
|
||||
fn parse_orchard(stream: Pin<&mut ffi::RustStream>) -> Result<Box<Orchard>, String> {
|
||||
Orchard::parse(stream)
|
||||
}
|
||||
|
||||
struct OrchardBundle;
|
||||
struct OrchardWallet;
|
||||
|
||||
impl Orchard {
|
||||
/// Appends the note commitments in the given bundle to this frontier.
|
||||
fn append_bundle(&mut self, bundle: *const OrchardBundle) -> bool {
|
||||
let bundle = unsafe { (bundle as *const orchard::Bundle<Authorized, Amount>).as_ref() };
|
||||
|
||||
if let Some(bundle) = bundle {
|
||||
for action in bundle.actions().iter() {
|
||||
if !self.0.append(&MerkleHashOrchard::from_cmx(action.cmx())) {
|
||||
error!("Orchard note commitment tree is full.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
/// Overwrites the first bridge of the Orchard wallet's note commitment tree to have
|
||||
/// `self` as its latest state.
|
||||
///
|
||||
/// This will fail with an assertion error if any checkpoints exist in the tree.
|
||||
///
|
||||
/// TODO: Remove once `crate::wallet` is migrated to `cxx`.
|
||||
fn init_wallet(&self, wallet: *mut OrchardWallet) -> bool {
|
||||
crate::wallet::orchard_wallet_init_from_frontier(wallet as *mut Wallet, &self.0)
|
||||
}
|
||||
}
|
|
@ -66,8 +66,8 @@ mod builder_ffi;
|
|||
mod bundlecache;
|
||||
mod history_ffi;
|
||||
mod incremental_merkle_tree;
|
||||
mod incremental_merkle_tree_ffi;
|
||||
mod init_ffi;
|
||||
mod merkle_frontier;
|
||||
mod orchard_bundle;
|
||||
mod orchard_ffi;
|
||||
mod orchard_keys_ffi;
|
||||
|
|
|
@ -26,7 +26,7 @@ use orchard::{
|
|||
use crate::{
|
||||
builder_ffi::OrchardSpendInfo,
|
||||
incremental_merkle_tree::{read_tree, write_tree},
|
||||
incremental_merkle_tree_ffi::MERKLE_DEPTH,
|
||||
merkle_frontier::MERKLE_DEPTH,
|
||||
streams_ffi::{CppStreamReader, CppStreamWriter, ReadCb, StreamObj, WriteCb},
|
||||
zcashd_orchard::OrderedAddress,
|
||||
};
|
||||
|
|
|
@ -226,7 +226,8 @@ public:
|
|||
*/
|
||||
void InitNoteCommitmentTree(const OrchardMerkleFrontier& frontier) {
|
||||
assert(!GetLastCheckpointHeight().has_value());
|
||||
assert(orchard_wallet_init_from_frontier(inner.get(), frontier.inner.get()));
|
||||
assert(frontier.inner->init_wallet(
|
||||
reinterpret_cast<merkle_frontier::OrchardWallet*>(inner.get())));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#include "zcash/util.h"
|
||||
|
||||
#include <primitives/orchard.h>
|
||||
#include <rust/orchard/incremental_merkle_tree.h>
|
||||
#include <rust/merkle_frontier.h>
|
||||
|
||||
namespace libzcash {
|
||||
|
||||
|
@ -265,19 +265,18 @@ class OrchardMerkleFrontierLegacySer;
|
|||
class OrchardMerkleFrontier
|
||||
{
|
||||
private:
|
||||
/// An incremental Sinsemilla tree; this pointer may never be null.
|
||||
/// Memory is allocated by Rust.
|
||||
std::unique_ptr<OrchardMerkleFrontierPtr, decltype(&orchard_merkle_frontier_free)> inner;
|
||||
/// An incremental Sinsemilla tree. Memory is allocated by Rust.
|
||||
rust::Box<merkle_frontier::Orchard> inner;
|
||||
|
||||
friend class OrchardWallet;
|
||||
friend class OrchardMerkleFrontierLegacySer;
|
||||
public:
|
||||
OrchardMerkleFrontier() : inner(orchard_merkle_frontier_empty(), orchard_merkle_frontier_free) {}
|
||||
OrchardMerkleFrontier() : inner(merkle_frontier::new_orchard()) {}
|
||||
|
||||
OrchardMerkleFrontier(OrchardMerkleFrontier&& frontier) : inner(std::move(frontier.inner)) {}
|
||||
|
||||
OrchardMerkleFrontier(const OrchardMerkleFrontier& frontier) :
|
||||
inner(orchard_merkle_frontier_clone(frontier.inner.get()), orchard_merkle_frontier_free) {}
|
||||
inner(frontier.inner->box_clone()) {}
|
||||
|
||||
OrchardMerkleFrontier& operator=(OrchardMerkleFrontier&& frontier)
|
||||
{
|
||||
|
@ -289,52 +288,48 @@ public:
|
|||
OrchardMerkleFrontier& operator=(const OrchardMerkleFrontier& frontier)
|
||||
{
|
||||
if (this != &frontier) {
|
||||
inner.reset(orchard_merkle_frontier_clone(frontier.inner.get()));
|
||||
inner = frontier.inner->box_clone();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename Stream>
|
||||
void Serialize(Stream& s) const {
|
||||
RustStream rs(s);
|
||||
if (!orchard_merkle_frontier_serialize(inner.get(), &rs, RustStream<Stream>::write_callback)) {
|
||||
throw std::ios_base::failure("Failed to serialize v5 Orchard tree");
|
||||
try {
|
||||
inner->serialize(s);
|
||||
} catch (const std::exception& e) {
|
||||
throw std::ios_base::failure(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Stream>
|
||||
void Unserialize(Stream& s) {
|
||||
RustStream rs(s);
|
||||
OrchardMerkleFrontierPtr* tree = orchard_merkle_frontier_parse(
|
||||
&rs, RustStream<Stream>::read_callback);
|
||||
if (tree == nullptr) {
|
||||
throw std::ios_base::failure("Failed to parse v5 Orchard tree");
|
||||
try {
|
||||
inner = merkle_frontier::parse_orchard(s);
|
||||
} catch (const std::exception& e) {
|
||||
throw std::ios_base::failure(e.what());
|
||||
}
|
||||
inner.reset(tree);
|
||||
}
|
||||
|
||||
size_t DynamicMemoryUsage() const {
|
||||
return orchard_merkle_frontier_dynamic_mem_usage(inner.get());
|
||||
return inner->dynamic_memory_usage();
|
||||
}
|
||||
|
||||
bool AppendBundle(const OrchardBundle& bundle) {
|
||||
return orchard_merkle_frontier_append_bundle(inner.get(), bundle.inner.get());
|
||||
return inner->append_bundle(
|
||||
reinterpret_cast<merkle_frontier::OrchardBundle*>(bundle.inner.get()));
|
||||
}
|
||||
|
||||
const uint256 root() const {
|
||||
uint256 value;
|
||||
orchard_merkle_frontier_root(inner.get(), value.begin());
|
||||
return value;
|
||||
return uint256::FromRawBytes(inner->root());
|
||||
}
|
||||
|
||||
static uint256 empty_root() {
|
||||
uint256 value;
|
||||
orchard_merkle_tree_empty_root(value.begin());
|
||||
return value;
|
||||
return uint256::FromRawBytes(merkle_frontier::orchard_empty_root());
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
return orchard_merkle_frontier_num_leaves(inner.get());
|
||||
return inner->size();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -346,9 +341,10 @@ public:
|
|||
|
||||
template<typename Stream>
|
||||
void Serialize(Stream& s) const {
|
||||
RustStream rs(s);
|
||||
if (!orchard_merkle_frontier_serialize_legacy(frontier.inner.get(), &rs, RustStream<Stream>::write_callback)) {
|
||||
throw std::ios_base::failure("Failed to serialize Orchard merkle frontier in legacy format.");
|
||||
try {
|
||||
frontier.inner->serialize_legacy(s);
|
||||
} catch (const std::exception& e) {
|
||||
throw std::ios_base::failure(e.what());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue