Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

zcash_client_backend: Make scan range bounds required in data_api::chain::scan_cached_blocks #867

Merged
merged 3 commits into from
Jul 6, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions zcash_client_backend/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,15 @@ and this library adheres to Rust's notion of
- `impl Eq for zcash_client_backend::zip321::{Payment, TransactionRequest}`
- `impl Debug` for `zcash_client_backend::{data_api::wallet::input_selection::Proposal, wallet::ReceivedSaplingNote}`
- `zcash_client_backend::data_api`:
- `BlockMetadata`
- `NullifierQuery` for use with `WalletRead::get_sapling_nullifiers`
- `ScannedBlock`
- `ShieldedProtocol`
- `WalletRead::{block_metadata, block_fully_scanned, suggest_scan_ranges}`
- `WalletWrite::put_block`
- `WalletCommitmentTrees`
- `testing::MockWalletDb::new`
- `NullifierQuery` for use with `WalletRead::get_sapling_nullifiers`
- `BlockMetadata`
- `ScannedBlock`
- `chain::CommitmentTreeRoot`
- `testing::MockWalletDb::new`
- `wallet::input_sellection::Proposal::{min_target_height, min_anchor_height}`:
- `zcash_client_backend::wallet::WalletSaplingOutput::note_commitment_tree_position`
- `zcash_client_backend::scanning::ScanError`
Expand All @@ -35,7 +36,8 @@ and this library adheres to Rust's notion of
and its signature has changed; it now subsumes the removed `WalletRead::get_all_nullifiers`.
- `WalletRead::get_target_and_anchor_heights` now takes its argument as a `NonZeroU32`
- `chain::scan_cached_blocks` now takes a `from_height` argument that
permits the caller to control the starting position of the scan range.
permits the caller to control the starting position of the scan range
In addition, the `limit` parameter is now required.
- A new `CommitmentTree` variant has been added to `data_api::error::Error`
- `data_api::wallet::{create_spend_to_address, create_proposed_transaction,
shield_transparent_funds}` all now require that `WalletCommitmentTrees` be
Expand All @@ -49,6 +51,8 @@ and this library adheres to Rust's notion of
now take their respective `min_confirmations` arguments as `NonZeroU32`
- A new `Scan` variant has been added to `data_api::chain::error::Error`.
- A new `SyncRequired` variant has been added to `data_api::wallet::input_selection::InputSelectorError`.
- The variants of the `PoolType` enum have changed; the `PoolType::Sapling` variant has been
removed in favor of a `PoolType::Shielded` variant that wraps a `ShieldedProtocol` value.
- `zcash_client_backend::wallet`:
- `SpendableNote` has been renamed to `ReceivedSaplingNote`.
- Arguments to `WalletSaplingOutput::from_parts` have changed.
Expand Down
14 changes: 10 additions & 4 deletions zcash_client_backend/src/data_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -372,14 +372,21 @@ pub struct SentTransaction<'a> {
pub utxos_spent: Vec<OutPoint>,
}

/// A shielded transfer protocol supported by the wallet.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum ShieldedProtocol {
/// The Sapling protocol
Sapling,
// TODO: Orchard
}

/// A value pool to which the wallet supports sending transaction outputs.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum PoolType {
/// The transparent value pool
Transparent,
/// The Sapling value pool
Sapling,
// TODO: Orchard
/// A shielded value pool.
Shielded(ShieldedProtocol),
}

/// A type that represents the recipient of a transaction output; a recipient address (and, for
Expand Down Expand Up @@ -487,7 +494,6 @@ pub trait WalletWrite: WalletRead {
/// Updates the state of the wallet database by persisting the provided block information,
/// along with the note commitments that were detected when scanning the block for transactions
/// pertaining to this wallet.
#[allow(clippy::type_complexity)]
fn put_block(
&mut self,
block: ScannedBlock<sapling::Nullifier>,
Expand Down
124 changes: 73 additions & 51 deletions zcash_client_backend/src/data_api/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
//! // At this point, the cache and scanned data are locally consistent (though not
//! // necessarily consistent with the latest chain tip - this would be discovered the
//! // next time this codepath is executed after new blocks are received).
//! scan_cached_blocks(&network, &block_source, &mut db_data, None, None)
//! scan_cached_blocks(&network, &block_source, &mut db_data, BlockHeight::from(0), 10)
//! # }
//! # }
//! ```
Expand All @@ -60,9 +60,11 @@
data_api::{NullifierQuery, WalletWrite},
proto::compact_formats::CompactBlock,
scan::BatchRunner,
scanning::{add_block_to_runner, scan_block_with_runner},
scanning::{add_block_to_runner, check_continuity, scan_block_with_runner},
};

use super::BlockMetadata;

pub mod error;
use error::Error;

Expand Down Expand Up @@ -141,8 +143,8 @@
params: &ParamsT,
block_source: &BlockSourceT,
data_db: &mut DbT,
from_height: Option<BlockHeight>,
limit: Option<u32>,
from_height: BlockHeight,
limit: u32,
nuttycom marked this conversation as resolved.
Show resolved Hide resolved
) -> Result<(), Error<DbT::Error, BlockSourceT::Error>>
where
ParamsT: consensus::Parameters + Send + 'static,
Expand Down Expand Up @@ -178,61 +180,81 @@
.map(|(tag, ivk)| (tag, PreparedIncomingViewingKey::new(&ivk))),
);

// Start at either the provided height, or where we synced up to previously.
let (scan_from, mut prior_block_metadata) = match from_height {
Some(h) => {
// if we are provided with a starting height, obtain the metadata for the previous
// block (if any is available)
(
Some(h),
if h > BlockHeight::from(0) {
data_db.block_metadata(h - 1).map_err(Error::Wallet)?
} else {
None
},
)
}
None => {
let last_scanned = data_db.block_fully_scanned().map_err(Error::Wallet)?;
last_scanned.map_or_else(|| (None, None), |m| (Some(m.block_height + 1), Some(m)))
}
let mut prior_block_metadata = if from_height > BlockHeight::from(0) {
data_db
.block_metadata(from_height - 1)
.map_err(Error::Wallet)?

Check warning on line 186 in zcash_client_backend/src/data_api/chain.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_backend/src/data_api/chain.rs#L183-L186

Added lines #L183 - L186 were not covered by tests
} else {
None

Check warning on line 188 in zcash_client_backend/src/data_api/chain.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_backend/src/data_api/chain.rs#L188

Added line #L188 was not covered by tests
};

block_source.with_blocks::<_, DbT::Error>(scan_from, limit, |block: CompactBlock| {
add_block_to_runner(params, block, &mut batch_runner);
Ok(())
})?;
let mut continuity_check_metadata = prior_block_metadata;
block_source.with_blocks::<_, DbT::Error>(
Some(from_height),
Some(limit),
|block: CompactBlock| {

Check warning on line 195 in zcash_client_backend/src/data_api/chain.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_backend/src/data_api/chain.rs#L191-L195

Added lines #L191 - L195 were not covered by tests
// check block continuity
if let Some(scan_error) = check_continuity(&block, continuity_check_metadata.as_ref()) {
return Err(Error::Scan(scan_error));
}
continuity_check_metadata = continuity_check_metadata.as_ref().map(|m| {
nuttycom marked this conversation as resolved.
Show resolved Hide resolved
BlockMetadata::from_parts(
block.height(),
block.hash(),
block
.chain_metadata
.as_ref()
.map(|m| m.sapling_commitment_tree_size)
.unwrap_or_else(|| {
m.sapling_tree_size()
+ u32::try_from(
block.vtx.iter().map(|tx| tx.outputs.len()).sum::<usize>(),

Check warning on line 211 in zcash_client_backend/src/data_api/chain.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_backend/src/data_api/chain.rs#L209-L211

Added lines #L209 - L211 were not covered by tests
)
.unwrap()

Check warning on line 213 in zcash_client_backend/src/data_api/chain.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_backend/src/data_api/chain.rs#L213

Added line #L213 was not covered by tests
}),
)
});

batch_runner.flush();
add_block_to_runner(params, block, &mut batch_runner);

Ok(())
},
)?;

block_source.with_blocks::<_, DbT::Error>(scan_from, limit, |block: CompactBlock| {
let scanned_block = scan_block_with_runner(
params,
block,
&dfvks,
&sapling_nullifiers,
prior_block_metadata.as_ref(),
Some(&mut batch_runner),
)
.map_err(Error::Scan)?;
batch_runner.flush();

Check warning on line 224 in zcash_client_backend/src/data_api/chain.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_backend/src/data_api/chain.rs#L224

Added line #L224 was not covered by tests

let spent_nf: Vec<&sapling::Nullifier> = scanned_block
.transactions
.iter()
.flat_map(|tx| tx.sapling_spends.iter().map(|spend| spend.nf()))
.collect();
block_source.with_blocks::<_, DbT::Error>(
Some(from_height),
Some(limit),

Check warning on line 228 in zcash_client_backend/src/data_api/chain.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_backend/src/data_api/chain.rs#L226-L228

Added lines #L226 - L228 were not covered by tests
|block: CompactBlock| {
let scanned_block = scan_block_with_runner(
params,
block,
&dfvks,
&sapling_nullifiers,
prior_block_metadata.as_ref(),
Some(&mut batch_runner),
)
.map_err(Error::Scan)?;

sapling_nullifiers.retain(|(_, nf)| !spent_nf.contains(&nf));
sapling_nullifiers.extend(scanned_block.transactions.iter().flat_map(|tx| {
tx.sapling_outputs
let spent_nf: Vec<&sapling::Nullifier> = scanned_block
.transactions
.iter()
.map(|out| (out.account(), *out.nf()))
}));
.flat_map(|tx| tx.sapling_spends.iter().map(|spend| spend.nf()))
.collect();

sapling_nullifiers.retain(|(_, nf)| !spent_nf.contains(&nf));
sapling_nullifiers.extend(scanned_block.transactions.iter().flat_map(|tx| {
tx.sapling_outputs
.iter()
.map(|out| (out.account(), *out.nf()))
}));

prior_block_metadata = Some(*scanned_block.metadata());
data_db.put_block(scanned_block).map_err(Error::Wallet)?;
Ok(())
})?;
prior_block_metadata = Some(*scanned_block.metadata());
data_db.put_block(scanned_block).map_err(Error::Wallet)?;
Ok(())
},
)?;

Ok(())
}
Expand Down
40 changes: 24 additions & 16 deletions zcash_client_backend/src/data_api/wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
pub mod input_selection;
use input_selection::{GreedyInputSelector, GreedyInputSelectorError, InputSelector};

use super::ShieldedProtocol;

#[cfg(feature = "transparent-inputs")]
use {
crate::wallet::WalletTransparentOutput,
Expand Down Expand Up @@ -550,7 +552,7 @@
payment.memo.clone().unwrap_or_else(MemoBytes::empty),
)?;
sapling_output_meta.push((
Recipient::Unified(ua.clone(), PoolType::Sapling),
Recipient::Unified(ua.clone(), PoolType::Shielded(ShieldedProtocol::Sapling)),

Check warning on line 555 in zcash_client_backend/src/data_api/wallet.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_backend/src/data_api/wallet.rs#L555

Added line #L555 was not covered by tests
payment.amount,
payment.memo.clone(),
));
Expand Down Expand Up @@ -589,7 +591,10 @@
MemoBytes::empty(),
)?;
sapling_output_meta.push((
Recipient::InternalAccount(account, PoolType::Sapling),
Recipient::InternalAccount(
account,
PoolType::Shielded(ShieldedProtocol::Sapling),
),
*amount,
change_memo.clone(),
))
Expand All @@ -610,20 +615,23 @@
.output_index(i)
.expect("An output should exist in the transaction for each shielded payment.");

let received_as =
if let Recipient::InternalAccount(account, PoolType::Sapling) = recipient {
tx.sapling_bundle().and_then(|bundle| {
try_sapling_note_decryption(
params,
proposal.min_target_height(),
&internal_ivk,
&bundle.shielded_outputs()[output_index],
)
.map(|(note, _, _)| (account, note))
})
} else {
None
};
let received_as = if let Recipient::InternalAccount(
account,
PoolType::Shielded(ShieldedProtocol::Sapling),

Check warning on line 620 in zcash_client_backend/src/data_api/wallet.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_backend/src/data_api/wallet.rs#L620

Added line #L620 was not covered by tests
) = recipient
{
tx.sapling_bundle().and_then(|bundle| {
try_sapling_note_decryption(
params,
proposal.min_target_height(),
&internal_ivk,
&bundle.shielded_outputs()[output_index],
)
.map(|(note, _, _)| (account, note))
})
} else {
None
};

SentTransactionOutput::from_parts(output_index, recipient, value, memo, received_as)
});
Expand Down
Loading
Loading