Merge most `cxx::bridge` definitions into a single bridge
This enables us to use Rust types across more bridged APIs, which we can't do with multiple bridge definitions until `cxx` adds support.
This commit is contained in:
parent
1feec6a3b4
commit
33367709f7
|
@ -50,34 +50,21 @@ if ENABLE_WALLET
|
||||||
LIBBITCOIN_WALLET=libbitcoin_wallet.a
|
LIBBITCOIN_WALLET=libbitcoin_wallet.a
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# TODO: Figure out how to avoid an explicit file list.
|
|
||||||
CXXBRIDGE_RS = \
|
CXXBRIDGE_RS = \
|
||||||
rust/src/blake2b.rs \
|
rust/src/blake2b.rs \
|
||||||
rust/src/bundlecache.rs \
|
|
||||||
rust/src/equihash.rs \
|
rust/src/equihash.rs \
|
||||||
rust/src/merkle_frontier.rs \
|
|
||||||
rust/src/orchard_bundle.rs \
|
|
||||||
rust/src/sapling.rs \
|
|
||||||
rust/src/streams.rs \
|
rust/src/streams.rs \
|
||||||
rust/src/wallet_scanner.rs
|
rust/src/bridge.rs
|
||||||
CXXBRIDGE_H = \
|
CXXBRIDGE_H = \
|
||||||
rust/gen/include/rust/blake2b.h \
|
rust/gen/include/rust/blake2b.h \
|
||||||
rust/gen/include/rust/bundlecache.h \
|
|
||||||
rust/gen/include/rust/equihash.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 \
|
rust/gen/include/rust/streams.h \
|
||||||
rust/gen/include/rust/wallet_scanner.h
|
rust/gen/include/rust/bridge.h
|
||||||
CXXBRIDGE_CPP = \
|
CXXBRIDGE_CPP = \
|
||||||
rust/gen/src/blake2b.cpp \
|
rust/gen/src/blake2b.cpp \
|
||||||
rust/gen/src/bundlecache.cpp \
|
|
||||||
rust/gen/src/equihash.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 \
|
rust/gen/src/streams.cpp \
|
||||||
rust/gen/src/wallet_scanner.cpp
|
rust/gen/src/bridge.cpp
|
||||||
|
|
||||||
# We add a rust/cxx.h include to indicate that we provide this (via the rustcxx depends
|
# We add a rust/cxx.h include to indicate that we provide this (via the rustcxx depends
|
||||||
# package), so that cxxbridge doesn't include it within the generated headers and code.
|
# package), so that cxxbridge doesn't include it within the generated headers and code.
|
||||||
|
|
|
@ -15,8 +15,8 @@
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
|
||||||
#include "librustzcash.h"
|
#include "librustzcash.h"
|
||||||
|
#include <rust/bridge.h>
|
||||||
#include <rust/ed25519.h>
|
#include <rust/ed25519.h>
|
||||||
#include <rust/sapling.h>
|
|
||||||
|
|
||||||
static void ECDSA(benchmark::State& state)
|
static void ECDSA(benchmark::State& state)
|
||||||
{
|
{
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <rust/wallet_scanner.h>
|
#include <rust/bridge.h>
|
||||||
|
|
||||||
struct CDNSSeedData {
|
struct CDNSSeedData {
|
||||||
std::string name, host;
|
std::string name, host;
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
#include <sodium.h>
|
#include <sodium.h>
|
||||||
#include <tracing.h>
|
#include <tracing.h>
|
||||||
|
|
||||||
#include <rust/bundlecache.h>
|
#include <rust/bridge.h>
|
||||||
|
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
|
|
||||||
|
|
|
@ -11,8 +11,8 @@
|
||||||
#include "zcash/JoinSplit.hpp"
|
#include "zcash/JoinSplit.hpp"
|
||||||
|
|
||||||
#include <librustzcash.h>
|
#include <librustzcash.h>
|
||||||
|
#include <rust/bridge.h>
|
||||||
#include <rust/ed25519.h>
|
#include <rust/ed25519.h>
|
||||||
#include <rust/sapling.h>
|
|
||||||
#include <rust/orchard.h>
|
#include <rust/orchard.h>
|
||||||
|
|
||||||
// Subclass of CTransaction which doesn't call UpdateHash when constructing
|
// Subclass of CTransaction which doesn't call UpdateHash when constructing
|
||||||
|
|
|
@ -67,7 +67,7 @@
|
||||||
#include "zmq/zmqnotificationinterface.h"
|
#include "zmq/zmqnotificationinterface.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <rust/bundlecache.h>
|
#include <rust/bridge.h>
|
||||||
#include <rust/init.h>
|
#include <rust/init.h>
|
||||||
#include <rust/metrics.h>
|
#include <rust/metrics.h>
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,7 @@
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <rust/sapling.h>
|
#include <rust/bridge.h>
|
||||||
#include <rust/orchard.h>
|
#include <rust/orchard.h>
|
||||||
|
|
||||||
#include <boost/unordered_map.hpp>
|
#include <boost/unordered_map.hpp>
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
#include "validationinterface.h"
|
#include "validationinterface.h"
|
||||||
|
|
||||||
#include <librustzcash.h>
|
#include <librustzcash.h>
|
||||||
#include <rust/sapling.h>
|
#include <rust/bridge.h>
|
||||||
|
|
||||||
#include <boost/thread.hpp>
|
#include <boost/thread.hpp>
|
||||||
#include <boost/tuple/tuple.hpp>
|
#include <boost/tuple/tuple.hpp>
|
||||||
|
|
|
@ -8,8 +8,9 @@
|
||||||
#include "streams.h"
|
#include "streams.h"
|
||||||
|
|
||||||
#include <amount.h>
|
#include <amount.h>
|
||||||
|
|
||||||
|
#include <rust/bridge.h>
|
||||||
#include <rust/orchard.h>
|
#include <rust/orchard.h>
|
||||||
#include <rust/orchard_bundle.h>
|
|
||||||
#include <rust/orchard/wallet.h>
|
#include <rust/orchard/wallet.h>
|
||||||
#include "zcash/address/orchard.hpp"
|
#include "zcash/address/orchard.hpp"
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
#include <boost/assign/list_of.hpp>
|
#include <boost/assign/list_of.hpp>
|
||||||
|
|
||||||
#include <univalue.h>
|
#include <univalue.h>
|
||||||
#include <rust/orchard_bundle.h>
|
#include <rust/bridge.h>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,277 @@
|
||||||
|
//! FFI bridges between `zcashd`'s Rust and C++ code.
|
||||||
|
//!
|
||||||
|
//! These are all collected into a single file because we can't use the same Rust type
|
||||||
|
//! across multiple bridges until https://github.com/dtolnay/cxx/issues/496 is closed.
|
||||||
|
//!
|
||||||
|
//! The bridges that we leave separate are either standalone Rust code, or exporting C++
|
||||||
|
//! types to Rust (because we _can_ use the same C++ type across multiple bridges).
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
bundlecache::init as bundlecache_init,
|
||||||
|
merkle_frontier::{new_orchard, orchard_empty_root, parse_orchard, Orchard, OrchardWallet},
|
||||||
|
note_encryption::{
|
||||||
|
try_sapling_note_decryption, try_sapling_output_recovery, DecryptedSaplingOutput,
|
||||||
|
},
|
||||||
|
orchard_bundle::{from_tx_bundle, Action, Bundle, OrchardBundle},
|
||||||
|
params::{network, Network},
|
||||||
|
sapling::{
|
||||||
|
finish_bundle_assembly, init_batch_validator, init_prover, init_verifier,
|
||||||
|
new_bundle_assembler, BatchValidator, Bundle as SaplingBundle,
|
||||||
|
BundleAssembler as SaplingBundleAssembler, Prover, Verifier,
|
||||||
|
},
|
||||||
|
wallet_scanner::{init_batch_scanner, BatchResult, BatchScanner},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[cxx::bridge]
|
||||||
|
pub(crate) mod ffi {
|
||||||
|
extern "C++" {
|
||||||
|
include!("streams.h");
|
||||||
|
|
||||||
|
#[cxx_name = "RustDataStream"]
|
||||||
|
type RustStream = crate::streams::ffi::RustStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[namespace = "consensus"]
|
||||||
|
extern "Rust" {
|
||||||
|
type Network;
|
||||||
|
|
||||||
|
fn network(
|
||||||
|
network: &str,
|
||||||
|
overwinter: i32,
|
||||||
|
sapling: i32,
|
||||||
|
blossom: i32,
|
||||||
|
heartwood: i32,
|
||||||
|
canopy: i32,
|
||||||
|
nu5: i32,
|
||||||
|
) -> Result<Box<Network>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[namespace = "libzcash"]
|
||||||
|
unsafe extern "C++" {
|
||||||
|
include!("zcash/cache.h");
|
||||||
|
|
||||||
|
type BundleValidityCache;
|
||||||
|
|
||||||
|
fn NewBundleValidityCache(kind: &str, bytes: usize) -> UniquePtr<BundleValidityCache>;
|
||||||
|
fn insert(self: Pin<&mut BundleValidityCache>, entry: [u8; 32]);
|
||||||
|
fn contains(&self, entry: &[u8; 32], erase: bool) -> bool;
|
||||||
|
}
|
||||||
|
#[namespace = "bundlecache"]
|
||||||
|
extern "Rust" {
|
||||||
|
#[rust_name = "bundlecache_init"]
|
||||||
|
fn init(cache_bytes: usize);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[namespace = "sapling"]
|
||||||
|
extern "Rust" {
|
||||||
|
#[rust_name = "SaplingBundle"]
|
||||||
|
type Bundle;
|
||||||
|
|
||||||
|
#[rust_name = "SaplingBundleAssembler"]
|
||||||
|
type BundleAssembler;
|
||||||
|
|
||||||
|
fn new_bundle_assembler() -> Box<SaplingBundleAssembler>;
|
||||||
|
fn add_spend(
|
||||||
|
self: &mut SaplingBundleAssembler,
|
||||||
|
cv: &[u8; 32],
|
||||||
|
anchor: &[u8; 32],
|
||||||
|
nullifier: [u8; 32],
|
||||||
|
rk: &[u8; 32],
|
||||||
|
zkproof: [u8; 192], // GROTH_PROOF_SIZE
|
||||||
|
spend_auth_sig: &[u8; 64],
|
||||||
|
) -> bool;
|
||||||
|
fn add_output(
|
||||||
|
self: &mut SaplingBundleAssembler,
|
||||||
|
cv: &[u8; 32],
|
||||||
|
cmu: &[u8; 32],
|
||||||
|
ephemeral_key: [u8; 32],
|
||||||
|
enc_ciphertext: [u8; 580],
|
||||||
|
out_ciphertext: [u8; 80],
|
||||||
|
zkproof: [u8; 192], // GROTH_PROOF_SIZE
|
||||||
|
) -> bool;
|
||||||
|
fn finish_bundle_assembly(
|
||||||
|
assembler: Box<SaplingBundleAssembler>,
|
||||||
|
value_balance: i64,
|
||||||
|
binding_sig: [u8; 64],
|
||||||
|
) -> Box<SaplingBundle>;
|
||||||
|
|
||||||
|
type Prover;
|
||||||
|
|
||||||
|
fn init_prover() -> Box<Prover>;
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
fn create_spend_proof(
|
||||||
|
self: &mut Prover,
|
||||||
|
ak: &[u8; 32],
|
||||||
|
nsk: &[u8; 32],
|
||||||
|
diversifier: &[u8; 11],
|
||||||
|
rcm: &[u8; 32],
|
||||||
|
ar: &[u8; 32],
|
||||||
|
value: u64,
|
||||||
|
anchor: &[u8; 32],
|
||||||
|
merkle_path: &[u8; 1065], // 1 + 33 * SAPLING_TREE_DEPTH + 8
|
||||||
|
cv: &mut [u8; 32],
|
||||||
|
rk_out: &mut [u8; 32],
|
||||||
|
zkproof: &mut [u8; 192], // GROTH_PROOF_SIZE
|
||||||
|
) -> bool;
|
||||||
|
fn create_output_proof(
|
||||||
|
self: &mut Prover,
|
||||||
|
esk: &[u8; 32],
|
||||||
|
payment_address: &[u8; 43],
|
||||||
|
rcm: &[u8; 32],
|
||||||
|
value: u64,
|
||||||
|
cv: &mut [u8; 32],
|
||||||
|
zkproof: &mut [u8; 192], // GROTH_PROOF_SIZE
|
||||||
|
) -> bool;
|
||||||
|
fn binding_sig(
|
||||||
|
self: &mut Prover,
|
||||||
|
value_balance: i64,
|
||||||
|
sighash: &[u8; 32],
|
||||||
|
result: &mut [u8; 64],
|
||||||
|
) -> bool;
|
||||||
|
|
||||||
|
type Verifier;
|
||||||
|
|
||||||
|
fn init_verifier() -> Box<Verifier>;
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
fn check_spend(
|
||||||
|
self: &mut Verifier,
|
||||||
|
cv: &[u8; 32],
|
||||||
|
anchor: &[u8; 32],
|
||||||
|
nullifier: &[u8; 32],
|
||||||
|
rk: &[u8; 32],
|
||||||
|
zkproof: &[u8; 192], // GROTH_PROOF_SIZE
|
||||||
|
spend_auth_sig: &[u8; 64],
|
||||||
|
sighash_value: &[u8; 32],
|
||||||
|
) -> bool;
|
||||||
|
fn check_output(
|
||||||
|
self: &mut Verifier,
|
||||||
|
cv: &[u8; 32],
|
||||||
|
cm: &[u8; 32],
|
||||||
|
ephemeral_key: &[u8; 32],
|
||||||
|
zkproof: &[u8; 192], // GROTH_PROOF_SIZE
|
||||||
|
) -> bool;
|
||||||
|
fn final_check(
|
||||||
|
self: &Verifier,
|
||||||
|
value_balance: i64,
|
||||||
|
binding_sig: &[u8; 64],
|
||||||
|
sighash_value: &[u8; 32],
|
||||||
|
) -> bool;
|
||||||
|
|
||||||
|
type BatchValidator;
|
||||||
|
fn init_batch_validator(cache_store: bool) -> Box<BatchValidator>;
|
||||||
|
fn check_bundle(
|
||||||
|
self: &mut BatchValidator,
|
||||||
|
bundle: Box<SaplingBundle>,
|
||||||
|
sighash: [u8; 32],
|
||||||
|
) -> bool;
|
||||||
|
fn validate(self: &mut BatchValidator) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[namespace = "orchard_bundle"]
|
||||||
|
extern "Rust" {
|
||||||
|
type Action;
|
||||||
|
type Bundle;
|
||||||
|
type OrchardBundle;
|
||||||
|
|
||||||
|
fn cv(self: &Action) -> [u8; 32];
|
||||||
|
fn nullifier(self: &Action) -> [u8; 32];
|
||||||
|
fn rk(self: &Action) -> [u8; 32];
|
||||||
|
fn cmx(self: &Action) -> [u8; 32];
|
||||||
|
fn ephemeral_key(self: &Action) -> [u8; 32];
|
||||||
|
fn enc_ciphertext(self: &Action) -> [u8; 580];
|
||||||
|
fn out_ciphertext(self: &Action) -> [u8; 80];
|
||||||
|
fn spend_auth_sig(self: &Action) -> [u8; 64];
|
||||||
|
|
||||||
|
unsafe fn from_tx_bundle(bundle: *const OrchardBundle) -> Box<Bundle>;
|
||||||
|
fn actions(self: &Bundle) -> Vec<Action>;
|
||||||
|
fn num_actions(self: &Bundle) -> usize;
|
||||||
|
fn enable_spends(self: &Bundle) -> bool;
|
||||||
|
fn enable_outputs(self: &Bundle) -> bool;
|
||||||
|
fn value_balance_zat(self: &Bundle) -> i64;
|
||||||
|
fn anchor(self: &Bundle) -> [u8; 32];
|
||||||
|
fn proof(self: &Bundle) -> Vec<u8>;
|
||||||
|
fn binding_sig(self: &Bundle) -> [u8; 64];
|
||||||
|
}
|
||||||
|
|
||||||
|
#[namespace = "merkle_frontier"]
|
||||||
|
extern "Rust" {
|
||||||
|
type Orchard;
|
||||||
|
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;
|
||||||
|
fn append_bundle(self: &mut Orchard, bundle: &Bundle) -> bool;
|
||||||
|
unsafe fn init_wallet(self: &Orchard, wallet: *mut OrchardWallet) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[namespace = "wallet"]
|
||||||
|
struct SaplingDecryptionResult {
|
||||||
|
txid: [u8; 32],
|
||||||
|
output: u32,
|
||||||
|
ivk: [u8; 32],
|
||||||
|
diversifier: [u8; 11],
|
||||||
|
pk_d: [u8; 32],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[namespace = "wallet"]
|
||||||
|
pub(crate) struct SaplingShieldedOutput {
|
||||||
|
cv: [u8; 32],
|
||||||
|
cmu: [u8; 32],
|
||||||
|
ephemeral_key: [u8; 32],
|
||||||
|
enc_ciphertext: [u8; 580],
|
||||||
|
out_ciphertext: [u8; 80],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[namespace = "wallet"]
|
||||||
|
extern "Rust" {
|
||||||
|
fn try_sapling_note_decryption(
|
||||||
|
network: &Network,
|
||||||
|
height: u32,
|
||||||
|
raw_ivk: &[u8; 32],
|
||||||
|
output: SaplingShieldedOutput,
|
||||||
|
) -> Result<Box<DecryptedSaplingOutput>>;
|
||||||
|
fn try_sapling_output_recovery(
|
||||||
|
network: &Network,
|
||||||
|
height: u32,
|
||||||
|
ovk: [u8; 32],
|
||||||
|
output: SaplingShieldedOutput,
|
||||||
|
) -> Result<Box<DecryptedSaplingOutput>>;
|
||||||
|
|
||||||
|
type DecryptedSaplingOutput;
|
||||||
|
fn note_value(self: &DecryptedSaplingOutput) -> u64;
|
||||||
|
fn note_rseed(self: &DecryptedSaplingOutput) -> [u8; 32];
|
||||||
|
fn zip_212_enabled(self: &DecryptedSaplingOutput) -> bool;
|
||||||
|
fn recipient_d(self: &DecryptedSaplingOutput) -> [u8; 11];
|
||||||
|
fn recipient_pk_d(self: &DecryptedSaplingOutput) -> [u8; 32];
|
||||||
|
fn memo(self: &DecryptedSaplingOutput) -> [u8; 512];
|
||||||
|
|
||||||
|
type BatchScanner;
|
||||||
|
type BatchResult;
|
||||||
|
|
||||||
|
fn init_batch_scanner(
|
||||||
|
network: &Network,
|
||||||
|
sapling_ivks: &[[u8; 32]],
|
||||||
|
) -> Result<Box<BatchScanner>>;
|
||||||
|
fn add_transaction(
|
||||||
|
self: &mut BatchScanner,
|
||||||
|
block_tag: [u8; 32],
|
||||||
|
tx_bytes: &[u8],
|
||||||
|
height: u32,
|
||||||
|
) -> Result<()>;
|
||||||
|
fn flush(self: &mut BatchScanner);
|
||||||
|
fn collect_results(
|
||||||
|
self: &mut BatchScanner,
|
||||||
|
block_tag: [u8; 32],
|
||||||
|
txid: [u8; 32],
|
||||||
|
) -> Box<BatchResult>;
|
||||||
|
|
||||||
|
fn get_sapling(self: &BatchResult) -> Vec<SaplingDecryptionResult>;
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,23 +5,7 @@ use std::{
|
||||||
|
|
||||||
use rand_core::{OsRng, RngCore};
|
use rand_core::{OsRng, RngCore};
|
||||||
|
|
||||||
#[cxx::bridge]
|
use crate::bridge::ffi;
|
||||||
mod ffi {
|
|
||||||
#[namespace = "libzcash"]
|
|
||||||
unsafe extern "C++" {
|
|
||||||
include!("zcash/cache.h");
|
|
||||||
|
|
||||||
type BundleValidityCache;
|
|
||||||
|
|
||||||
fn NewBundleValidityCache(kind: &str, bytes: usize) -> UniquePtr<BundleValidityCache>;
|
|
||||||
fn insert(self: Pin<&mut BundleValidityCache>, entry: [u8; 32]);
|
|
||||||
fn contains(&self, entry: &[u8; 32], erase: bool) -> bool;
|
|
||||||
}
|
|
||||||
#[namespace = "bundlecache"]
|
|
||||||
extern "Rust" {
|
|
||||||
fn init(cache_bytes: usize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct CacheEntry([u8; 32]);
|
pub(crate) struct CacheEntry([u8; 32]);
|
||||||
|
|
||||||
|
@ -114,7 +98,7 @@ static BUNDLE_CACHES_LOADED: Once = Once::new();
|
||||||
static mut SAPLING_BUNDLE_VALIDITY_CACHE: Option<RwLock<BundleValidityCache>> = None;
|
static mut SAPLING_BUNDLE_VALIDITY_CACHE: Option<RwLock<BundleValidityCache>> = None;
|
||||||
static mut ORCHARD_BUNDLE_VALIDITY_CACHE: Option<RwLock<BundleValidityCache>> = None;
|
static mut ORCHARD_BUNDLE_VALIDITY_CACHE: Option<RwLock<BundleValidityCache>> = None;
|
||||||
|
|
||||||
fn init(cache_bytes: usize) {
|
pub(crate) fn init(cache_bytes: usize) {
|
||||||
BUNDLE_CACHES_LOADED.call_once(|| unsafe {
|
BUNDLE_CACHES_LOADED.call_once(|| unsafe {
|
||||||
SAPLING_BUNDLE_VALIDITY_CACHE = Some(RwLock::new(BundleValidityCache::new(
|
SAPLING_BUNDLE_VALIDITY_CACHE = Some(RwLock::new(BundleValidityCache::new(
|
||||||
"Sapling",
|
"Sapling",
|
||||||
|
|
|
@ -2,63 +2,31 @@ use core::mem::size_of_val;
|
||||||
use core::pin::Pin;
|
use core::pin::Pin;
|
||||||
|
|
||||||
use incrementalmerkletree::{bridgetree, Altitude, Frontier, Hashable};
|
use incrementalmerkletree::{bridgetree, Altitude, Frontier, Hashable};
|
||||||
use orchard::{bundle::Authorized, tree::MerkleHashOrchard};
|
use orchard::tree::MerkleHashOrchard;
|
||||||
use tracing::error;
|
use tracing::error;
|
||||||
use zcash_primitives::{
|
use zcash_primitives::merkle_tree::{
|
||||||
merkle_tree::{
|
|
||||||
incremental::{read_frontier_v1, write_frontier_v1},
|
incremental::{read_frontier_v1, write_frontier_v1},
|
||||||
CommitmentTree, HashSer,
|
CommitmentTree, HashSer,
|
||||||
},
|
|
||||||
transaction::components::Amount,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{streams::CppStream, wallet::Wallet};
|
use crate::{bridge::ffi, orchard_bundle, streams::CppStream, wallet::Wallet};
|
||||||
|
|
||||||
pub const MERKLE_DEPTH: u8 = 32;
|
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>;
|
type Inner<H> = bridgetree::Frontier<H, MERKLE_DEPTH>;
|
||||||
|
|
||||||
/// An incremental Merkle frontier.
|
/// An incremental Merkle frontier.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct MerkleFrontier<H>(Inner<H>);
|
pub(crate) struct MerkleFrontier<H>(Inner<H>);
|
||||||
|
|
||||||
impl<H: Copy + Hashable + HashSer> MerkleFrontier<H> {
|
impl<H: Copy + Hashable + HashSer> MerkleFrontier<H> {
|
||||||
/// Returns a copy of the value.
|
/// Returns a copy of the value.
|
||||||
fn box_clone(&self) -> Box<Self> {
|
pub(crate) fn box_clone(&self) -> Box<Self> {
|
||||||
Box::new(self.clone())
|
Box::new(self.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempts to parse a Merkle frontier from the given C++ stream.
|
/// Attempts to parse a Merkle frontier from the given C++ stream.
|
||||||
fn parse(stream: Pin<&mut ffi::RustStream>) -> Result<Box<Self>, String> {
|
pub(crate) fn parse(stream: Pin<&mut ffi::RustStream>) -> Result<Box<Self>, String> {
|
||||||
let reader = CppStream::from(stream);
|
let reader = CppStream::from(stream);
|
||||||
|
|
||||||
match read_frontier_v1(reader) {
|
match read_frontier_v1(reader) {
|
||||||
|
@ -68,14 +36,14 @@ impl<H: Copy + Hashable + HashSer> MerkleFrontier<H> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Serializes the frontier to the given C++ stream.
|
/// Serializes the frontier to the given C++ stream.
|
||||||
fn serialize(&self, stream: Pin<&mut ffi::RustStream>) -> Result<(), String> {
|
pub(crate) fn serialize(&self, stream: Pin<&mut ffi::RustStream>) -> Result<(), String> {
|
||||||
let writer = CppStream::from(stream);
|
let writer = CppStream::from(stream);
|
||||||
write_frontier_v1(writer, &self.0)
|
write_frontier_v1(writer, &self.0)
|
||||||
.map_err(|e| format!("Failed to serialize v5 Merkle frontier: {}", e))
|
.map_err(|e| format!("Failed to serialize v5 Merkle frontier: {}", e))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Serializes the frontier to the given C++ stream in the legacy frontier encoding.
|
/// Serializes the frontier to the given C++ stream in the legacy frontier encoding.
|
||||||
fn serialize_legacy(&self, stream: Pin<&mut ffi::RustStream>) -> Result<(), String> {
|
pub(crate) fn serialize_legacy(&self, stream: Pin<&mut ffi::RustStream>) -> Result<(), String> {
|
||||||
let writer = CppStream::from(stream);
|
let writer = CppStream::from(stream);
|
||||||
let commitment_tree = CommitmentTree::from_frontier(&self.0);
|
let commitment_tree = CommitmentTree::from_frontier(&self.0);
|
||||||
commitment_tree.write(writer).map_err(|e| {
|
commitment_tree.write(writer).map_err(|e| {
|
||||||
|
@ -89,13 +57,13 @@ impl<H: Copy + Hashable + HashSer> MerkleFrontier<H> {
|
||||||
/// Returns the amount of memory dynamically allocated for the frontier.
|
/// Returns the amount of memory dynamically allocated for the frontier.
|
||||||
///
|
///
|
||||||
/// Includes `self` because this type is stored on the heap when passed to C++.
|
/// Includes `self` because this type is stored on the heap when passed to C++.
|
||||||
fn dynamic_memory_usage(&self) -> usize {
|
pub(crate) fn dynamic_memory_usage(&self) -> usize {
|
||||||
size_of_val(&self.0) + self.0.dynamic_memory_usage()
|
size_of_val(&self.0) + self.0.dynamic_memory_usage()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Obtains the current root of this Merkle frontier by hashing against empty nodes up
|
/// 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.
|
/// to the maximum height of the pruned tree that the frontier represents.
|
||||||
fn root(&self) -> [u8; 32] {
|
pub(crate) fn root(&self) -> [u8; 32] {
|
||||||
let mut root = [0; 32];
|
let mut root = [0; 32];
|
||||||
self.0
|
self.0
|
||||||
.root()
|
.root()
|
||||||
|
@ -105,39 +73,36 @@ impl<H: Copy + Hashable + HashSer> MerkleFrontier<H> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the number of leaves appended to the frontier.
|
/// Returns the number of leaves appended to the frontier.
|
||||||
fn size(&self) -> u64 {
|
pub(crate) fn size(&self) -> u64 {
|
||||||
self.0.position().map_or(0, |p| <u64>::from(p) + 1)
|
self.0.position().map_or(0, |p| <u64>::from(p) + 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the root of an empty Orchard Merkle tree.
|
/// Returns the root of an empty Orchard Merkle tree.
|
||||||
fn orchard_empty_root() -> [u8; 32] {
|
pub(crate) fn orchard_empty_root() -> [u8; 32] {
|
||||||
let altitude = Altitude::from(MERKLE_DEPTH);
|
let altitude = Altitude::from(MERKLE_DEPTH);
|
||||||
MerkleHashOrchard::empty_root(altitude).to_bytes()
|
MerkleHashOrchard::empty_root(altitude).to_bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An Orchard incremental Merkle frontier.
|
/// An Orchard incremental Merkle frontier.
|
||||||
type Orchard = MerkleFrontier<MerkleHashOrchard>;
|
pub(crate) type Orchard = MerkleFrontier<MerkleHashOrchard>;
|
||||||
|
|
||||||
/// Constructs a new empty Orchard Merkle frontier.
|
/// Constructs a new empty Orchard Merkle frontier.
|
||||||
fn new_orchard() -> Box<Orchard> {
|
pub(crate) fn new_orchard() -> Box<Orchard> {
|
||||||
Box::new(MerkleFrontier(Inner::empty()))
|
Box::new(MerkleFrontier(Inner::empty()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempts to parse an Orchard Merkle frontier from the given C++ stream.
|
/// Attempts to parse an Orchard Merkle frontier from the given C++ stream.
|
||||||
fn parse_orchard(stream: Pin<&mut ffi::RustStream>) -> Result<Box<Orchard>, String> {
|
pub(crate) fn parse_orchard(stream: Pin<&mut ffi::RustStream>) -> Result<Box<Orchard>, String> {
|
||||||
Orchard::parse(stream)
|
Orchard::parse(stream)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct OrchardBundle;
|
pub(crate) struct OrchardWallet;
|
||||||
struct OrchardWallet;
|
|
||||||
|
|
||||||
impl Orchard {
|
impl Orchard {
|
||||||
/// Appends the note commitments in the given bundle to this frontier.
|
/// Appends the note commitments in the given bundle to this frontier.
|
||||||
fn append_bundle(&mut self, bundle: *const OrchardBundle) -> bool {
|
pub(crate) fn append_bundle(&mut self, bundle: &orchard_bundle::Bundle) -> bool {
|
||||||
let bundle = unsafe { (bundle as *const orchard::Bundle<Authorized, Amount>).as_ref() };
|
if let Some(bundle) = bundle.inner() {
|
||||||
|
|
||||||
if let Some(bundle) = bundle {
|
|
||||||
for action in bundle.actions().iter() {
|
for action in bundle.actions().iter() {
|
||||||
if !self.0.append(&MerkleHashOrchard::from_cmx(action.cmx())) {
|
if !self.0.append(&MerkleHashOrchard::from_cmx(action.cmx())) {
|
||||||
error!("Orchard note commitment tree is full.");
|
error!("Orchard note commitment tree is full.");
|
||||||
|
@ -155,7 +120,7 @@ impl Orchard {
|
||||||
/// This will fail with an assertion error if any checkpoints exist in the tree.
|
/// This will fail with an assertion error if any checkpoints exist in the tree.
|
||||||
///
|
///
|
||||||
/// TODO: Remove once `crate::wallet` is migrated to `cxx`.
|
/// TODO: Remove once `crate::wallet` is migrated to `cxx`.
|
||||||
fn init_wallet(&self, wallet: *mut OrchardWallet) -> bool {
|
pub(crate) fn init_wallet(&self, wallet: *mut OrchardWallet) -> bool {
|
||||||
crate::wallet::orchard_wallet_init_from_frontier(wallet as *mut Wallet, &self.0)
|
crate::wallet::orchard_wallet_init_from_frontier(wallet as *mut Wallet, &self.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ use zcash_primitives::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{params::Network, wallet_scanner::ffi::SaplingShieldedOutput};
|
use crate::{bridge::ffi::SaplingShieldedOutput, params::Network};
|
||||||
|
|
||||||
/// Trial decryption of the full note plaintext by the recipient.
|
/// Trial decryption of the full note plaintext by the recipient.
|
||||||
///
|
///
|
||||||
|
|
|
@ -4,80 +4,56 @@ use orchard::{
|
||||||
};
|
};
|
||||||
use zcash_primitives::transaction::components::Amount;
|
use zcash_primitives::transaction::components::Amount;
|
||||||
|
|
||||||
#[cxx::bridge(namespace = "orchard_bundle")]
|
|
||||||
mod ffi {
|
|
||||||
extern "Rust" {
|
|
||||||
type Action;
|
|
||||||
type Bundle;
|
|
||||||
type OrchardBundle;
|
|
||||||
|
|
||||||
fn cv(self: &Action) -> [u8; 32];
|
|
||||||
fn nullifier(self: &Action) -> [u8; 32];
|
|
||||||
fn rk(self: &Action) -> [u8; 32];
|
|
||||||
fn cmx(self: &Action) -> [u8; 32];
|
|
||||||
fn ephemeral_key(self: &Action) -> [u8; 32];
|
|
||||||
fn enc_ciphertext(self: &Action) -> [u8; 580];
|
|
||||||
fn out_ciphertext(self: &Action) -> [u8; 80];
|
|
||||||
fn spend_auth_sig(self: &Action) -> [u8; 64];
|
|
||||||
|
|
||||||
unsafe fn from_tx_bundle(bundle: *const OrchardBundle) -> Box<Bundle>;
|
|
||||||
fn actions(self: &Bundle) -> Vec<Action>;
|
|
||||||
fn num_actions(self: &Bundle) -> usize;
|
|
||||||
fn enable_spends(self: &Bundle) -> bool;
|
|
||||||
fn enable_outputs(self: &Bundle) -> bool;
|
|
||||||
fn value_balance_zat(self: &Bundle) -> i64;
|
|
||||||
fn anchor(self: &Bundle) -> [u8; 32];
|
|
||||||
fn proof(self: &Bundle) -> Vec<u8>;
|
|
||||||
fn binding_sig(self: &Bundle) -> [u8; 64];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Action(orchard::Action<Signature<SpendAuth>>);
|
pub struct Action(orchard::Action<Signature<SpendAuth>>);
|
||||||
|
|
||||||
impl Action {
|
impl Action {
|
||||||
fn cv(&self) -> [u8; 32] {
|
pub(crate) fn cv(&self) -> [u8; 32] {
|
||||||
self.0.cv_net().to_bytes()
|
self.0.cv_net().to_bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nullifier(&self) -> [u8; 32] {
|
pub(crate) fn nullifier(&self) -> [u8; 32] {
|
||||||
self.0.nullifier().to_bytes()
|
self.0.nullifier().to_bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rk(&self) -> [u8; 32] {
|
pub(crate) fn rk(&self) -> [u8; 32] {
|
||||||
self.0.rk().into()
|
self.0.rk().into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cmx(&self) -> [u8; 32] {
|
pub(crate) fn cmx(&self) -> [u8; 32] {
|
||||||
self.0.cmx().to_bytes()
|
self.0.cmx().to_bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ephemeral_key(&self) -> [u8; 32] {
|
pub(crate) fn ephemeral_key(&self) -> [u8; 32] {
|
||||||
self.0.encrypted_note().epk_bytes
|
self.0.encrypted_note().epk_bytes
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enc_ciphertext(&self) -> [u8; 580] {
|
pub(crate) fn enc_ciphertext(&self) -> [u8; 580] {
|
||||||
self.0.encrypted_note().enc_ciphertext
|
self.0.encrypted_note().enc_ciphertext
|
||||||
}
|
}
|
||||||
|
|
||||||
fn out_ciphertext(&self) -> [u8; 80] {
|
pub(crate) fn out_ciphertext(&self) -> [u8; 80] {
|
||||||
self.0.encrypted_note().out_ciphertext
|
self.0.encrypted_note().out_ciphertext
|
||||||
}
|
}
|
||||||
|
|
||||||
fn spend_auth_sig(&self) -> [u8; 64] {
|
pub(crate) fn spend_auth_sig(&self) -> [u8; 64] {
|
||||||
self.0.authorization().into()
|
self.0.authorization().into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Bundle(Option<orchard::Bundle<Authorized, Amount>>);
|
pub struct Bundle(Option<orchard::Bundle<Authorized, Amount>>);
|
||||||
pub struct OrchardBundle;
|
pub struct OrchardBundle;
|
||||||
unsafe fn from_tx_bundle(bundle: *const OrchardBundle) -> Box<Bundle> {
|
pub(crate) unsafe fn from_tx_bundle(bundle: *const OrchardBundle) -> Box<Bundle> {
|
||||||
Box::new(Bundle(
|
Box::new(Bundle(
|
||||||
{ (bundle as *const orchard::Bundle<Authorized, Amount>).as_ref() }.cloned(),
|
{ (bundle as *const orchard::Bundle<Authorized, Amount>).as_ref() }.cloned(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Bundle {
|
impl Bundle {
|
||||||
fn actions(&self) -> Vec<Action> {
|
pub(crate) fn inner(&self) -> Option<&orchard::Bundle<Authorized, Amount>> {
|
||||||
|
self.0.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn actions(&self) -> Vec<Action> {
|
||||||
self.0
|
self.0
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|b| b.actions().iter())
|
.flat_map(|b| b.actions().iter())
|
||||||
|
@ -86,42 +62,35 @@ impl Bundle {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn num_actions(&self) -> usize {
|
pub(crate) fn num_actions(&self) -> usize {
|
||||||
self.0.as_ref().map(|b| b.actions().len()).unwrap_or(0)
|
self.inner().map(|b| b.actions().len()).unwrap_or(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enable_spends(&self) -> bool {
|
pub(crate) fn enable_spends(&self) -> bool {
|
||||||
self.0
|
self.inner()
|
||||||
.as_ref()
|
|
||||||
.map(|b| b.flags().spends_enabled())
|
.map(|b| b.flags().spends_enabled())
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enable_outputs(&self) -> bool {
|
pub(crate) fn enable_outputs(&self) -> bool {
|
||||||
self.0
|
self.inner()
|
||||||
.as_ref()
|
|
||||||
.map(|b| b.flags().outputs_enabled())
|
.map(|b| b.flags().outputs_enabled())
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn value_balance_zat(&self) -> i64 {
|
pub(crate) fn value_balance_zat(&self) -> i64 {
|
||||||
self.0
|
self.inner().map(|b| b.value_balance().into()).unwrap_or(0)
|
||||||
.as_ref()
|
|
||||||
.map(|b| b.value_balance().into())
|
|
||||||
.unwrap_or(0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn anchor(&self) -> [u8; 32] {
|
pub(crate) fn anchor(&self) -> [u8; 32] {
|
||||||
self.0
|
self.inner()
|
||||||
.as_ref()
|
|
||||||
.expect("Bundle actions should have been checked to be non-empty")
|
.expect("Bundle actions should have been checked to be non-empty")
|
||||||
.anchor()
|
.anchor()
|
||||||
.to_bytes()
|
.to_bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn proof(&self) -> Vec<u8> {
|
pub(crate) fn proof(&self) -> Vec<u8> {
|
||||||
self.0
|
self.inner()
|
||||||
.as_ref()
|
|
||||||
.expect("Bundle actions should have been checked to be non-empty")
|
.expect("Bundle actions should have been checked to be non-empty")
|
||||||
.authorization()
|
.authorization()
|
||||||
.proof()
|
.proof()
|
||||||
|
@ -129,9 +98,8 @@ impl Bundle {
|
||||||
.to_vec()
|
.to_vec()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn binding_sig(&self) -> [u8; 64] {
|
pub(crate) fn binding_sig(&self) -> [u8; 64] {
|
||||||
self.0
|
self.inner()
|
||||||
.as_ref()
|
|
||||||
.expect("Bundle actions should have been checked to be non-empty")
|
.expect("Bundle actions should have been checked to be non-empty")
|
||||||
.authorization()
|
.authorization()
|
||||||
.binding_signature()
|
.binding_signature()
|
||||||
|
|
|
@ -70,6 +70,8 @@ mod streams_ffi;
|
||||||
mod tracing_ffi;
|
mod tracing_ffi;
|
||||||
mod zcashd_orchard;
|
mod zcashd_orchard;
|
||||||
|
|
||||||
|
mod bridge;
|
||||||
|
|
||||||
mod address_ffi;
|
mod address_ffi;
|
||||||
mod builder_ffi;
|
mod builder_ffi;
|
||||||
mod bundlecache;
|
mod bundlecache;
|
||||||
|
|
|
@ -36,106 +36,7 @@ use crate::bundlecache::{
|
||||||
sapling_bundle_validity_cache, sapling_bundle_validity_cache_mut, CacheEntries,
|
sapling_bundle_validity_cache, sapling_bundle_validity_cache_mut, CacheEntries,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cxx::bridge(namespace = "sapling")]
|
pub(crate) struct Bundle(sapling::Bundle<sapling::Authorized>);
|
||||||
mod ffi {
|
|
||||||
extern "Rust" {
|
|
||||||
type Bundle;
|
|
||||||
type BundleAssembler;
|
|
||||||
fn new_bundle_assembler() -> Box<BundleAssembler>;
|
|
||||||
fn add_spend(
|
|
||||||
self: &mut BundleAssembler,
|
|
||||||
cv: &[u8; 32],
|
|
||||||
anchor: &[u8; 32],
|
|
||||||
nullifier: [u8; 32],
|
|
||||||
rk: &[u8; 32],
|
|
||||||
zkproof: [u8; 192], // GROTH_PROOF_SIZE
|
|
||||||
spend_auth_sig: &[u8; 64],
|
|
||||||
) -> bool;
|
|
||||||
fn add_output(
|
|
||||||
self: &mut BundleAssembler,
|
|
||||||
cv: &[u8; 32],
|
|
||||||
cmu: &[u8; 32],
|
|
||||||
ephemeral_key: [u8; 32],
|
|
||||||
enc_ciphertext: [u8; 580],
|
|
||||||
out_ciphertext: [u8; 80],
|
|
||||||
zkproof: [u8; 192], // GROTH_PROOF_SIZE
|
|
||||||
) -> bool;
|
|
||||||
fn finish_bundle_assembly(
|
|
||||||
assembler: Box<BundleAssembler>,
|
|
||||||
value_balance: i64,
|
|
||||||
binding_sig: [u8; 64],
|
|
||||||
) -> Box<Bundle>;
|
|
||||||
|
|
||||||
type Prover;
|
|
||||||
|
|
||||||
fn init_prover() -> Box<Prover>;
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
|
||||||
fn create_spend_proof(
|
|
||||||
self: &mut Prover,
|
|
||||||
ak: &[u8; 32],
|
|
||||||
nsk: &[u8; 32],
|
|
||||||
diversifier: &[u8; 11],
|
|
||||||
rcm: &[u8; 32],
|
|
||||||
ar: &[u8; 32],
|
|
||||||
value: u64,
|
|
||||||
anchor: &[u8; 32],
|
|
||||||
merkle_path: &[u8; 1065], // 1 + 33 * SAPLING_TREE_DEPTH + 8
|
|
||||||
cv: &mut [u8; 32],
|
|
||||||
rk_out: &mut [u8; 32],
|
|
||||||
zkproof: &mut [u8; 192], // GROTH_PROOF_SIZE
|
|
||||||
) -> bool;
|
|
||||||
fn create_output_proof(
|
|
||||||
self: &mut Prover,
|
|
||||||
esk: &[u8; 32],
|
|
||||||
payment_address: &[u8; 43],
|
|
||||||
rcm: &[u8; 32],
|
|
||||||
value: u64,
|
|
||||||
cv: &mut [u8; 32],
|
|
||||||
zkproof: &mut [u8; 192], // GROTH_PROOF_SIZE
|
|
||||||
) -> bool;
|
|
||||||
fn binding_sig(
|
|
||||||
self: &mut Prover,
|
|
||||||
value_balance: i64,
|
|
||||||
sighash: &[u8; 32],
|
|
||||||
result: &mut [u8; 64],
|
|
||||||
) -> bool;
|
|
||||||
|
|
||||||
type Verifier;
|
|
||||||
|
|
||||||
fn init_verifier() -> Box<Verifier>;
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
|
||||||
fn check_spend(
|
|
||||||
self: &mut Verifier,
|
|
||||||
cv: &[u8; 32],
|
|
||||||
anchor: &[u8; 32],
|
|
||||||
nullifier: &[u8; 32],
|
|
||||||
rk: &[u8; 32],
|
|
||||||
zkproof: &[u8; 192], // GROTH_PROOF_SIZE
|
|
||||||
spend_auth_sig: &[u8; 64],
|
|
||||||
sighash_value: &[u8; 32],
|
|
||||||
) -> bool;
|
|
||||||
fn check_output(
|
|
||||||
self: &mut Verifier,
|
|
||||||
cv: &[u8; 32],
|
|
||||||
cm: &[u8; 32],
|
|
||||||
ephemeral_key: &[u8; 32],
|
|
||||||
zkproof: &[u8; 192], // GROTH_PROOF_SIZE
|
|
||||||
) -> bool;
|
|
||||||
fn final_check(
|
|
||||||
self: &Verifier,
|
|
||||||
value_balance: i64,
|
|
||||||
binding_sig: &[u8; 64],
|
|
||||||
sighash_value: &[u8; 32],
|
|
||||||
) -> bool;
|
|
||||||
|
|
||||||
type BatchValidator;
|
|
||||||
fn init_batch_validator(cache_store: bool) -> Box<BatchValidator>;
|
|
||||||
fn check_bundle(self: &mut BatchValidator, bundle: Box<Bundle>, sighash: [u8; 32]) -> bool;
|
|
||||||
fn validate(self: &mut BatchValidator) -> bool;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Bundle(sapling::Bundle<sapling::Authorized>);
|
|
||||||
|
|
||||||
impl Bundle {
|
impl Bundle {
|
||||||
fn commitment<D: TransactionDigest<Authorized>>(&self, digester: D) -> D::SaplingDigest {
|
fn commitment<D: TransactionDigest<Authorized>>(&self, digester: D) -> D::SaplingDigest {
|
||||||
|
@ -143,12 +44,12 @@ impl Bundle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct BundleAssembler {
|
pub(crate) struct BundleAssembler {
|
||||||
shielded_spends: Vec<sapling::SpendDescription<sapling::Authorized>>,
|
shielded_spends: Vec<sapling::SpendDescription<sapling::Authorized>>,
|
||||||
shielded_outputs: Vec<sapling::OutputDescription<[u8; 192]>>, // GROTH_PROOF_SIZE
|
shielded_outputs: Vec<sapling::OutputDescription<[u8; 192]>>, // GROTH_PROOF_SIZE
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_bundle_assembler() -> Box<BundleAssembler> {
|
pub(crate) fn new_bundle_assembler() -> Box<BundleAssembler> {
|
||||||
Box::new(BundleAssembler {
|
Box::new(BundleAssembler {
|
||||||
shielded_spends: vec![],
|
shielded_spends: vec![],
|
||||||
shielded_outputs: vec![],
|
shielded_outputs: vec![],
|
||||||
|
@ -156,7 +57,7 @@ fn new_bundle_assembler() -> Box<BundleAssembler> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BundleAssembler {
|
impl BundleAssembler {
|
||||||
fn add_spend(
|
pub(crate) fn add_spend(
|
||||||
self: &mut BundleAssembler,
|
self: &mut BundleAssembler,
|
||||||
cv: &[u8; 32],
|
cv: &[u8; 32],
|
||||||
anchor: &[u8; 32],
|
anchor: &[u8; 32],
|
||||||
|
@ -203,7 +104,7 @@ impl BundleAssembler {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_output(
|
pub(crate) fn add_output(
|
||||||
self: &mut BundleAssembler,
|
self: &mut BundleAssembler,
|
||||||
cv: &[u8; 32],
|
cv: &[u8; 32],
|
||||||
cm: &[u8; 32],
|
cm: &[u8; 32],
|
||||||
|
@ -239,7 +140,7 @@ impl BundleAssembler {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::boxed_local)]
|
#[allow(clippy::boxed_local)]
|
||||||
fn finish_bundle_assembly(
|
pub(crate) fn finish_bundle_assembly(
|
||||||
assembler: Box<BundleAssembler>,
|
assembler: Box<BundleAssembler>,
|
||||||
value_balance: i64,
|
value_balance: i64,
|
||||||
binding_sig: [u8; 64],
|
binding_sig: [u8; 64],
|
||||||
|
@ -255,15 +156,15 @@ fn finish_bundle_assembly(
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Prover(SaplingProvingContext);
|
pub(crate) struct Prover(SaplingProvingContext);
|
||||||
|
|
||||||
fn init_prover() -> Box<Prover> {
|
pub(crate) fn init_prover() -> Box<Prover> {
|
||||||
Box::new(Prover(SaplingProvingContext::new()))
|
Box::new(Prover(SaplingProvingContext::new()))
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Prover {
|
impl Prover {
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn create_spend_proof(
|
pub(crate) fn create_spend_proof(
|
||||||
&mut self,
|
&mut self,
|
||||||
ak: &[u8; 32],
|
ak: &[u8; 32],
|
||||||
nsk: &[u8; 32],
|
nsk: &[u8; 32],
|
||||||
|
@ -361,7 +262,8 @@ impl Prover {
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
fn create_output_proof(
|
|
||||||
|
pub(crate) fn create_output_proof(
|
||||||
&mut self,
|
&mut self,
|
||||||
esk: &[u8; 32],
|
esk: &[u8; 32],
|
||||||
payment_address: &[u8; 43],
|
payment_address: &[u8; 43],
|
||||||
|
@ -409,7 +311,8 @@ impl Prover {
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
fn binding_sig(
|
|
||||||
|
pub(crate) fn binding_sig(
|
||||||
&mut self,
|
&mut self,
|
||||||
value_balance: i64,
|
value_balance: i64,
|
||||||
sighash: &[u8; 32],
|
sighash: &[u8; 32],
|
||||||
|
@ -434,9 +337,9 @@ impl Prover {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Verifier(SaplingVerificationContext);
|
pub(crate) struct Verifier(SaplingVerificationContext);
|
||||||
|
|
||||||
fn init_verifier() -> Box<Verifier> {
|
pub(crate) fn init_verifier() -> Box<Verifier> {
|
||||||
// We consider ZIP 216 active all of the time because blocks prior to NU5
|
// We consider ZIP 216 active all of the time because blocks prior to NU5
|
||||||
// activation (on mainnet and testnet) did not contain Sapling transactions
|
// activation (on mainnet and testnet) did not contain Sapling transactions
|
||||||
// that violated its canonicity rule.
|
// that violated its canonicity rule.
|
||||||
|
@ -445,7 +348,7 @@ fn init_verifier() -> Box<Verifier> {
|
||||||
|
|
||||||
impl Verifier {
|
impl Verifier {
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn check_spend(
|
pub(crate) fn check_spend(
|
||||||
&mut self,
|
&mut self,
|
||||||
cv: &[u8; 32],
|
cv: &[u8; 32],
|
||||||
anchor: &[u8; 32],
|
anchor: &[u8; 32],
|
||||||
|
@ -500,7 +403,8 @@ impl Verifier {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
fn check_output(
|
|
||||||
|
pub(crate) fn check_output(
|
||||||
&mut self,
|
&mut self,
|
||||||
cv: &[u8; 32],
|
cv: &[u8; 32],
|
||||||
cm: &[u8; 32],
|
cm: &[u8; 32],
|
||||||
|
@ -543,7 +447,8 @@ impl Verifier {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
fn final_check(
|
|
||||||
|
pub(crate) fn final_check(
|
||||||
&self,
|
&self,
|
||||||
value_balance: i64,
|
value_balance: i64,
|
||||||
binding_sig: &[u8; 64],
|
binding_sig: &[u8; 64],
|
||||||
|
@ -570,9 +475,9 @@ struct BatchValidatorInner {
|
||||||
queued_entries: CacheEntries,
|
queued_entries: CacheEntries,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct BatchValidator(Option<BatchValidatorInner>);
|
pub(crate) struct BatchValidator(Option<BatchValidatorInner>);
|
||||||
|
|
||||||
fn init_batch_validator(cache_store: bool) -> Box<BatchValidator> {
|
pub(crate) fn init_batch_validator(cache_store: bool) -> Box<BatchValidator> {
|
||||||
Box::new(BatchValidator(Some(BatchValidatorInner {
|
Box::new(BatchValidator(Some(BatchValidatorInner {
|
||||||
validator: sapling_proofs::BatchValidator::new(),
|
validator: sapling_proofs::BatchValidator::new(),
|
||||||
queued_entries: CacheEntries::new(cache_store),
|
queued_entries: CacheEntries::new(cache_store),
|
||||||
|
@ -594,7 +499,7 @@ impl BatchValidator {
|
||||||
/// the global bundle validity cache, it will have been removed (and this method will
|
/// the global bundle validity cache, it will have been removed (and this method will
|
||||||
/// return `true`).
|
/// return `true`).
|
||||||
#[allow(clippy::boxed_local)]
|
#[allow(clippy::boxed_local)]
|
||||||
fn check_bundle(&mut self, bundle: Box<Bundle>, sighash: [u8; 32]) -> bool {
|
pub(crate) fn check_bundle(&mut self, bundle: Box<Bundle>, sighash: [u8; 32]) -> bool {
|
||||||
if let Some(inner) = &mut self.0 {
|
if let Some(inner) = &mut self.0 {
|
||||||
let cache = sapling_bundle_validity_cache();
|
let cache = sapling_bundle_validity_cache();
|
||||||
|
|
||||||
|
@ -637,7 +542,7 @@ impl BatchValidator {
|
||||||
/// If this batch was configured to cache the results, then if this method returns
|
/// If this batch was configured to cache the results, then if this method returns
|
||||||
/// `true` every bundle added to the batch will have also been added to the global
|
/// `true` every bundle added to the batch will have also been added to the global
|
||||||
/// bundle validity cache.
|
/// bundle validity cache.
|
||||||
fn validate(&mut self) -> bool {
|
pub(crate) fn validate(&mut self) -> bool {
|
||||||
if let Some(inner) = self.0.take() {
|
if let Some(inner) = self.0.take() {
|
||||||
if inner.validator.validate(
|
if inner.validator.validate(
|
||||||
unsafe { SAPLING_SPEND_VK.as_ref() }
|
unsafe { SAPLING_SPEND_VK.as_ref() }
|
||||||
|
|
|
@ -21,95 +21,7 @@ use zcash_primitives::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{bridge::ffi, note_encryption::parse_and_prepare_sapling_ivk, params::Network};
|
||||||
note_encryption::{
|
|
||||||
parse_and_prepare_sapling_ivk, try_sapling_note_decryption, try_sapling_output_recovery,
|
|
||||||
DecryptedSaplingOutput,
|
|
||||||
},
|
|
||||||
params::{network, Network},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[cxx::bridge]
|
|
||||||
pub(crate) mod ffi {
|
|
||||||
#[namespace = "wallet"]
|
|
||||||
pub(crate) struct SaplingShieldedOutput {
|
|
||||||
cv: [u8; 32],
|
|
||||||
cmu: [u8; 32],
|
|
||||||
ephemeral_key: [u8; 32],
|
|
||||||
enc_ciphertext: [u8; 580],
|
|
||||||
out_ciphertext: [u8; 80],
|
|
||||||
}
|
|
||||||
|
|
||||||
#[namespace = "wallet"]
|
|
||||||
struct SaplingDecryptionResult {
|
|
||||||
txid: [u8; 32],
|
|
||||||
output: u32,
|
|
||||||
ivk: [u8; 32],
|
|
||||||
diversifier: [u8; 11],
|
|
||||||
pk_d: [u8; 32],
|
|
||||||
}
|
|
||||||
|
|
||||||
#[namespace = "consensus"]
|
|
||||||
extern "Rust" {
|
|
||||||
type Network;
|
|
||||||
|
|
||||||
fn network(
|
|
||||||
network: &str,
|
|
||||||
overwinter: i32,
|
|
||||||
sapling: i32,
|
|
||||||
blossom: i32,
|
|
||||||
heartwood: i32,
|
|
||||||
canopy: i32,
|
|
||||||
nu5: i32,
|
|
||||||
) -> Result<Box<Network>>;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[namespace = "wallet"]
|
|
||||||
extern "Rust" {
|
|
||||||
fn try_sapling_note_decryption(
|
|
||||||
network: &Network,
|
|
||||||
height: u32,
|
|
||||||
raw_ivk: &[u8; 32],
|
|
||||||
output: SaplingShieldedOutput,
|
|
||||||
) -> Result<Box<DecryptedSaplingOutput>>;
|
|
||||||
fn try_sapling_output_recovery(
|
|
||||||
network: &Network,
|
|
||||||
height: u32,
|
|
||||||
ovk: [u8; 32],
|
|
||||||
output: SaplingShieldedOutput,
|
|
||||||
) -> Result<Box<DecryptedSaplingOutput>>;
|
|
||||||
|
|
||||||
type DecryptedSaplingOutput;
|
|
||||||
fn note_value(self: &DecryptedSaplingOutput) -> u64;
|
|
||||||
fn note_rseed(self: &DecryptedSaplingOutput) -> [u8; 32];
|
|
||||||
fn zip_212_enabled(self: &DecryptedSaplingOutput) -> bool;
|
|
||||||
fn recipient_d(self: &DecryptedSaplingOutput) -> [u8; 11];
|
|
||||||
fn recipient_pk_d(self: &DecryptedSaplingOutput) -> [u8; 32];
|
|
||||||
fn memo(self: &DecryptedSaplingOutput) -> [u8; 512];
|
|
||||||
|
|
||||||
type BatchScanner;
|
|
||||||
type BatchResult;
|
|
||||||
|
|
||||||
fn init_batch_scanner(
|
|
||||||
network: &Network,
|
|
||||||
sapling_ivks: &[[u8; 32]],
|
|
||||||
) -> Result<Box<BatchScanner>>;
|
|
||||||
fn add_transaction(
|
|
||||||
self: &mut BatchScanner,
|
|
||||||
block_tag: [u8; 32],
|
|
||||||
tx_bytes: &[u8],
|
|
||||||
height: u32,
|
|
||||||
) -> Result<()>;
|
|
||||||
fn flush(self: &mut BatchScanner);
|
|
||||||
fn collect_results(
|
|
||||||
self: &mut BatchScanner,
|
|
||||||
block_tag: [u8; 32],
|
|
||||||
txid: [u8; 32],
|
|
||||||
) -> Box<BatchResult>;
|
|
||||||
|
|
||||||
fn get_sapling(self: &BatchResult) -> Vec<SaplingDecryptionResult>;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The minimum number of outputs to trial decrypt in a batch.
|
/// The minimum number of outputs to trial decrypt in a batch.
|
||||||
///
|
///
|
||||||
|
@ -641,7 +553,7 @@ type SaplingRunner =
|
||||||
BatchRunner<[u8; 32], SaplingDomain<Network>, OutputDescription<GrothProofBytes>, WithUsage>;
|
BatchRunner<[u8; 32], SaplingDomain<Network>, OutputDescription<GrothProofBytes>, WithUsage>;
|
||||||
|
|
||||||
/// A batch scanner for the `zcashd` wallet.
|
/// A batch scanner for the `zcashd` wallet.
|
||||||
struct BatchScanner {
|
pub(crate) struct BatchScanner {
|
||||||
params: Network,
|
params: Network,
|
||||||
sapling_runner: Option<SaplingRunner>,
|
sapling_runner: Option<SaplingRunner>,
|
||||||
}
|
}
|
||||||
|
@ -656,7 +568,7 @@ impl DynamicUsage for BatchScanner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_batch_scanner(
|
pub(crate) fn init_batch_scanner(
|
||||||
network: &Network,
|
network: &Network,
|
||||||
sapling_ivks: &[[u8; 32]],
|
sapling_ivks: &[[u8; 32]],
|
||||||
) -> Result<Box<BatchScanner>, &'static str> {
|
) -> Result<Box<BatchScanner>, &'static str> {
|
||||||
|
@ -690,7 +602,7 @@ impl BatchScanner {
|
||||||
/// After adding the outputs, any accumulated batch of sufficient size is run on the
|
/// After adding the outputs, any accumulated batch of sufficient size is run on the
|
||||||
/// global threadpool. Subsequent calls to `Self::add_transaction` will accumulate
|
/// global threadpool. Subsequent calls to `Self::add_transaction` will accumulate
|
||||||
/// those output kinds into new batches.
|
/// those output kinds into new batches.
|
||||||
fn add_transaction(
|
pub(crate) fn add_transaction(
|
||||||
&mut self,
|
&mut self,
|
||||||
block_tag: [u8; 32],
|
block_tag: [u8; 32],
|
||||||
tx_bytes: &[u8],
|
tx_bytes: &[u8],
|
||||||
|
@ -724,7 +636,7 @@ impl BatchScanner {
|
||||||
/// Runs the currently accumulated batches on the global threadpool.
|
/// Runs the currently accumulated batches on the global threadpool.
|
||||||
///
|
///
|
||||||
/// Subsequent calls to `Self::add_transaction` will be accumulated into new batches.
|
/// Subsequent calls to `Self::add_transaction` will be accumulated into new batches.
|
||||||
fn flush(&mut self) {
|
pub(crate) fn flush(&mut self) {
|
||||||
if let Some(runner) = &mut self.sapling_runner {
|
if let Some(runner) = &mut self.sapling_runner {
|
||||||
runner.flush();
|
runner.flush();
|
||||||
}
|
}
|
||||||
|
@ -737,7 +649,11 @@ impl BatchScanner {
|
||||||
/// mempool change).
|
/// mempool change).
|
||||||
///
|
///
|
||||||
/// TODO: Return the `HashMap`s directly once `cxx` supports it.
|
/// TODO: Return the `HashMap`s directly once `cxx` supports it.
|
||||||
fn collect_results(&mut self, block_tag: [u8; 32], txid: [u8; 32]) -> Box<BatchResult> {
|
pub(crate) fn collect_results(
|
||||||
|
&mut self,
|
||||||
|
block_tag: [u8; 32],
|
||||||
|
txid: [u8; 32],
|
||||||
|
) -> Box<BatchResult> {
|
||||||
let block_tag = BlockHash(block_tag);
|
let block_tag = BlockHash(block_tag);
|
||||||
let txid = TxId::from_bytes(txid);
|
let txid = TxId::from_bytes(txid);
|
||||||
|
|
||||||
|
@ -754,12 +670,12 @@ impl BatchScanner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct BatchResult {
|
pub(crate) struct BatchResult {
|
||||||
sapling: HashMap<(TxId, usize), DecryptedNote<[u8; 32], SaplingDomain<Network>>>,
|
sapling: HashMap<(TxId, usize), DecryptedNote<[u8; 32], SaplingDomain<Network>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BatchResult {
|
impl BatchResult {
|
||||||
fn get_sapling(&self) -> Vec<ffi::SaplingDecryptionResult> {
|
pub(crate) fn get_sapling(&self) -> Vec<ffi::SaplingDecryptionResult> {
|
||||||
self.sapling
|
self.sapling
|
||||||
.iter()
|
.iter()
|
||||||
.map(
|
.map(
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
|
|
||||||
#include "librustzcash.h"
|
#include "librustzcash.h"
|
||||||
|
|
||||||
#include <rust/bundlecache.h>
|
#include <rust/bridge.h>
|
||||||
|
|
||||||
const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr;
|
const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr;
|
||||||
|
|
||||||
|
|
|
@ -35,8 +35,8 @@
|
||||||
#include <boost/test/unit_test.hpp>
|
#include <boost/test/unit_test.hpp>
|
||||||
#include <boost/test/data/test_case.hpp>
|
#include <boost/test/data/test_case.hpp>
|
||||||
|
|
||||||
|
#include <rust/bridge.h>
|
||||||
#include <rust/ed25519.h>
|
#include <rust/ed25519.h>
|
||||||
#include <rust/sapling.h>
|
|
||||||
#include <rust/orchard.h>
|
#include <rust/orchard.h>
|
||||||
|
|
||||||
#include <univalue.h>
|
#include <univalue.h>
|
||||||
|
|
|
@ -22,8 +22,8 @@
|
||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
|
#include <rust/bridge.h>
|
||||||
#include <rust/builder.h>
|
#include <rust/builder.h>
|
||||||
#include <rust/sapling.h>
|
|
||||||
|
|
||||||
#define NO_MEMO {{0xF6}}
|
#define NO_MEMO {{0xF6}}
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,7 @@
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <rust/wallet_scanner.h>
|
#include <rust/bridge.h>
|
||||||
|
|
||||||
#include <boost/shared_ptr.hpp>
|
#include <boost/shared_ptr.hpp>
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
#include "zcash/util.h"
|
#include "zcash/util.h"
|
||||||
|
|
||||||
#include <primitives/orchard.h>
|
#include <primitives/orchard.h>
|
||||||
#include <rust/merkle_frontier.h>
|
#include <rust/bridge.h>
|
||||||
|
|
||||||
namespace libzcash {
|
namespace libzcash {
|
||||||
|
|
||||||
|
@ -316,8 +316,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AppendBundle(const OrchardBundle& bundle) {
|
bool AppendBundle(const OrchardBundle& bundle) {
|
||||||
return inner->append_bundle(
|
return inner->append_bundle(*bundle.GetDetails());
|
||||||
reinterpret_cast<merkle_frontier::OrchardBundle*>(bundle.inner.get()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint256 root() const {
|
const uint256 root() const {
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
#include <rust/wallet_scanner.h>
|
#include <rust/bridge.h>
|
||||||
|
|
||||||
namespace libzcash {
|
namespace libzcash {
|
||||||
|
|
||||||
|
|
|
@ -35,8 +35,8 @@
|
||||||
#include "zcash/Note.hpp"
|
#include "zcash/Note.hpp"
|
||||||
#include "librustzcash.h"
|
#include "librustzcash.h"
|
||||||
|
|
||||||
|
#include <rust/bridge.h>
|
||||||
#include <rust/ed25519/types.h>
|
#include <rust/ed25519/types.h>
|
||||||
#include <rust/sapling.h>
|
|
||||||
|
|
||||||
using namespace libzcash;
|
using namespace libzcash;
|
||||||
// This method is based on Shutdown from init.cpp
|
// This method is based on Shutdown from init.cpp
|
||||||
|
|
Loading…
Reference in New Issue