Skip to content

Commit

Permalink
Merge pull request #985 from zcash/983-transparent-balance-fix
Browse files Browse the repository at this point in the history
`zcash_client_sqlite`: Fix transparent balance APIs
  • Loading branch information
str4d authored Sep 22, 2023
2 parents e817a75 + b76b028 commit f4fdba2
Show file tree
Hide file tree
Showing 5 changed files with 310 additions and 86 deletions.
2 changes: 1 addition & 1 deletion zcash_client_backend/src/data_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -490,7 +490,7 @@ impl<Nf> ScannedBlock<Nf> {
}

/// Returns the metadata describing the state of the note commitment trees as of the end of the
/// scanned block.
/// scanned block.
///
/// The metadata returned from this method is guaranteed to be consistent with what is returned
/// by [`Self::height`] and [`Self::block_hash`].
Expand Down
27 changes: 23 additions & 4 deletions zcash_client_backend/src/proto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,10 +116,8 @@ impl compact_formats::CompactSaplingOutput {
}
}

impl<A: sapling::Authorization> From<sapling::OutputDescription<A>>
for compact_formats::CompactSaplingOutput
{
fn from(out: sapling::OutputDescription<A>) -> compact_formats::CompactSaplingOutput {
impl<Proof> From<&sapling::OutputDescription<Proof>> for compact_formats::CompactSaplingOutput {
fn from(out: &sapling::OutputDescription<Proof>) -> compact_formats::CompactSaplingOutput {
compact_formats::CompactSaplingOutput {
cmu: out.cmu().to_bytes().to_vec(),
ephemeral_key: out.ephemeral_key().as_ref().to_vec(),
Expand All @@ -146,6 +144,27 @@ impl compact_formats::CompactSaplingSpend {
}
}

impl<A: sapling::Authorization> From<&sapling::SpendDescription<A>>
for compact_formats::CompactSaplingSpend
{
fn from(spend: &sapling::SpendDescription<A>) -> compact_formats::CompactSaplingSpend {
compact_formats::CompactSaplingSpend {
nf: spend.nullifier().to_vec(),
}
}
}

impl<SpendAuth> From<&orchard::Action<SpendAuth>> for compact_formats::CompactOrchardAction {
fn from(action: &orchard::Action<SpendAuth>) -> compact_formats::CompactOrchardAction {
compact_formats::CompactOrchardAction {
nullifier: action.nullifier().to_bytes().to_vec(),
cmx: action.cmx().to_bytes().to_vec(),
ephemeral_key: action.encrypted_note().epk_bytes.to_vec(),
ciphertext: action.encrypted_note().enc_ciphertext[..COMPACT_NOTE_SIZE].to_vec(),
}
}
}

impl service::TreeState {
/// Deserializes and returns the Sapling note commitment tree field of the tree state.
pub fn sapling_tree(&self) -> io::Result<CommitmentTree<Node, NOTE_COMMITMENT_TREE_DEPTH>> {
Expand Down
70 changes: 53 additions & 17 deletions zcash_client_sqlite/src/testing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use tempfile::NamedTempFile;
#[cfg(feature = "unstable")]
use tempfile::TempDir;

use zcash_client_backend::data_api::AccountBalance;
use zcash_client_backend::data_api::{AccountBalance, WalletRead};
#[allow(deprecated)]
use zcash_client_backend::{
address::RecipientAddress,
Expand All @@ -35,7 +35,7 @@ use zcash_client_backend::{
wallet::OvkPolicy,
zip321,
};
use zcash_note_encryption::{Domain, COMPACT_NOTE_SIZE};
use zcash_note_encryption::Domain;
use zcash_primitives::{
block::BlockHash,
consensus::{self, BlockHeight, Network, NetworkUpgrade, Parameters},
Expand Down Expand Up @@ -270,22 +270,49 @@ where
(height, res)
}

/// Creates a fake block at the expected next height containing only the wallet
/// transaction with the given txid, and inserts it into the cache.
///
/// This generated block will be treated as the latest block, and subsequent calls to
/// [`Self::generate_next_block`] (or similar) will build on it.
pub(crate) fn generate_next_block_including(
&mut self,
txid: TxId,
) -> (BlockHeight, Cache::InsertResult) {
let tx = self
.wallet()
.get_transaction(txid)
.expect("TxId should exist in the wallet");

// Index 0 is by definition a coinbase transaction, and the wallet doesn't
// construct coinbase transactions. So we pretend here that the block has a
// coinbase transaction that does not have shielded coinbase outputs.
self.generate_next_block_from_tx(1, &tx)
}

/// Creates a fake block at the expected next height containing only the given
/// transaction, and inserts it into the cache.
/// This assumes that the transaction only has Sapling spends and outputs.
///
/// This generated block will be treated as the latest block, and subsequent calls to
/// [`Self::generate_next_block`] will build on it.
pub(crate) fn generate_next_block_from_tx(
&mut self,
tx_index: usize,
tx: &Transaction,
) -> (BlockHeight, Cache::InsertResult) {
let (height, prev_hash, initial_sapling_tree_size) = self
.latest_cached_block
.map(|(prev_height, prev_hash, end_size)| (prev_height + 1, prev_hash, end_size))
.unwrap_or_else(|| (self.sapling_activation_height(), BlockHash([0; 32]), 0));

let cb = fake_compact_block_from_tx(height, prev_hash, tx, initial_sapling_tree_size);
let cb = fake_compact_block_from_tx(
height,
prev_hash,
tx_index,
tx,
initial_sapling_tree_size,
0,
);
let res = self.cache.insert(&cb);

self.latest_cached_block = Some((
Expand Down Expand Up @@ -728,35 +755,42 @@ pub(crate) fn fake_compact_block<P: consensus::Parameters>(
}

/// Create a fake CompactBlock at the given height containing only the given transaction.
/// This assumes that the transaction only has Sapling spends and outputs.
pub(crate) fn fake_compact_block_from_tx(
height: BlockHeight,
prev_hash: BlockHash,
tx_index: usize,
tx: &Transaction,
initial_sapling_tree_size: u32,
initial_orchard_tree_size: u32,
) -> CompactBlock {
// Create a fake CompactTx
// Create a fake CompactTx containing the transaction.
let mut ctx = CompactTx {
index: tx_index as u64,
hash: tx.txid().as_ref().to_vec(),
..Default::default()
};

if let Some(bundle) = tx.sapling_bundle() {
for spend in bundle.shielded_spends() {
ctx.spends.push(CompactSaplingSpend {
nf: spend.nullifier().to_vec(),
});
ctx.spends.push(spend.into());
}
for output in bundle.shielded_outputs() {
ctx.outputs.push(CompactSaplingOutput {
cmu: output.cmu().to_bytes().to_vec(),
ephemeral_key: output.ephemeral_key().0.to_vec(),
ciphertext: output.enc_ciphertext()[..COMPACT_NOTE_SIZE].to_vec(),
});
ctx.outputs.push(output.into());
}
}
if let Some(bundle) = tx.orchard_bundle() {
for action in bundle.actions() {
ctx.actions.push(action.into());
}
}

fake_compact_block_from_compact_tx(ctx, height, prev_hash, initial_sapling_tree_size)
fake_compact_block_from_compact_tx(
ctx,
height,
prev_hash,
initial_sapling_tree_size,
initial_orchard_tree_size,
)
}

/// Create a fake CompactBlock at the given height, spending a single note from the
Expand Down Expand Up @@ -833,14 +867,15 @@ pub(crate) fn fake_compact_block_spending<P: consensus::Parameters>(
}
});

fake_compact_block_from_compact_tx(ctx, height, prev_hash, initial_sapling_tree_size)
fake_compact_block_from_compact_tx(ctx, height, prev_hash, initial_sapling_tree_size, 0)
}

pub(crate) fn fake_compact_block_from_compact_tx(
ctx: CompactTx,
height: BlockHeight,
prev_hash: BlockHash,
initial_sapling_tree_size: u32,
initial_orchard_tree_size: u32,
) -> CompactBlock {
let mut rng = OsRng;
let mut cb = CompactBlock {
Expand All @@ -857,7 +892,8 @@ pub(crate) fn fake_compact_block_from_compact_tx(
cb.chain_metadata = Some(compact::ChainMetadata {
sapling_commitment_tree_size: initial_sapling_tree_size
+ cb.vtx.iter().map(|tx| tx.outputs.len() as u32).sum::<u32>(),
..Default::default()
orchard_commitment_tree_size: initial_orchard_tree_size
+ cb.vtx.iter().map(|tx| tx.actions.len() as u32).sum::<u32>(),
});
cb
}
Expand Down
Loading

0 comments on commit f4fdba2

Please sign in to comment.