Pass height to methods which encrypt or decrypt Sapling outputs
This commit is contained in:
parent
71d31abad6
commit
b537f0f712
|
@ -1,5 +1,6 @@
|
||||||
use pairing::bls12_381::Bls12;
|
use pairing::bls12_381::Bls12;
|
||||||
use zcash_primitives::{
|
use zcash_primitives::{
|
||||||
|
consensus,
|
||||||
note_encryption::{try_sapling_note_decryption, try_sapling_output_recovery, Memo},
|
note_encryption::{try_sapling_note_decryption, try_sapling_output_recovery, Memo},
|
||||||
primitives::{Note, PaymentAddress},
|
primitives::{Note, PaymentAddress},
|
||||||
transaction::Transaction,
|
transaction::Transaction,
|
||||||
|
@ -30,7 +31,8 @@ pub struct DecryptedOutput {
|
||||||
|
|
||||||
/// Scans a [`Transaction`] for any information that can be decrypted by the set of
|
/// Scans a [`Transaction`] for any information that can be decrypted by the set of
|
||||||
/// [`ExtendedFullViewingKey`]s.
|
/// [`ExtendedFullViewingKey`]s.
|
||||||
pub fn decrypt_transaction(
|
pub fn decrypt_transaction<P: consensus::Parameters>(
|
||||||
|
parameters: &P,
|
||||||
tx: &Transaction,
|
tx: &Transaction,
|
||||||
extfvks: &[ExtendedFullViewingKey],
|
extfvks: &[ExtendedFullViewingKey],
|
||||||
) -> Vec<DecryptedOutput> {
|
) -> Vec<DecryptedOutput> {
|
||||||
|
@ -49,21 +51,29 @@ pub fn decrypt_transaction(
|
||||||
};
|
};
|
||||||
|
|
||||||
for (account, (ivk, ovk)) in vks.iter().enumerate() {
|
for (account, (ivk, ovk)) in vks.iter().enumerate() {
|
||||||
let ((note, to, memo), outgoing) =
|
let ((note, to, memo), outgoing) = match try_sapling_note_decryption(
|
||||||
match try_sapling_note_decryption(ivk, &epk, &output.cmu, &output.enc_ciphertext) {
|
parameters,
|
||||||
Some(ret) => (ret, false),
|
tx.expiry_height,
|
||||||
None => match try_sapling_output_recovery(
|
ivk,
|
||||||
ovk,
|
&epk,
|
||||||
&output.cv,
|
&output.cmu,
|
||||||
&output.cmu,
|
&output.enc_ciphertext,
|
||||||
&epk,
|
) {
|
||||||
&output.enc_ciphertext,
|
Some(ret) => (ret, false),
|
||||||
&output.out_ciphertext,
|
None => match try_sapling_output_recovery(
|
||||||
) {
|
parameters,
|
||||||
Some(ret) => (ret, true),
|
tx.expiry_height,
|
||||||
None => continue,
|
ovk,
|
||||||
},
|
&output.cv,
|
||||||
};
|
&output.cmu,
|
||||||
|
&epk,
|
||||||
|
&output.enc_ciphertext,
|
||||||
|
&output.out_ciphertext,
|
||||||
|
) {
|
||||||
|
Some(ret) => (ret, true),
|
||||||
|
None => continue,
|
||||||
|
},
|
||||||
|
};
|
||||||
decrypted.push(DecryptedOutput {
|
decrypted.push(DecryptedOutput {
|
||||||
index,
|
index,
|
||||||
note,
|
note,
|
||||||
|
|
|
@ -4,6 +4,7 @@ use ff::PrimeField;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use subtle::{ConditionallySelectable, ConstantTimeEq, CtOption};
|
use subtle::{ConditionallySelectable, ConstantTimeEq, CtOption};
|
||||||
use zcash_primitives::{
|
use zcash_primitives::{
|
||||||
|
consensus,
|
||||||
jubjub::fs::Fs,
|
jubjub::fs::Fs,
|
||||||
merkle_tree::{CommitmentTree, IncrementalWitness},
|
merkle_tree::{CommitmentTree, IncrementalWitness},
|
||||||
note_encryption::try_sapling_compact_note_decryption,
|
note_encryption::try_sapling_compact_note_decryption,
|
||||||
|
@ -22,7 +23,9 @@ use crate::wallet::{WalletShieldedOutput, WalletShieldedSpend, WalletTx};
|
||||||
///
|
///
|
||||||
/// The given [`CommitmentTree`] and existing [`IncrementalWitness`]es are incremented
|
/// The given [`CommitmentTree`] and existing [`IncrementalWitness`]es are incremented
|
||||||
/// with this output's commitment.
|
/// with this output's commitment.
|
||||||
fn scan_output(
|
fn scan_output<P: consensus::Parameters>(
|
||||||
|
parameters: &P,
|
||||||
|
height: u32,
|
||||||
(index, output): (usize, CompactOutput),
|
(index, output): (usize, CompactOutput),
|
||||||
ivks: &[Fs],
|
ivks: &[Fs],
|
||||||
spent_from_accounts: &HashSet<usize>,
|
spent_from_accounts: &HashSet<usize>,
|
||||||
|
@ -49,10 +52,11 @@ fn scan_output(
|
||||||
tree.append(node).unwrap();
|
tree.append(node).unwrap();
|
||||||
|
|
||||||
for (account, ivk) in ivks.iter().enumerate() {
|
for (account, ivk) in ivks.iter().enumerate() {
|
||||||
let (note, to) = match try_sapling_compact_note_decryption(ivk, &epk, &cmu, &ct) {
|
let (note, to) =
|
||||||
Some(ret) => ret,
|
match try_sapling_compact_note_decryption(parameters, height, ivk, &epk, &cmu, &ct) {
|
||||||
None => continue,
|
Some(ret) => ret,
|
||||||
};
|
None => continue,
|
||||||
|
};
|
||||||
|
|
||||||
// A note is marked as "change" if the account that received it
|
// A note is marked as "change" if the account that received it
|
||||||
// also spent notes in the same transaction. This will catch,
|
// also spent notes in the same transaction. This will catch,
|
||||||
|
@ -83,7 +87,8 @@ fn scan_output(
|
||||||
///
|
///
|
||||||
/// The given [`CommitmentTree`] and existing [`IncrementalWitness`]es are
|
/// The given [`CommitmentTree`] and existing [`IncrementalWitness`]es are
|
||||||
/// incremented appropriately.
|
/// incremented appropriately.
|
||||||
pub fn scan_block(
|
pub fn scan_block<P: consensus::Parameters>(
|
||||||
|
parameters: &P,
|
||||||
block: CompactBlock,
|
block: CompactBlock,
|
||||||
extfvks: &[ExtendedFullViewingKey],
|
extfvks: &[ExtendedFullViewingKey],
|
||||||
nullifiers: &[(&[u8], usize)],
|
nullifiers: &[(&[u8], usize)],
|
||||||
|
@ -151,6 +156,8 @@ pub fn scan_block(
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
if let Some(output) = scan_output(
|
if let Some(output) = scan_output(
|
||||||
|
parameters,
|
||||||
|
block.height as u32,
|
||||||
to_scan,
|
to_scan,
|
||||||
&ivks,
|
&ivks,
|
||||||
&spent_from_accounts,
|
&spent_from_accounts,
|
||||||
|
@ -187,6 +194,7 @@ mod tests {
|
||||||
use pairing::bls12_381::{Bls12, Fr};
|
use pairing::bls12_381::{Bls12, Fr};
|
||||||
use rand_core::{OsRng, RngCore};
|
use rand_core::{OsRng, RngCore};
|
||||||
use zcash_primitives::{
|
use zcash_primitives::{
|
||||||
|
consensus,
|
||||||
jubjub::{fs::Fs, FixedGenerators, JubjubParams, ToUniform},
|
jubjub::{fs::Fs, FixedGenerators, JubjubParams, ToUniform},
|
||||||
merkle_tree::CommitmentTree,
|
merkle_tree::CommitmentTree,
|
||||||
note_encryption::{Memo, SaplingNoteEncryption},
|
note_encryption::{Memo, SaplingNoteEncryption},
|
||||||
|
@ -318,7 +326,14 @@ mod tests {
|
||||||
assert_eq!(cb.vtx.len(), 2);
|
assert_eq!(cb.vtx.len(), 2);
|
||||||
|
|
||||||
let mut tree = CommitmentTree::new();
|
let mut tree = CommitmentTree::new();
|
||||||
let txs = scan_block(cb, &[extfvk], &[], &mut tree, &mut []);
|
let txs = scan_block(
|
||||||
|
&consensus::MainNetwork,
|
||||||
|
cb,
|
||||||
|
&[extfvk],
|
||||||
|
&[],
|
||||||
|
&mut tree,
|
||||||
|
&mut [],
|
||||||
|
);
|
||||||
assert_eq!(txs.len(), 1);
|
assert_eq!(txs.len(), 1);
|
||||||
|
|
||||||
let tx = &txs[0];
|
let tx = &txs[0];
|
||||||
|
@ -350,7 +365,14 @@ mod tests {
|
||||||
assert_eq!(cb.vtx.len(), 3);
|
assert_eq!(cb.vtx.len(), 3);
|
||||||
|
|
||||||
let mut tree = CommitmentTree::new();
|
let mut tree = CommitmentTree::new();
|
||||||
let txs = scan_block(cb, &[extfvk], &[], &mut tree, &mut []);
|
let txs = scan_block(
|
||||||
|
&consensus::MainNetwork,
|
||||||
|
cb,
|
||||||
|
&[extfvk],
|
||||||
|
&[],
|
||||||
|
&mut tree,
|
||||||
|
&mut [],
|
||||||
|
);
|
||||||
assert_eq!(txs.len(), 1);
|
assert_eq!(txs.len(), 1);
|
||||||
|
|
||||||
let tx = &txs[0];
|
let tx = &txs[0];
|
||||||
|
@ -378,7 +400,14 @@ mod tests {
|
||||||
assert_eq!(cb.vtx.len(), 2);
|
assert_eq!(cb.vtx.len(), 2);
|
||||||
|
|
||||||
let mut tree = CommitmentTree::new();
|
let mut tree = CommitmentTree::new();
|
||||||
let txs = scan_block(cb, &[], &[(&nf, account)], &mut tree, &mut []);
|
let txs = scan_block(
|
||||||
|
&consensus::MainNetwork,
|
||||||
|
cb,
|
||||||
|
&[],
|
||||||
|
&[(&nf, account)],
|
||||||
|
&mut tree,
|
||||||
|
&mut [],
|
||||||
|
);
|
||||||
assert_eq!(txs.len(), 1);
|
assert_eq!(txs.len(), 1);
|
||||||
|
|
||||||
let tx = &txs[0];
|
let tx = &txs[0];
|
||||||
|
|
|
@ -9,6 +9,7 @@ use zcash_client_backend::{
|
||||||
proto::compact_formats::CompactBlock, welding_rig::scan_block,
|
proto::compact_formats::CompactBlock, welding_rig::scan_block,
|
||||||
};
|
};
|
||||||
use zcash_primitives::{
|
use zcash_primitives::{
|
||||||
|
consensus,
|
||||||
merkle_tree::{CommitmentTree, IncrementalWitness},
|
merkle_tree::{CommitmentTree, IncrementalWitness},
|
||||||
sapling::Node,
|
sapling::Node,
|
||||||
transaction::Transaction,
|
transaction::Transaction,
|
||||||
|
@ -188,6 +189,7 @@ pub fn scan_cached_blocks<P: AsRef<Path>, Q: AsRef<Path>>(
|
||||||
let nf_refs: Vec<_> = nullifiers.iter().map(|(nf, acc)| (&nf[..], *acc)).collect();
|
let nf_refs: Vec<_> = nullifiers.iter().map(|(nf, acc)| (&nf[..], *acc)).collect();
|
||||||
let mut witness_refs: Vec<_> = witnesses.iter_mut().map(|w| &mut w.witness).collect();
|
let mut witness_refs: Vec<_> = witnesses.iter_mut().map(|w| &mut w.witness).collect();
|
||||||
scan_block(
|
scan_block(
|
||||||
|
&consensus::MainNetwork,
|
||||||
block,
|
block,
|
||||||
&extfvks[..],
|
&extfvks[..],
|
||||||
&nf_refs,
|
&nf_refs,
|
||||||
|
@ -372,7 +374,7 @@ pub fn decrypt_and_store_transaction<P: AsRef<Path>>(
|
||||||
.collect::<Result<Result<Option<_>, _>, _>>()??
|
.collect::<Result<Result<Option<_>, _>, _>>()??
|
||||||
.ok_or(Error(ErrorKind::IncorrectHRPExtFVK))?;
|
.ok_or(Error(ErrorKind::IncorrectHRPExtFVK))?;
|
||||||
|
|
||||||
let outputs = decrypt_transaction(tx, &extfvks);
|
let outputs = decrypt_transaction(&consensus::MainNetwork, tx, &extfvks);
|
||||||
|
|
||||||
if outputs.is_empty() {
|
if outputs.is_empty() {
|
||||||
// Nothing to see here
|
// Nothing to see here
|
||||||
|
|
|
@ -5,10 +5,10 @@ use std::fmt;
|
||||||
|
|
||||||
/// Zcash consensus parameters.
|
/// Zcash consensus parameters.
|
||||||
pub trait Parameters {
|
pub trait Parameters {
|
||||||
fn activation_height(nu: NetworkUpgrade) -> Option<u32>;
|
fn activation_height(&self, nu: NetworkUpgrade) -> Option<u32>;
|
||||||
|
|
||||||
fn is_nu_active(nu: NetworkUpgrade, height: u32) -> bool {
|
fn is_nu_active(&self, nu: NetworkUpgrade, height: u32) -> bool {
|
||||||
match Self::activation_height(nu) {
|
match self.activation_height(nu) {
|
||||||
Some(h) if h <= height => true,
|
Some(h) if h <= height => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ pub trait Parameters {
|
||||||
pub struct MainNetwork;
|
pub struct MainNetwork;
|
||||||
|
|
||||||
impl Parameters for MainNetwork {
|
impl Parameters for MainNetwork {
|
||||||
fn activation_height(nu: NetworkUpgrade) -> Option<u32> {
|
fn activation_height(&self, nu: NetworkUpgrade) -> Option<u32> {
|
||||||
match nu {
|
match nu {
|
||||||
NetworkUpgrade::Overwinter => Some(347_500),
|
NetworkUpgrade::Overwinter => Some(347_500),
|
||||||
NetworkUpgrade::Sapling => Some(419_200),
|
NetworkUpgrade::Sapling => Some(419_200),
|
||||||
|
@ -36,7 +36,7 @@ impl Parameters for MainNetwork {
|
||||||
pub struct TestNetwork;
|
pub struct TestNetwork;
|
||||||
|
|
||||||
impl Parameters for TestNetwork {
|
impl Parameters for TestNetwork {
|
||||||
fn activation_height(nu: NetworkUpgrade) -> Option<u32> {
|
fn activation_height(&self, nu: NetworkUpgrade) -> Option<u32> {
|
||||||
match nu {
|
match nu {
|
||||||
NetworkUpgrade::Overwinter => Some(207_500),
|
NetworkUpgrade::Overwinter => Some(207_500),
|
||||||
NetworkUpgrade::Sapling => Some(280_000),
|
NetworkUpgrade::Sapling => Some(280_000),
|
||||||
|
@ -174,9 +174,9 @@ impl BranchId {
|
||||||
/// the given height.
|
/// the given height.
|
||||||
///
|
///
|
||||||
/// This is the branch ID that should be used when creating transactions.
|
/// This is the branch ID that should be used when creating transactions.
|
||||||
pub fn for_height<C: Parameters>(height: u32) -> Self {
|
pub fn for_height<C: Parameters>(parameters: C, height: u32) -> Self {
|
||||||
for nu in UPGRADES_IN_ORDER.iter().rev() {
|
for nu in UPGRADES_IN_ORDER.iter().rev() {
|
||||||
if C::is_nu_active(*nu, height) {
|
if parameters.is_nu_active(*nu, height) {
|
||||||
return nu.branch_id();
|
return nu.branch_id();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
//! Implementation of in-band secret distribution for Zcash transactions.
|
//! Implementation of in-band secret distribution for Zcash transactions.
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
consensus,
|
||||||
|
consensus::NetworkUpgrade,
|
||||||
jubjub::{
|
jubjub::{
|
||||||
edwards,
|
edwards,
|
||||||
fs::{Fs, FsRepr},
|
fs::{Fs, FsRepr},
|
||||||
|
@ -335,7 +337,9 @@ impl SaplingNoteEncryption {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_note_plaintext_without_memo(
|
fn parse_note_plaintext_without_memo<P: consensus::Parameters>(
|
||||||
|
parameters: &P,
|
||||||
|
height: u32,
|
||||||
ivk: &Fs,
|
ivk: &Fs,
|
||||||
cmu: &Fr,
|
cmu: &Fr,
|
||||||
plaintext: &[u8],
|
plaintext: &[u8],
|
||||||
|
@ -380,7 +384,9 @@ fn parse_note_plaintext_without_memo(
|
||||||
/// `PaymentAddress` to which the note was sent.
|
/// `PaymentAddress` to which the note was sent.
|
||||||
///
|
///
|
||||||
/// Implements section 4.17.2 of the Zcash Protocol Specification.
|
/// Implements section 4.17.2 of the Zcash Protocol Specification.
|
||||||
pub fn try_sapling_note_decryption(
|
pub fn try_sapling_note_decryption<P: consensus::Parameters>(
|
||||||
|
parameters: &P,
|
||||||
|
height: u32,
|
||||||
ivk: &Fs,
|
ivk: &Fs,
|
||||||
epk: &edwards::Point<Bls12, PrimeOrder>,
|
epk: &edwards::Point<Bls12, PrimeOrder>,
|
||||||
cmu: &Fr,
|
cmu: &Fr,
|
||||||
|
@ -405,7 +411,7 @@ pub fn try_sapling_note_decryption(
|
||||||
NOTE_PLAINTEXT_SIZE
|
NOTE_PLAINTEXT_SIZE
|
||||||
);
|
);
|
||||||
|
|
||||||
let (note, to) = parse_note_plaintext_without_memo(ivk, cmu, &plaintext)?;
|
let (note, to) = parse_note_plaintext_without_memo(parameters, height, ivk, cmu, &plaintext)?;
|
||||||
|
|
||||||
let mut memo = [0u8; 512];
|
let mut memo = [0u8; 512];
|
||||||
memo.copy_from_slice(&plaintext[COMPACT_NOTE_SIZE..NOTE_PLAINTEXT_SIZE]);
|
memo.copy_from_slice(&plaintext[COMPACT_NOTE_SIZE..NOTE_PLAINTEXT_SIZE]);
|
||||||
|
@ -422,7 +428,9 @@ pub fn try_sapling_note_decryption(
|
||||||
/// Implements the procedure specified in [`ZIP 307`].
|
/// Implements the procedure specified in [`ZIP 307`].
|
||||||
///
|
///
|
||||||
/// [`ZIP 307`]: https://github.com/zcash/zips/pull/226
|
/// [`ZIP 307`]: https://github.com/zcash/zips/pull/226
|
||||||
pub fn try_sapling_compact_note_decryption(
|
pub fn try_sapling_compact_note_decryption<P: consensus::Parameters>(
|
||||||
|
parameters: &P,
|
||||||
|
height: u32,
|
||||||
ivk: &Fs,
|
ivk: &Fs,
|
||||||
epk: &edwards::Point<Bls12, PrimeOrder>,
|
epk: &edwards::Point<Bls12, PrimeOrder>,
|
||||||
cmu: &Fr,
|
cmu: &Fr,
|
||||||
|
@ -438,7 +446,7 @@ pub fn try_sapling_compact_note_decryption(
|
||||||
plaintext.copy_from_slice(&enc_ciphertext);
|
plaintext.copy_from_slice(&enc_ciphertext);
|
||||||
ChaCha20Ietf::xor(key.as_bytes(), &[0u8; 12], 1, &mut plaintext);
|
ChaCha20Ietf::xor(key.as_bytes(), &[0u8; 12], 1, &mut plaintext);
|
||||||
|
|
||||||
parse_note_plaintext_without_memo(ivk, cmu, &plaintext)
|
parse_note_plaintext_without_memo(parameters, height, ivk, cmu, &plaintext)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Recovery of the full note plaintext by the sender.
|
/// Recovery of the full note plaintext by the sender.
|
||||||
|
@ -448,7 +456,9 @@ pub fn try_sapling_compact_note_decryption(
|
||||||
/// `PaymentAddress` to which the note was sent.
|
/// `PaymentAddress` to which the note was sent.
|
||||||
///
|
///
|
||||||
/// Implements section 4.17.3 of the Zcash Protocol Specification.
|
/// Implements section 4.17.3 of the Zcash Protocol Specification.
|
||||||
pub fn try_sapling_output_recovery(
|
pub fn try_sapling_output_recovery<P: consensus::Parameters>(
|
||||||
|
parameters: &P,
|
||||||
|
height: u32,
|
||||||
ovk: &OutgoingViewingKey,
|
ovk: &OutgoingViewingKey,
|
||||||
cv: &edwards::Point<Bls12, Unknown>,
|
cv: &edwards::Point<Bls12, Unknown>,
|
||||||
cmu: &Fr,
|
cmu: &Fr,
|
||||||
|
@ -717,6 +727,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn random_enc_ciphertext_with<R: RngCore + CryptoRng>(
|
fn random_enc_ciphertext_with<R: RngCore + CryptoRng>(
|
||||||
|
height: u32,
|
||||||
ivk: Fs,
|
ivk: Fs,
|
||||||
mut rng: &mut R,
|
mut rng: &mut R,
|
||||||
) -> (
|
) -> (
|
||||||
|
|
|
@ -13,6 +13,7 @@ use std::fmt;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
consensus,
|
consensus,
|
||||||
|
consensus::NetworkUpgrade,
|
||||||
keys::OutgoingViewingKey,
|
keys::OutgoingViewingKey,
|
||||||
legacy::TransparentAddress,
|
legacy::TransparentAddress,
|
||||||
merkle_tree::MerklePath,
|
merkle_tree::MerklePath,
|
||||||
|
@ -86,7 +87,9 @@ pub struct SaplingOutput {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SaplingOutput {
|
impl SaplingOutput {
|
||||||
pub fn new<R: RngCore + CryptoRng>(
|
pub fn new<R: RngCore + CryptoRng, P: consensus::Parameters>(
|
||||||
|
parameters: P,
|
||||||
|
height: u32,
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
ovk: OutgoingViewingKey,
|
ovk: OutgoingViewingKey,
|
||||||
to: PaymentAddress<Bls12>,
|
to: PaymentAddress<Bls12>,
|
||||||
|
@ -304,6 +307,7 @@ impl TransactionMetadata {
|
||||||
/// Generates a [`Transaction`] from its inputs and outputs.
|
/// Generates a [`Transaction`] from its inputs and outputs.
|
||||||
pub struct Builder<R: RngCore + CryptoRng> {
|
pub struct Builder<R: RngCore + CryptoRng> {
|
||||||
rng: R,
|
rng: R,
|
||||||
|
height: u32,
|
||||||
mtx: TransactionData,
|
mtx: TransactionData,
|
||||||
fee: Amount,
|
fee: Amount,
|
||||||
anchor: Option<Fr>,
|
anchor: Option<Fr>,
|
||||||
|
@ -344,6 +348,7 @@ impl<R: RngCore + CryptoRng> Builder<R> {
|
||||||
|
|
||||||
Builder {
|
Builder {
|
||||||
rng,
|
rng,
|
||||||
|
height,
|
||||||
mtx,
|
mtx,
|
||||||
fee: DEFAULT_FEE,
|
fee: DEFAULT_FEE,
|
||||||
anchor: None,
|
anchor: None,
|
||||||
|
@ -399,7 +404,15 @@ impl<R: RngCore + CryptoRng> Builder<R> {
|
||||||
value: Amount,
|
value: Amount,
|
||||||
memo: Option<Memo>,
|
memo: Option<Memo>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let output = SaplingOutput::new(&mut self.rng, ovk, to, value, memo)?;
|
let output = SaplingOutput::new(
|
||||||
|
consensus::MainNetwork,
|
||||||
|
self.height,
|
||||||
|
&mut self.rng,
|
||||||
|
ovk,
|
||||||
|
to,
|
||||||
|
value,
|
||||||
|
memo,
|
||||||
|
)?;
|
||||||
|
|
||||||
self.mtx.value_balance -= value;
|
self.mtx.value_balance -= value;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue