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

Remove the legacy sync algo #31

Merged
merged 3 commits into from
Oct 1, 2024
Merged
Changes from 1 commit
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
Next Next commit
remove the legacy sync algo
willemolding committed Sep 30, 2024
commit 443ad173dd770eafff632ae9ad03f6c002e4f310
1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -41,7 +41,6 @@ native = ["tonic/channel", "tonic/gzip", "tonic/tls-webpki-roots", "tokio/macros
sqlite-db = ["dep:zcash_client_sqlite"]
console_error_panic_hook = ["dep:console_error_panic_hook"]
no-bundler = ["wasm-bindgen-rayon?/no-bundler", "wasm_thread/no-bundler"]
sync2 = []

[dependencies]
## Web dependencies
10 changes: 5 additions & 5 deletions justfile
Original file line number Diff line number Diff line change
@@ -2,26 +2,26 @@ default:
just --list

build *features:
wasm-pack build --no-opt -t web --scope webzjs --release --out-dir ./packages/webz-core --no-default-features --features="wasm wasm-parallel sync2 {{features}}" -Z build-std="panic_abort,std"
wasm-pack build --no-opt -t web --scope webzjs --release --out-dir ./packages/webz-core --no-default-features --features="wasm wasm-parallel {{features}}" -Z build-std="panic_abort,std"

# All Wasm Tests
test-web *features:
WASM_BINDGEN_TEST_TIMEOUT=99999 wasm-pack test --release --firefox --no-default-features --features "wasm no-bundler {{features}}" -Z build-std="panic_abort,std"

# sync message board in the web: addigional args: sync2
# sync message board in the web: addigional args:
test-message-board-web *features:
WASM_BINDGEN_TEST_TIMEOUT=99999 wasm-pack test --release --chrome --no-default-features --features "wasm no-bundler {{features}}" -Z build-std="panic_abort,std" --test message-board-sync

# simple example in the web: additional args: sync2
# simple example in the web: additional args:
test-simple-web *features:
WASM_BINDGEN_TEST_TIMEOUT=99999 wasm-pack test --release --chrome --no-default-features --features "wasm no-bundler {{features}}" -Z build-std="panic_abort,std" --test simple-sync-and-send


# simple example: additional args: sync2, sqlite-db
# simple example: additional args:, sqlite-db
example-simple *features:
RUST_LOG="info,zcash_client_backend::sync=debug" cargo run -r --example simple-sync --features "native {{features}}"

# sync the message board: additional args: sync2, sqlite-db
# sync the message board: additional args:, sqlite-db
example-message-board *features:
RUST_LOG=info,zcash_client_backend::sync=debug cargo run -r --example message-board-sync --features "native {{features}}"

23 changes: 3 additions & 20 deletions src/bindgen/wallet.rs
Original file line number Diff line number Diff line change
@@ -117,31 +117,14 @@ impl WebWallet {
self.inner.suggest_scan_ranges().await
}

/// Synchronize the wallet with the blockchain up to the tip
/// The passed callback will be called for every batch of blocks processed with the current progress
pub async fn sync(&self, callback: &js_sys::Function) -> Result<(), Error> {
let callback = move |scanned_to: BlockHeight, tip: BlockHeight| {
let this = JsValue::null();
let _ = callback.call2(
&this,
&JsValue::from(Into::<u32>::into(scanned_to)),
&JsValue::from(Into::<u32>::into(tip)),
);
};

self.inner.sync(callback).await?;

Ok(())
}

/// Synchronize the wallet with the blockchain up to the tip using zcash_client_backend's algo
pub async fn sync2(&self) -> Result<(), Error> {
pub async fn sync(&self) -> Result<(), Error> {
assert!(!thread::is_web_worker_thread());

let db = self.inner.clone();

let sync_handler = thread::Builder::new()
.name("sync2".to_string())
.name("sync".to_string())
.spawn_async(|| async {
assert!(thread::is_web_worker_thread());
tracing::debug!(
@@ -150,7 +133,7 @@ impl WebWallet {
);

let db = db;
db.sync2().await.unwrap_throw();
db.sync().await.unwrap_throw();
})
.unwrap_throw()
.join_async();
137 changes: 4 additions & 133 deletions src/wallet.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use std::num::NonZeroU32;

use bip0039::{English, Mnemonic};
use futures_util::{StreamExt, TryStreamExt};
use nonempty::NonEmpty;
use secrecy::{ExposeSecret, SecretVec, Zeroize};
use tonic::{
@@ -22,23 +21,21 @@ use zcash_address::ZcashAddress;
use zcash_client_backend::data_api::wallet::{
create_proposed_transactions, input_selection::GreedyInputSelector, propose_transfer,
};
use zcash_client_backend::data_api::{scanning::ScanRange, WalletCommitmentTrees};
use zcash_client_backend::data_api::WalletCommitmentTrees;
use zcash_client_backend::data_api::{
AccountBirthday, AccountPurpose, InputSource, NullifierQuery, WalletRead, WalletSummary,
WalletWrite,
AccountBirthday, AccountPurpose, InputSource, WalletRead, WalletSummary, WalletWrite,
};
use zcash_client_backend::fees::zip317::SingleOutputChangeStrategy;
use zcash_client_backend::proposal::Proposal;
use zcash_client_backend::proto::service::{
self, compact_tx_streamer_client::CompactTxStreamerClient,
};
use zcash_client_backend::scanning::{scan_block, Nullifiers, ScanningKeys};
use zcash_client_backend::wallet::OvkPolicy;
use zcash_client_backend::zip321::{Payment, TransactionRequest};
use zcash_client_backend::ShieldedProtocol;
use zcash_client_memory::{MemBlockCache, MemoryWalletDb};
use zcash_keys::keys::{UnifiedFullViewingKey, UnifiedSpendingKey};
use zcash_primitives::consensus::{self, BlockHeight, Network};
use zcash_primitives::consensus::{self, Network};
use zcash_primitives::transaction::components::amount::NonNegativeAmount;
use zcash_primitives::transaction::fees::zip317::FeeRule;
use zcash_primitives::transaction::TxId;
@@ -228,7 +225,7 @@ where
})?)
}

pub async fn sync2(&self) -> Result<(), Error> {
pub async fn sync(&self) -> Result<(), Error> {
let mut client = self.client.clone();
// TODO: This should be held in the Wallet struct so we can download in parallel
let db_cache = MemBlockCache::new();
@@ -245,113 +242,6 @@ where
.map_err(Into::into)
}

/// Synchronize the wallet with the blockchain up to the tip
/// The passed callback will be called for every batch of blocks processed with the current progress
pub async fn sync(&self, callback: impl Fn(BlockHeight, BlockHeight)) -> Result<(), Error> {
let tip = self.update_chain_tip().await?;

tracing::info!("Retrieving suggested scan ranges from wallet");
let scan_ranges = self.db.read().await.suggest_scan_ranges()?;
tracing::info!("Suggested scan ranges: {:?}", scan_ranges);

// TODO: Ensure wallet's view of the chain tip as of the previous wallet session is valid.
// See https://github.com/Electric-Coin-Company/zec-sqlite-cli/blob/8c2e49f6d3067ec6cc85248488915278c3cb1c5a/src/commands/sync.rs#L157

// Download and process all blocks in the requested ranges
// Split each range into BATCH_SIZE chunks to avoid requesting too many blocks at once
for scan_range in scan_ranges.into_iter().flat_map(|r| {
// Limit the number of blocks we download and scan at any one time.
(0..).scan(r, |acc, _| {
if acc.is_empty() {
None
} else if let Some((cur, next)) = acc.split_at(acc.block_range().start + BATCH_SIZE)
{
*acc = next;
Some(cur)
} else {
let cur = acc.clone();
let end = acc.block_range().end;
*acc = ScanRange::from_parts(end..end, acc.priority());
Some(cur)
}
})
}) {
self.fetch_and_scan_range(
scan_range.block_range().start.into(),
scan_range.block_range().end.into(),
)
.await?;
callback(scan_range.block_range().end, tip);
}

Ok(())
}

/// Download and process all blocks in the given range
async fn fetch_and_scan_range(&self, start: u32, end: u32) -> Result<(), Error> {
let mut client = self.client.clone();
// get the chainstate prior to the range
let tree_state = client
.get_tree_state(service::BlockId {
height: (start - 1).into(),
..Default::default()
})
.await?;
let chainstate = tree_state.into_inner().to_chain_state()?;

// Get the scanning keys from the DB
let account_ufvks = self.db.read().await.get_unified_full_viewing_keys()?;
let scanning_keys = ScanningKeys::from_account_ufvks(account_ufvks);

// Get the nullifiers for the unspent notes we are tracking
let nullifiers = Nullifiers::new(
self.db
.read()
.await
.get_sapling_nullifiers(NullifierQuery::Unspent)?,
self.db
.read()
.await
.get_orchard_nullifiers(NullifierQuery::Unspent)?,
);

let range = service::BlockRange {
start: Some(service::BlockId {
height: start.into(),
..Default::default()
}),
end: Some(service::BlockId {
height: (end - 1).into(),
..Default::default()
}),
};

tracing::info!("Scanning block range: {:?} to {:?}", start, end);

let scanned_blocks = client
.get_block_range(range)
.await?
.into_inner()
.map(|compact_block| {
scan_block(
&self.network,
compact_block.unwrap(),
&scanning_keys,
&nullifiers,
None,
)
})
.try_collect()
.await?;

self.db
.write()
.await
.put_blocks(&chainstate, scanned_blocks)?;

Ok(())
}

pub async fn get_wallet_summary(&self) -> Result<Option<WalletSummary<AccountId>>, Error> {
Ok(self
.db
@@ -360,25 +250,6 @@ where
.get_wallet_summary(self.min_confirmations.into())?)
}

pub(crate) async fn update_chain_tip(&self) -> Result<BlockHeight, Error> {
tracing::info!("Retrieving chain tip from lightwalletd");

let tip_height = self
.client
.clone()
.get_latest_block(service::ChainSpec::default())
.await?
.get_ref()
.height
.try_into()
.unwrap();

tracing::info!("Latest block height is {}", tip_height);
self.db.write().await.update_chain_tip(tip_height)?;

Ok(tip_height)
}

///
/// Create a transaction proposal to send funds from the wallet to a given address
///
18 changes: 3 additions & 15 deletions tests/message-board-sync.rs
Original file line number Diff line number Diff line change
@@ -39,21 +39,9 @@ async fn test_message_board() {
let id = w.import_ufvk(&ufvk_str, Some(2477329)).await.unwrap();
tracing::info!("Created account with id: {}", id);

#[cfg(not(feature = "sync2"))]
{
tracing::info!("Syncing wallet with our sync impl");
w.sync(&js_sys::Function::new_with_args(
"scanned_to, tip",
"console.log('Scanned: ', scanned_to, '/', tip)",
))
.await
.unwrap();
}
#[cfg(feature = "sync2")]
{
tracing::info!("Syncing wallet with sync2");
w.sync2().await.unwrap();
}
tracing::info!("Syncing wallet with our sync impl");
w.sync().await.unwrap();

tracing::info!("Syncing complete :)");

let summary = w.get_wallet_summary().await.unwrap();
16 changes: 2 additions & 14 deletions tests/simple-sync-and-send.rs
Original file line number Diff line number Diff line change
@@ -33,20 +33,8 @@ async fn test_get_and_scan_range() {
let w_clone = w.clone();
let w = w_clone;

#[cfg(not(feature = "sync2"))]
{
w.sync(&js_sys::Function::new_with_args(
"scanned_to, tip",
"console.log('Scanned: ', scanned_to, '/', tip)",
))
.await
.unwrap();
}
#[cfg(feature = "sync2")]
{
tracing::info!("Syncing wallet with sync2");
w.sync2().await.unwrap();
}
w.sync().await.unwrap();

tracing::info!("Syncing complete :)");

let summary = w.get_wallet_summary().await.unwrap();