2022-11-05 05:42:55 -07:00
|
|
|
use crate::chain::get_latest_height;
|
|
|
|
use crate::db::{AccountViewKey, DbAdapter};
|
2022-10-04 20:22:04 -07:00
|
|
|
use serde::Serialize;
|
2022-07-21 18:08:29 -07:00
|
|
|
|
2021-07-16 01:42:29 -07:00
|
|
|
use crate::transaction::retrieve_tx_info;
|
2022-11-05 05:42:55 -07:00
|
|
|
use crate::{connect_lightwalletd, CompactBlock, CompactSaplingOutput, CompactTx, DbAdapterBuilder};
|
2022-10-19 23:24:36 -07:00
|
|
|
use crate::chain::{DecryptNode, download_chain};
|
2022-07-21 18:08:29 -07:00
|
|
|
|
2022-09-05 08:05:55 -07:00
|
|
|
use anyhow::anyhow;
|
2022-08-21 09:40:14 -07:00
|
|
|
use lazy_static::lazy_static;
|
2021-09-12 21:08:31 -07:00
|
|
|
use std::collections::HashMap;
|
2021-06-24 05:08:20 -07:00
|
|
|
use std::sync::Arc;
|
2022-10-28 06:02:34 -07:00
|
|
|
use orchard::note_encryption::OrchardDomain;
|
2022-08-17 18:23:23 -07:00
|
|
|
use tokio::runtime::{Builder, Runtime};
|
2021-06-26 02:52:03 -07:00
|
|
|
use tokio::sync::mpsc;
|
2021-06-24 05:08:20 -07:00
|
|
|
use tokio::sync::Mutex;
|
2022-09-04 04:19:49 -07:00
|
|
|
use zcash_client_backend::encoding::decode_extended_full_viewing_key;
|
2022-06-07 09:58:24 -07:00
|
|
|
use zcash_params::coin::{get_coin_chain, CoinType};
|
2022-11-05 05:42:55 -07:00
|
|
|
use zcash_primitives::consensus::{Network, Parameters};
|
2021-06-18 01:17:41 -07:00
|
|
|
|
2022-11-05 05:42:55 -07:00
|
|
|
use zcash_primitives::sapling::Note;
|
2022-10-27 03:10:51 -07:00
|
|
|
use zcash_primitives::sapling::note_encryption::SaplingDomain;
|
2022-10-28 06:02:34 -07:00
|
|
|
use crate::orchard::{DecryptedOrchardNote, OrchardDecrypter, OrchardHasher, OrchardViewKey};
|
2022-10-27 03:10:51 -07:00
|
|
|
use crate::sapling::{DecryptedSaplingNote, SaplingDecrypter, SaplingHasher, SaplingViewKey};
|
2022-11-05 05:42:55 -07:00
|
|
|
use crate::sync::{Synchronizer, WarpProcessor};
|
2021-06-18 01:17:41 -07:00
|
|
|
|
2022-10-04 20:22:04 -07:00
|
|
|
pub struct Blocks(pub Vec<CompactBlock>, pub usize);
|
2021-06-21 17:33:13 -07:00
|
|
|
|
2022-08-17 18:23:23 -07:00
|
|
|
lazy_static! {
|
|
|
|
static ref DECRYPTER_RUNTIME: Runtime = Builder::new_multi_thread().build().unwrap();
|
|
|
|
}
|
|
|
|
|
2021-07-27 22:07:20 -07:00
|
|
|
#[derive(Debug)]
|
|
|
|
struct TxIdSet(Vec<u32>);
|
|
|
|
|
2021-06-21 17:33:13 -07:00
|
|
|
impl std::fmt::Debug for Blocks {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
write!(f, "Blocks of len {}", self.0.len())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-04 20:22:04 -07:00
|
|
|
#[derive(Clone, Serialize)]
|
|
|
|
pub struct Progress {
|
2022-10-19 23:24:36 -07:00
|
|
|
pub height: u32,
|
|
|
|
pub trial_decryptions: u64,
|
|
|
|
pub downloaded: usize,
|
2022-10-04 20:22:04 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
pub type ProgressCallback = dyn Fn(Progress) + Send;
|
2022-06-08 05:48:16 -07:00
|
|
|
pub type AMProgressCallback = Arc<Mutex<ProgressCallback>>;
|
2021-06-21 17:33:13 -07:00
|
|
|
|
2021-08-10 04:51:39 -07:00
|
|
|
#[derive(PartialEq, PartialOrd, Debug, Hash, Eq)]
|
|
|
|
pub struct TxIdHeight {
|
2021-09-12 21:08:31 -07:00
|
|
|
id_tx: u32,
|
2021-08-10 04:51:39 -07:00
|
|
|
height: u32,
|
|
|
|
index: u32,
|
|
|
|
}
|
|
|
|
|
2022-10-27 03:10:51 -07:00
|
|
|
type SaplingSynchronizer = Synchronizer<Network, SaplingDomain<Network>, SaplingViewKey, DecryptedSaplingNote,
|
|
|
|
SaplingDecrypter<Network>, SaplingHasher>;
|
|
|
|
|
2022-10-28 06:02:34 -07:00
|
|
|
type OrchardSynchronizer = Synchronizer<Network, OrchardDomain, OrchardViewKey, DecryptedOrchardNote,
|
|
|
|
OrchardDecrypter<Network>, OrchardHasher>;
|
|
|
|
|
2022-10-27 03:10:51 -07:00
|
|
|
pub async fn sync_async<'a>(
|
|
|
|
coin_type: CoinType,
|
|
|
|
_chunk_size: u32,
|
2022-11-05 05:42:55 -07:00
|
|
|
_get_tx: bool, // TODO
|
2022-10-27 03:10:51 -07:00
|
|
|
db_path: &'a str,
|
|
|
|
target_height_offset: u32,
|
|
|
|
max_cost: u32,
|
2022-11-05 05:42:55 -07:00
|
|
|
_progress_callback: AMProgressCallback, // TODO
|
2022-10-27 03:10:51 -07:00
|
|
|
cancel: &'static std::sync::Mutex<bool>,
|
|
|
|
ld_url: &'a str,
|
|
|
|
) -> anyhow::Result<()> {
|
|
|
|
let ld_url = ld_url.to_owned();
|
|
|
|
let db_path = db_path.to_owned();
|
|
|
|
let network = {
|
|
|
|
let chain = get_coin_chain(coin_type);
|
|
|
|
*chain.network()
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut client = connect_lightwalletd(&ld_url).await?;
|
2022-10-28 06:02:34 -07:00
|
|
|
let (start_height, prev_hash, sapling_vks, orchard_vks) = {
|
2022-10-27 03:10:51 -07:00
|
|
|
let db = DbAdapter::new(coin_type, &db_path)?;
|
|
|
|
let height = db.get_db_height()?;
|
|
|
|
let hash = db.get_db_hash(height)?;
|
2022-10-30 03:03:38 -07:00
|
|
|
let sapling_vks = db.get_sapling_fvks()?;
|
|
|
|
let orchard_vks = db.get_orchard_fvks()?;
|
2022-10-28 06:02:34 -07:00
|
|
|
(height, hash, sapling_vks, orchard_vks)
|
2022-10-27 03:10:51 -07:00
|
|
|
};
|
|
|
|
let end_height = get_latest_height(&mut client).await?;
|
|
|
|
let end_height = (end_height - target_height_offset).max(start_height);
|
|
|
|
if start_height >= end_height {
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
|
2022-11-04 18:58:35 -07:00
|
|
|
let mut height = start_height;
|
2022-10-27 03:10:51 -07:00
|
|
|
let (blocks_tx, mut blocks_rx) = mpsc::channel::<Blocks>(1);
|
|
|
|
tokio::spawn(async move {
|
|
|
|
download_chain(&mut client, start_height, end_height, prev_hash, max_cost, cancel, blocks_tx).await?;
|
|
|
|
Ok::<_, anyhow::Error>(())
|
|
|
|
});
|
|
|
|
|
|
|
|
let db_builder = DbAdapterBuilder { coin_type, db_path: db_path.clone() };
|
|
|
|
while let Some(blocks) = blocks_rx.recv().await {
|
|
|
|
let first_block = blocks.0.first().unwrap(); // cannot be empty because blocks are not
|
|
|
|
log::info!("Height: {}", first_block.height);
|
|
|
|
let last_block = blocks.0.last().unwrap();
|
2022-10-28 06:02:34 -07:00
|
|
|
let last_hash: [u8; 32] = last_block.hash.clone().try_into().unwrap();
|
2022-10-27 03:10:51 -07:00
|
|
|
let last_height = last_block.height as u32;
|
|
|
|
let last_timestamp = last_block.time;
|
|
|
|
|
2022-10-28 06:02:34 -07:00
|
|
|
// Sapling
|
2022-10-30 03:03:38 -07:00
|
|
|
log::info!("Sapling");
|
2022-10-28 06:02:34 -07:00
|
|
|
{
|
|
|
|
let decrypter = SaplingDecrypter::new(network);
|
|
|
|
let warper = WarpProcessor::new(SaplingHasher::default());
|
|
|
|
let mut synchronizer = SaplingSynchronizer::new(
|
|
|
|
decrypter,
|
|
|
|
warper,
|
|
|
|
sapling_vks.clone(),
|
|
|
|
db_builder.clone(),
|
|
|
|
"sapling".to_string(),
|
|
|
|
);
|
2022-11-04 18:58:35 -07:00
|
|
|
synchronizer.initialize(height)?;
|
2022-10-28 06:02:34 -07:00
|
|
|
synchronizer.process(&blocks.0)?;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Orchard
|
2022-10-30 03:03:38 -07:00
|
|
|
log::info!("Orchard");
|
2022-10-28 06:02:34 -07:00
|
|
|
{
|
|
|
|
let decrypter = OrchardDecrypter::new(network);
|
|
|
|
let warper = WarpProcessor::new(OrchardHasher::new());
|
|
|
|
let mut synchronizer = OrchardSynchronizer::new(
|
|
|
|
decrypter,
|
|
|
|
warper,
|
|
|
|
orchard_vks.clone(),
|
|
|
|
db_builder.clone(),
|
|
|
|
"orchard".to_string(),
|
|
|
|
);
|
2022-11-04 18:58:35 -07:00
|
|
|
synchronizer.initialize(height)?;
|
2022-10-28 06:02:34 -07:00
|
|
|
synchronizer.process(&blocks.0)?;
|
|
|
|
}
|
2022-10-27 03:10:51 -07:00
|
|
|
|
|
|
|
let db = db_builder.build()?;
|
2022-10-28 06:02:34 -07:00
|
|
|
db.store_block_timestamp(last_height, &last_hash, last_timestamp)?;
|
2022-11-04 18:58:35 -07:00
|
|
|
height = last_height;
|
2022-10-27 03:10:51 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2021-07-09 06:33:05 -07:00
|
|
|
pub async fn latest_height(ld_url: &str) -> anyhow::Result<u32> {
|
|
|
|
let mut client = connect_lightwalletd(ld_url).await?;
|
2021-06-24 05:08:20 -07:00
|
|
|
let height = get_latest_height(&mut client).await?;
|
|
|
|
Ok(height)
|
2021-06-21 17:33:13 -07:00
|
|
|
}
|
2022-09-04 04:19:49 -07:00
|
|
|
|
|
|
|
#[allow(dead_code)]
|
|
|
|
// test function
|
2022-09-05 08:05:55 -07:00
|
|
|
pub fn trial_decrypt_one(
|
|
|
|
network: &Network,
|
|
|
|
height: u32,
|
|
|
|
fvk: &str,
|
|
|
|
cmu: &[u8],
|
|
|
|
epk: &[u8],
|
|
|
|
ciphertext: &[u8],
|
|
|
|
) -> anyhow::Result<Option<Note>> {
|
2022-09-04 04:19:49 -07:00
|
|
|
let mut vks = HashMap::new();
|
2022-09-05 08:05:55 -07:00
|
|
|
let fvk =
|
2022-10-21 21:01:29 -07:00
|
|
|
decode_extended_full_viewing_key(network.hrp_sapling_extended_full_viewing_key(), &fvk)
|
2022-11-05 05:42:55 -07:00
|
|
|
.map_err(|_| anyhow!("Bech32 Decode Error"))?;
|
2022-09-04 04:19:49 -07:00
|
|
|
let ivk = fvk.fvk.vk.ivk();
|
2022-09-05 08:05:55 -07:00
|
|
|
vks.insert(
|
|
|
|
0,
|
|
|
|
AccountViewKey {
|
|
|
|
fvk,
|
|
|
|
ivk,
|
|
|
|
viewonly: false,
|
|
|
|
},
|
|
|
|
);
|
2022-09-04 04:19:49 -07:00
|
|
|
let dn = DecryptNode::new(vks);
|
|
|
|
let block = vec![CompactBlock {
|
|
|
|
proto_version: 0, // don't care about most of these fields
|
|
|
|
height: height as u64,
|
|
|
|
hash: vec![],
|
|
|
|
prev_hash: vec![],
|
|
|
|
time: 0,
|
|
|
|
header: vec![],
|
2022-09-05 08:05:55 -07:00
|
|
|
vtx: vec![CompactTx {
|
|
|
|
index: 0,
|
|
|
|
hash: vec![],
|
|
|
|
fee: 0,
|
|
|
|
spends: vec![],
|
|
|
|
actions: vec![],
|
|
|
|
outputs: vec![CompactSaplingOutput {
|
|
|
|
cmu: cmu.to_vec(),
|
|
|
|
epk: epk.to_vec(),
|
|
|
|
ciphertext: ciphertext.to_vec(),
|
|
|
|
}],
|
|
|
|
}],
|
2022-09-04 04:19:49 -07:00
|
|
|
}];
|
|
|
|
let decrypted_block = dn.decrypt_blocks(network, block);
|
|
|
|
let decrypted_block = decrypted_block.first().unwrap();
|
|
|
|
let note = decrypted_block.notes.first().map(|dn| dn.note.clone());
|
|
|
|
Ok(note)
|
2022-09-05 08:05:55 -07:00
|
|
|
}
|