Skip to content
Closed
Show file tree
Hide file tree
Changes from all 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
4 changes: 4 additions & 0 deletions pepper-sync/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed

- `config::SyncConfig`:
- added `extended_zip212_grace_period` field.
- updated serialization to version 2 include `extended_zip212_grace_period` field

### Removed

## [0.3.0]
Expand Down
18 changes: 15 additions & 3 deletions pepper-sync/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,12 +86,16 @@ pub struct SyncConfig {
pub transparent_address_discovery: TransparentAddressDiscovery,
/// Performance level
pub performance_level: PerformanceLevel,
/// Optionally extend the grace period to enable recovery of zecwalletlite funds.
/// <https://github.com/zcash/librustzcash/issues/323>
/// <https://github.com/adityapk00/librustzcash/commit/c31a04a4dbfa5a2ac013139db229f41cd421754d>
pub extended_zip212_grace_period: bool,
}

#[cfg(feature = "wallet_essentials")]
impl SyncConfig {
fn serialized_version() -> u8 {
1
2
}

/// Deserialize into `reader`
Expand All @@ -101,10 +105,16 @@ impl SyncConfig {
let gap_limit = reader.read_u8()?;
let scopes = reader.read_u8()?;
let performance_level = if version >= 1 {
PerformanceLevel::read(reader)?
PerformanceLevel::read(&mut reader)?
} else {
PerformanceLevel::High
};
let extended_zip212_grace_period = if version >= 2 {
reader.read_u8()? != 0
} else {
false
};

Ok(Self {
transparent_address_discovery: TransparentAddressDiscovery {
gap_limit,
Expand All @@ -115,6 +125,7 @@ impl SyncConfig {
},
},
performance_level,
extended_zip212_grace_period,
})
}

Expand All @@ -133,7 +144,8 @@ impl SyncConfig {
scopes |= 0b100;
}
writer.write_u8(scopes)?;
self.performance_level.write(writer)?;
self.performance_level.write(&mut writer)?;
writer.write_u8(self.extended_zip212_grace_period as u8)?;

Ok(())
}
Expand Down
2 changes: 2 additions & 0 deletions pepper-sync/src/scan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ pub(crate) async fn scan<P>(
ufvks: &HashMap<AccountId, UnifiedFullViewingKey>,
scan_task: ScanTask,
max_batch_outputs: usize,
extended_zip212_grace_period: bool,
) -> Result<ScanResults, ScanError>
where
P: consensus::Parameters + Sync + Send + 'static,
Expand Down Expand Up @@ -182,6 +183,7 @@ where
&ufvks_clone,
initial_scan_data,
max_batch_outputs / 8,
extended_zip212_grace_period,
)
})
.await
Expand Down
9 changes: 8 additions & 1 deletion pepper-sync/src/scan/compact_blocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ pub(super) fn scan_compact_blocks<P>(
ufvks: &HashMap<AccountId, UnifiedFullViewingKey>,
initial_scan_data: InitialScanData,
trial_decrypt_task_size: usize,
extended_zip212_grace_period: bool,
) -> Result<ScanData, ScanError>
where
P: consensus::Parameters + Sync + Send + 'static,
Expand All @@ -54,6 +55,7 @@ where
&scanning_keys,
&compact_blocks,
trial_decrypt_task_size,
extended_zip212_grace_period,
)?;

let mut wallet_blocks: BTreeMap<BlockHeight, WalletBlock> = BTreeMap::new();
Expand Down Expand Up @@ -181,14 +183,19 @@ fn trial_decrypt<P>(
scanning_keys: &ScanningKeys,
compact_blocks: &[CompactBlock],
trial_decrypt_task_size: usize,
extended_zip212_grace_period: bool,
) -> Result<BatchRunners<(), ()>, ScanError>
where
P: consensus::Parameters + Send + 'static,
{
let mut runners = BatchRunners::<(), ()>::for_keys(trial_decrypt_task_size, scanning_keys);
for block in compact_blocks {
runners
.add_block(consensus_parameters, block.clone())
.add_block(
consensus_parameters,
block.clone(),
extended_zip212_grace_period,
)
.map_err(ScanError::ZcbScanError)?;
}
runners.flush();
Expand Down
108 changes: 104 additions & 4 deletions pepper-sync/src/scan/compact_blocks/runners.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ use std::sync::atomic::AtomicUsize;
use crossbeam_channel as channel;

use orchard::note_encryption::{CompactAction, OrchardDomain};
use sapling_crypto::note_encryption::Zip212Enforcement;
use sapling_crypto::note_encryption::{CompactOutputDescription, SaplingDomain};
use zcash_client_backend::proto::compact_formats::CompactBlock;
use zcash_note_encryption::{BatchDomain, COMPACT_NOTE_SIZE, Domain, ShieldedOutput, batch};
use zcash_primitives::{
block::BlockHash, transaction::TxId, transaction::components::sapling::zip212_enforcement,
};
use zcash_primitives::{block::BlockHash, transaction::TxId};
use zcash_protocol::consensus::BlockHeight;
use zcash_protocol::consensus::NetworkUpgrade;
use zcash_protocol::consensus::Parameters;
use zcash_protocol::{ShieldedProtocol, consensus};

use memuse::DynamicUsage;
Expand All @@ -23,6 +25,42 @@ use crate::keys::ScanningKeyOps as _;
use crate::keys::ScanningKeys;
use crate::wallet::OutputId;

/// The "grace period" defined in [ZIP 212].
///
/// [ZIP 212]: <https://zips.z.cash/zip-0212#changes-to-the-process-of-receiving-sapling-or-orchard-notes>
const ZIP212_GRACE_PERIOD: u32 = 32256;

/// An extended grace period used by zecwalletlite and resulting in missing funds for zip212 conformant wallets.
/// <https://github.com/adityapk00/librustzcash/commit/c31a04a4dbfa5a2ac013139db229f41cd421754d>
const ZIP212_EXTENDED_GRACE_PERIOD: u32 = 32256 + 161280;

/// Returns the enforcement policy for ZIP 212 at the given height.
/// If `extended` is true, the grace window will be extended to enable recovery of zecwalletlite funds.
/// https://github.com/zcash/librustzcash/issues/323
fn zip212_enforcement(
params: &impl Parameters,
height: BlockHeight,
extended: bool,
) -> Zip212Enforcement {
if params.is_nu_active(NetworkUpgrade::Canopy, height) {
let grace_period = if extended {
ZIP212_EXTENDED_GRACE_PERIOD
} else {
ZIP212_GRACE_PERIOD
};
let grace_period_end_height =
params.activation_height(NetworkUpgrade::Canopy).unwrap() + grace_period;

if height < grace_period_end_height {
Zip212Enforcement::GracePeriod
} else {
Zip212Enforcement::On
}
} else {
Zip212Enforcement::Off
}
}

type TaggedSaplingBatch = Batch<
SaplingDomain,
sapling_crypto::note_encryption::CompactOutputDescription,
Expand Down Expand Up @@ -85,13 +123,15 @@ where
&mut self,
params: &P,
block: CompactBlock,
extended_zip212_grace_period: bool,
) -> Result<(), zcash_client_backend::scanning::ScanError>
where
P: consensus::Parameters + Send + 'static,
{
let block_hash = block.hash();
let block_height = block.height();
let zip212_enforcement = zip212_enforcement(params, block_height);
let zip212_enforcement =
zip212_enforcement(params, block_height, extended_zip212_grace_period);

for tx in block.vtx {
let txid = tx.txid();
Expand Down Expand Up @@ -606,3 +646,63 @@ where
.unwrap_or_default()
}
}

#[cfg(test)]
mod tests {
use super::*;
use zcash_protocol::consensus::MainNetwork;

// Mainnet Canopy activates at height 1_046_400. The standard ZIP-212 grace
// period ends at 1_078_656, while the extended recovery window ends at
// 1_239_936. The end heights are exclusive: at the end height itself,
// enforcement flips from `GracePeriod` to `On`. These tests pin behavior at
// each boundary and at the height where the two modes diverge.
mod zip212_enforcement {
use super::*;

#[test]
fn standard_mode_last_grace_height() {
assert_eq!(
zip212_enforcement(&MainNetwork, BlockHeight::from_u32(1_078_655), false),
Zip212Enforcement::GracePeriod,
);
}

#[test]
fn standard_mode_first_enforced_height() {
assert_eq!(
zip212_enforcement(&MainNetwork, BlockHeight::from_u32(1_078_656), false),
Zip212Enforcement::On,
);
}

#[test]
fn extended_mode_last_grace_height() {
assert_eq!(
zip212_enforcement(&MainNetwork, BlockHeight::from_u32(1_239_935), true),
Zip212Enforcement::GracePeriod,
);
}

#[test]
fn extended_mode_first_enforced_height() {
assert_eq!(
zip212_enforcement(&MainNetwork, BlockHeight::from_u32(1_239_936), true),
Zip212Enforcement::On,
);
}

#[test]
fn extended_flag_diverges_at_standard_end() {
let height = BlockHeight::from_u32(1_078_656);
assert_eq!(
zip212_enforcement(&MainNetwork, height, false),
Zip212Enforcement::On,
);
assert_eq!(
zip212_enforcement(&MainNetwork, height, true),
Zip212Enforcement::GracePeriod,
);
}
}
}
8 changes: 6 additions & 2 deletions pepper-sync/src/scan/task.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ pub(crate) struct Scanner<P> {
fetch_request_sender: mpsc::UnboundedSender<FetchRequest>,
consensus_parameters: P,
ufvks: HashMap<AccountId, UnifiedFullViewingKey>,
extended_zip212_grace_period: bool,
}

impl<P> Scanner<P>
Expand All @@ -77,6 +78,7 @@ where
scan_results_sender: mpsc::UnboundedSender<(ScanRange, Result<ScanResults, ScanError>)>,
fetch_request_sender: mpsc::UnboundedSender<FetchRequest>,
ufvks: HashMap<AccountId, UnifiedFullViewingKey>,
extended_zip212_grace_period: bool,
) -> Self {
let workers: Vec<ScanWorker<P>> = Vec::with_capacity(MAX_WORKER_POOLSIZE);

Expand All @@ -89,6 +91,7 @@ where
fetch_request_sender,
consensus_parameters,
ufvks,
extended_zip212_grace_period,
}
}

Expand Down Expand Up @@ -152,7 +155,7 @@ where
self.fetch_request_sender.clone(),
self.ufvks.clone(),
);
worker.run(max_batch_outputs);
worker.run(max_batch_outputs, self.extended_zip212_grace_period);
self.workers.push(worker);
self.unique_id += 1;
}
Expand Down Expand Up @@ -649,7 +652,7 @@ where
/// Runs the worker in a new tokio task.
///
/// Waits for a scan task and then calls [`crate::scan::scan`] on the given range.
fn run(&mut self, max_batch_outputs: usize) {
fn run(&mut self, max_batch_outputs: usize, extended_zip212_grace_period: bool) {
let (scan_task_sender, mut scan_task_receiver) = mpsc::channel::<ScanTask>(1);

let is_scanning = self.is_scanning.clone();
Expand All @@ -668,6 +671,7 @@ where
&ufvks,
scan_task,
max_batch_outputs,
extended_zip212_grace_period,
);

let scan_results = match tokio::time::timeout(SCAN_TASK_TIMEOUT, scan_fut).await {
Expand Down
1 change: 1 addition & 0 deletions pepper-sync/src/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,7 @@ where
scan_results_sender,
fetch_request_sender.clone(),
ufvks.clone(),
config.extended_zip212_grace_period,
);
scanner.launch(config.performance_level);

Expand Down
1 change: 1 addition & 0 deletions zingo-cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,7 @@ fn build_zingo_config(filled_template: &ConfigTemplate) -> std::io::Result<Clien
sync_config: SyncConfig {
transparent_address_discovery: TransparentAddressDiscovery::minimal(),
performance_level: PerformanceLevel::High,
extended_zip212_grace_period: false,
},
min_confirmations: NonZeroU32::try_from(3).unwrap(),
};
Expand Down
1 change: 1 addition & 0 deletions zingo-cli/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -656,6 +656,7 @@ mod config_template {
sync_config: SyncConfig {
transparent_address_discovery: TransparentAddressDiscovery::minimal(),
performance_level: PerformanceLevel::High,
extended_zip212_grace_period: false,
},
min_confirmations: NonZeroU32::try_from(3).unwrap(),
},
Expand Down
1 change: 1 addition & 0 deletions zingolib/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,7 @@ impl Default for ClientConfigBuilder {
sync_config: SyncConfig {
transparent_address_discovery: TransparentAddressDiscovery::minimal(),
performance_level: pepper_sync::config::PerformanceLevel::High,
extended_zip212_grace_period: false,
},
min_confirmations: NonZeroU32::try_from(3)
.expect("hard coded non-zero integer"),
Expand Down
1 change: 1 addition & 0 deletions zingolib/src/testutils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ pub fn default_test_wallet_settings() -> WalletSettings {
sync_config: SyncConfig {
transparent_address_discovery: TransparentAddressDiscovery::minimal(),
performance_level: PerformanceLevel::High,
extended_zip212_grace_period: false,
},
min_confirmations: NonZeroU32::try_from(1).expect("hard-coded non-zero integer"),
}
Expand Down
2 changes: 2 additions & 0 deletions zingolib/src/wallet/disk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,7 @@ impl LightWallet {
sync_config: SyncConfig {
transparent_address_discovery: TransparentAddressDiscovery::minimal(),
performance_level: PerformanceLevel::High,
extended_zip212_grace_period: false,
},
min_confirmations: NonZeroU32::try_from(3).unwrap(),
},
Expand Down Expand Up @@ -580,6 +581,7 @@ impl LightWallet {
sync_config: SyncConfig {
transparent_address_discovery: TransparentAddressDiscovery::minimal(),
performance_level: PerformanceLevel::High,
extended_zip212_grace_period: false,
},
min_confirmations: NonZeroU32::try_from(3).unwrap(),
}
Expand Down