2022-10-19 23:24:36 -07:00
|
|
|
//! Warp Synchronize
|
2022-06-08 05:48:16 -07:00
|
|
|
|
|
|
|
use crate::coinconfig::CoinConfig;
|
2022-10-04 20:22:04 -07:00
|
|
|
use crate::scan::{AMProgressCallback, Progress};
|
2022-11-06 04:50:51 -08:00
|
|
|
use crate::sync::CTree;
|
2022-11-17 01:13:51 -08:00
|
|
|
use crate::{AccountData, BlockId, CompactTxStreamerClient, DbAdapter};
|
2022-06-08 05:48:16 -07:00
|
|
|
use std::sync::Arc;
|
|
|
|
use tokio::sync::Mutex;
|
|
|
|
use tonic::transport::Channel;
|
|
|
|
use tonic::Request;
|
2022-09-04 04:19:49 -07:00
|
|
|
use zcash_primitives::sapling::Note;
|
2022-06-08 05:48:16 -07:00
|
|
|
|
2022-10-19 23:24:36 -07:00
|
|
|
/// Asynchronously perform warp sync
|
|
|
|
/// # Arguments
|
|
|
|
/// * `coin`: 0 for zcash, 1 for ycash
|
|
|
|
/// * `get_tx`: true to retrieve transaction details
|
|
|
|
/// * `anchor_offset`: minimum number of confirmations for note selection
|
|
|
|
/// * `max_cost`: tx that have a higher spending cost are excluded
|
|
|
|
/// * `progress_callback`: function callback during synchronization
|
|
|
|
/// * `cancel`: cancellation mutex, set to true to abort
|
2022-06-08 05:48:16 -07:00
|
|
|
pub async fn coin_sync(
|
|
|
|
coin: u8,
|
|
|
|
get_tx: bool,
|
|
|
|
anchor_offset: u32,
|
2022-07-30 16:11:58 -07:00
|
|
|
max_cost: u32,
|
2022-10-04 20:22:04 -07:00
|
|
|
progress_callback: impl Fn(Progress) + Send + 'static,
|
2022-08-30 07:00:15 -07:00
|
|
|
cancel: &'static std::sync::Mutex<bool>,
|
2022-06-08 05:48:16 -07:00
|
|
|
) -> anyhow::Result<()> {
|
2022-10-04 20:22:04 -07:00
|
|
|
let p_cb = Arc::new(Mutex::new(progress_callback));
|
2022-11-15 02:21:47 -08:00
|
|
|
coin_sync_impl(coin, get_tx, anchor_offset, max_cost, p_cb.clone(), cancel).await?;
|
|
|
|
coin_sync_impl(coin, get_tx, 0, u32::MAX, p_cb.clone(), cancel).await?;
|
2022-06-08 05:48:16 -07:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn coin_sync_impl(
|
|
|
|
coin: u8,
|
|
|
|
get_tx: bool,
|
|
|
|
target_height_offset: u32,
|
2022-07-30 16:11:58 -07:00
|
|
|
max_cost: u32,
|
2022-06-08 05:48:16 -07:00
|
|
|
progress_callback: AMProgressCallback,
|
2022-08-30 07:00:15 -07:00
|
|
|
cancel: &'static std::sync::Mutex<bool>,
|
2022-06-08 05:48:16 -07:00
|
|
|
) -> anyhow::Result<()> {
|
|
|
|
crate::scan::sync_async(
|
2022-11-05 18:49:17 -07:00
|
|
|
coin,
|
2022-06-08 05:48:16 -07:00
|
|
|
get_tx,
|
|
|
|
target_height_offset,
|
2022-07-30 16:11:58 -07:00
|
|
|
max_cost,
|
2022-06-08 05:48:16 -07:00
|
|
|
progress_callback,
|
2022-07-21 18:08:29 -07:00
|
|
|
cancel,
|
2022-06-08 05:48:16 -07:00
|
|
|
)
|
2022-11-15 02:21:47 -08:00
|
|
|
.await
|
2022-06-08 05:48:16 -07:00
|
|
|
}
|
|
|
|
|
2022-10-19 23:24:36 -07:00
|
|
|
/// Return the latest block height
|
2022-06-08 05:48:16 -07:00
|
|
|
pub async fn get_latest_height() -> anyhow::Result<u32> {
|
|
|
|
let c = CoinConfig::get_active();
|
|
|
|
let mut client = c.connect_lwd().await?;
|
|
|
|
let last_height = crate::chain::get_latest_height(&mut client).await?;
|
|
|
|
Ok(last_height)
|
|
|
|
}
|
|
|
|
|
2022-10-19 23:24:36 -07:00
|
|
|
/// Return the latest block height synchronized
|
2022-06-10 02:16:00 -07:00
|
|
|
pub fn get_synced_height() -> anyhow::Result<u32> {
|
|
|
|
let c = CoinConfig::get_active();
|
|
|
|
let db = c.db()?;
|
|
|
|
db.get_last_sync_height().map(|h| h.unwrap_or(0))
|
|
|
|
}
|
|
|
|
|
2022-10-19 23:24:36 -07:00
|
|
|
/// Skip block synchronization and directly mark the chain synchronized
|
|
|
|
/// Used for new accounts that have no transaction history
|
|
|
|
/// # Arguments
|
|
|
|
/// * `coin`: 0 for zcash, 1 for ycash
|
2022-06-08 05:48:16 -07:00
|
|
|
pub async fn skip_to_last_height(coin: u8) -> anyhow::Result<()> {
|
2022-07-08 01:27:39 -07:00
|
|
|
let c = CoinConfig::get(coin);
|
2022-06-08 05:48:16 -07:00
|
|
|
let mut client = c.connect_lwd().await?;
|
|
|
|
let last_height = crate::chain::get_latest_height(&mut client).await?;
|
2022-07-08 01:27:39 -07:00
|
|
|
fetch_and_store_tree_state(coin, &mut client, last_height).await?;
|
2022-06-08 05:48:16 -07:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2022-10-19 23:24:36 -07:00
|
|
|
/// Rewind to a previous block height
|
|
|
|
///
|
|
|
|
/// Height is snapped to a closest earlier checkpoint.
|
|
|
|
/// The effective height is returned
|
2022-09-06 19:38:16 -07:00
|
|
|
pub async fn rewind_to(height: u32) -> anyhow::Result<u32> {
|
2022-06-08 05:48:16 -07:00
|
|
|
let c = CoinConfig::get_active();
|
2022-09-06 19:38:16 -07:00
|
|
|
let height = c.db()?.trim_to_height(height)?;
|
2022-09-02 08:11:50 -07:00
|
|
|
Ok(height)
|
2022-06-08 05:48:16 -07:00
|
|
|
}
|
|
|
|
|
2022-10-19 23:24:36 -07:00
|
|
|
/// Synchronize from a given height
|
2022-09-06 19:38:16 -07:00
|
|
|
pub async fn rescan_from(height: u32) -> anyhow::Result<()> {
|
|
|
|
let c = CoinConfig::get_active();
|
|
|
|
c.db()?.truncate_sync_data()?;
|
|
|
|
let mut client = c.connect_lwd().await?;
|
|
|
|
fetch_and_store_tree_state(c.coin, &mut client, height).await?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2022-06-08 05:48:16 -07:00
|
|
|
async fn fetch_and_store_tree_state(
|
2022-07-08 01:27:39 -07:00
|
|
|
coin: u8,
|
2022-06-08 05:48:16 -07:00
|
|
|
client: &mut CompactTxStreamerClient<Channel>,
|
|
|
|
height: u32,
|
|
|
|
) -> anyhow::Result<()> {
|
2022-07-08 01:27:39 -07:00
|
|
|
let c = CoinConfig::get(coin);
|
2022-06-08 05:48:16 -07:00
|
|
|
let block_id = BlockId {
|
|
|
|
height: height as u64,
|
|
|
|
hash: vec![],
|
|
|
|
};
|
|
|
|
let block = client.get_block(block_id.clone()).await?.into_inner();
|
|
|
|
let tree_state = client
|
|
|
|
.get_tree_state(Request::new(block_id))
|
|
|
|
.await?
|
|
|
|
.into_inner();
|
2022-11-15 02:21:47 -08:00
|
|
|
let sapling_tree = CTree::read(&*hex::decode(&tree_state.sapling_tree)?)?; // retrieve orchard state and store it too
|
|
|
|
let orchard_tree = if !tree_state.orchard_tree.is_empty() {
|
|
|
|
CTree::read(&*hex::decode(&tree_state.orchard_tree)?)? // retrieve orchard state and store it too
|
|
|
|
} else {
|
|
|
|
CTree::new()
|
|
|
|
};
|
2022-07-12 00:28:58 -07:00
|
|
|
let db = c.db()?;
|
2022-11-15 02:21:47 -08:00
|
|
|
DbAdapter::store_block(
|
|
|
|
&db.connection,
|
|
|
|
height,
|
|
|
|
&block.hash,
|
|
|
|
block.time,
|
|
|
|
&sapling_tree,
|
|
|
|
&orchard_tree,
|
|
|
|
)?;
|
2022-06-08 05:48:16 -07:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2022-10-19 23:24:36 -07:00
|
|
|
/// Return the date of sapling activation
|
2022-06-08 05:48:16 -07:00
|
|
|
pub async fn get_activation_date() -> anyhow::Result<u32> {
|
|
|
|
let c = CoinConfig::get_active();
|
|
|
|
let mut client = c.connect_lwd().await?;
|
|
|
|
let date_time = crate::chain::get_activation_date(c.chain.network(), &mut client).await?;
|
|
|
|
Ok(date_time)
|
|
|
|
}
|
|
|
|
|
2022-10-19 23:24:36 -07:00
|
|
|
/// Return the block height for a given timestamp
|
|
|
|
/// # Arguments
|
|
|
|
/// * `time`: seconds since epoch
|
2022-06-08 05:48:16 -07:00
|
|
|
pub async fn get_block_by_time(time: u32) -> anyhow::Result<u32> {
|
|
|
|
let c = CoinConfig::get_active();
|
|
|
|
let mut client = c.connect_lwd().await?;
|
|
|
|
let date_time = crate::chain::get_block_by_time(c.chain.network(), &mut client, time).await?;
|
|
|
|
Ok(date_time)
|
|
|
|
}
|
2022-09-04 04:19:49 -07:00
|
|
|
|
2022-11-05 05:42:55 -07:00
|
|
|
#[allow(dead_code)]
|
2022-10-19 23:24:36 -07:00
|
|
|
fn trial_decrypt(
|
2022-09-05 08:05:55 -07:00
|
|
|
height: u32,
|
|
|
|
cmu: &[u8],
|
|
|
|
epk: &[u8],
|
|
|
|
ciphertext: &[u8],
|
|
|
|
) -> anyhow::Result<Option<Note>> {
|
2022-09-04 04:19:49 -07:00
|
|
|
let c = CoinConfig::get_active();
|
|
|
|
let AccountData { fvk, .. } = c.db().unwrap().get_account_info(c.id_account)?;
|
2022-09-05 08:05:55 -07:00
|
|
|
let note =
|
|
|
|
crate::scan::trial_decrypt_one(c.chain.network(), height, &fvk, cmu, epk, ciphertext)?;
|
2022-09-04 04:19:49 -07:00
|
|
|
Ok(note)
|
|
|
|
}
|