Repository navigation
Add one-time IVK traits to the backend #121
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
Changes from 1 commit
15cde0c
72aefc3
2c821b7
ad4c13f
4057ecf
e2f4a0b
c3d14b2
c15cc16
010c7d9
06c9a2e
cc33c49
4d2ae9c
c886999
f477106
359320b
a55867b
8436eca
4f43fa2
34728d8
daccd13
d7547d1
f181c49
4f9093b
5dcb449
6de6cef
364a555
72f9e48
12f3252
13bc108
aa31617
d3ffed3
d3c3640
2bf6050
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -159,7 +159,7 @@ use zcash_primitives::block::BlockHash; | |
| use zcash_protocol::consensus::{self, BlockHeight}; | ||
|
|
||
| use crate::{ | ||
| data_api::WalletWrite, | ||
| data_api::{ScannedBlock, WalletWrite}, | ||
| proto::compact_formats::CompactBlock, | ||
| scanning::{ | ||
| Nullifiers, ScanningKeys, | ||
|
|
@@ -172,6 +172,9 @@ use { | |
| super::scanning::ScanPriority, crate::data_api::scanning::ScanRange, async_trait::async_trait, | ||
| }; | ||
|
|
||
| #[cfg(feature = "orchard")] | ||
| use super::dynamic_ivk::DynamicIvkWrite; | ||
|
|
||
| pub mod error; | ||
| use error::Error; | ||
|
|
||
|
|
@@ -639,7 +642,97 @@ where | |
| .get_unified_full_viewing_keys() | ||
| .map_err(Error::Wallet)?; | ||
| let scanning_keys = ScanningKeys::from_account_ufvks(account_ufvks); | ||
| let mut runners = BatchRunners::<_, (), (), ()>::for_keys(100, &scanning_keys); | ||
| let (scan_summary, scanned_blocks) = scan_blocks( | ||
| params, | ||
| block_source, | ||
| data_db, | ||
| from_height, | ||
| limit, | ||
| &scanning_keys, | ||
| )?; | ||
|
|
||
| data_db | ||
| .put_blocks(from_state, scanned_blocks) | ||
| .map_err(Error::Wallet)?; | ||
| Ok(scan_summary) | ||
| } | ||
|
|
||
| /// [`scan_cached_blocks`], also trial-decrypting with the wallet's dynamic keys. | ||
| /// | ||
| /// The keys come from [`DynamicIvkRead::get_dynamic_scanning_keys`], and the blocks are | ||
| /// stored with [`DynamicIvkWrite::put_blocks_with_dynamic_ivks`]. A wallet with open | ||
| /// dynamic keys must be scanned with this function rather than [`scan_cached_blocks`]. | ||
| /// | ||
| /// [`DynamicIvkRead::get_dynamic_scanning_keys`]: super::dynamic_ivk::DynamicIvkRead::get_dynamic_scanning_keys | ||
| #[cfg(feature = "orchard")] | ||
| #[tracing::instrument(skip(params, block_source, data_db, from_state))] | ||
| #[allow(clippy::type_complexity)] | ||
| pub fn scan_cached_blocks_with_dynamic_ivks<ParamsT, DbT, BlockSourceT>( | ||
| params: &ParamsT, | ||
| block_source: &BlockSourceT, | ||
| data_db: &mut DbT, | ||
| from_height: BlockHeight, | ||
| from_state: &ChainState, | ||
| limit: usize, | ||
| ) -> Result<ScanSummary, Error<<DbT as WalletRead>::Error, BlockSourceT::Error>> | ||
| where | ||
| ParamsT: consensus::Parameters + Send + 'static, | ||
| BlockSourceT: BlockSource, | ||
| DbT: DynamicIvkWrite, | ||
| <DbT as WalletRead>::AccountId: ConditionallySelectable + Default + Send + Sync + 'static, | ||
| { | ||
| assert_eq!(from_height, from_state.block_height + 1); | ||
|
|
||
| let account_ufvks = data_db | ||
| .get_unified_full_viewing_keys() | ||
| .map_err(Error::Wallet)?; | ||
| let dynamic_keys = data_db.get_dynamic_scanning_keys().map_err(Error::Wallet)?; | ||
| let dynamic_key_ids = dynamic_keys | ||
| .iter() | ||
| .map(|key| (*key.account_id(), key.key_id())) | ||
| .collect::<Vec<_>>(); | ||
| let scanning_keys = | ||
| ScanningKeys::from_account_ufvks(account_ufvks).with_dynamic_ivks(dynamic_keys); | ||
| let (scan_summary, scanned_blocks) = scan_blocks( | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When this new scanner detects a dynamic-IVK payment, the output necessarily belongs to the Ironwood pool, but Useful? React with 👍 / 👎. |
||
| params, | ||
| block_source, | ||
| data_db, | ||
| from_height, | ||
| limit, | ||
| &scanning_keys, | ||
| )?; | ||
|
|
||
| data_db | ||
| .put_blocks_with_dynamic_ivks(from_state, scanned_blocks, &dynamic_key_ids) | ||
| .map_err(Error::Wallet)?; | ||
| Ok(scan_summary) | ||
| } | ||
|
|
||
| /// Scans at most `limit` blocks from `from_height` with `scanning_keys`, for | ||
| /// [`scan_cached_blocks`] and its dynamic IVK twin, returning the blocks to store. | ||
| #[allow(clippy::type_complexity)] | ||
| fn scan_blocks<ParamsT, DbT, BlockSourceT, IvkTag>( | ||
| params: &ParamsT, | ||
| block_source: &BlockSourceT, | ||
| data_db: &DbT, | ||
| from_height: BlockHeight, | ||
| limit: usize, | ||
| scanning_keys: &ScanningKeys<<DbT as WalletRead>::AccountId, IvkTag>, | ||
| ) -> Result< | ||
| ( | ||
| ScanSummary, | ||
| Vec<ScannedBlock<<DbT as WalletRead>::AccountId>>, | ||
| ), | ||
| Error<<DbT as WalletRead>::Error, BlockSourceT::Error>, | ||
| > | ||
| where | ||
| ParamsT: consensus::Parameters + Send + 'static, | ||
| BlockSourceT: BlockSource, | ||
| DbT: WalletRead, | ||
| <DbT as WalletRead>::AccountId: ConditionallySelectable + Default + Send + Sync + 'static, | ||
| IvkTag: Copy + std::hash::Hash + Eq + Send + 'static, | ||
| { | ||
| let mut runners = BatchRunners::<_, (), (), ()>::for_keys(100, scanning_keys); | ||
|
|
||
| block_source.with_blocks::<_, <DbT as WalletRead>::Error>( | ||
| Some(from_height), | ||
|
|
@@ -669,7 +762,7 @@ where | |
| let scanned_block = scan_block_with_runners::<_, _, _, (), (), ()>( | ||
| params, | ||
| block, | ||
| &scanning_keys, | ||
| scanning_keys, | ||
| &nullifiers, | ||
| prior_block_metadata.as_ref(), | ||
| Some(&mut runners), | ||
|
|
@@ -694,10 +787,7 @@ where | |
| }, | ||
| )?; | ||
|
|
||
| data_db | ||
| .put_blocks(from_state, scanned_blocks) | ||
| .map_err(Error::Wallet)?; | ||
| Ok(scan_summary) | ||
| Ok((scan_summary, scanned_blocks)) | ||
| } | ||
|
|
||
| #[cfg(feature = "test-dependencies")] | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When
zakura-client-backendis packaged or published, Cargo replaces this path dependency with the registry requirementzakura-dynamic-ivk = "0.0.0"; however, that crate's manifest declarespublish = false, so the required registry package cannot exist. This blocks the next backend release and would leave published consumers unable to resolve theorchardfeature. Publish the dependency at a real version before the backend, or avoid exposing it from this publishable crate.Useful? React with 👍 / 👎.