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
Show file tree
Hide file tree
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
1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 5 additions & 5 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -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}}"

Expand Down
23 changes: 3 additions & 20 deletions src/bindgen/wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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!(
Expand All @@ -150,7 +133,7 @@ impl WebWallet {
);

let db = db;
db.sync2().await.unwrap_throw();
db.sync().await.unwrap_throw();
})
.unwrap_throw()
.join_async();
Expand Down
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::{
Expand All @@ -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;
Expand Down Expand Up @@ -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();
Expand All @@ -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
Expand All @@ -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
///
Expand Down
18 changes: 3 additions & 15 deletions tests/message-board-sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
16 changes: 2 additions & 14 deletions tests/simple-sync-and-send.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
Loading