parent
48c5f45259
commit
fd47863277
|
@ -1,6 +1,7 @@
|
||||||
// Account creation
|
// Account creation
|
||||||
|
|
||||||
use crate::coinconfig::CoinConfig;
|
use crate::coinconfig::CoinConfig;
|
||||||
|
use crate::db::AccountData;
|
||||||
use crate::key2::decode_key;
|
use crate::key2::decode_key;
|
||||||
use crate::taddr::{derive_taddr, derive_tkeys};
|
use crate::taddr::{derive_taddr, derive_tkeys};
|
||||||
use crate::transaction::retrieve_tx_info;
|
use crate::transaction::retrieve_tx_info;
|
||||||
|
@ -36,7 +37,7 @@ pub fn new_account(
|
||||||
pub fn new_sub_account(name: &str, index: Option<u32>, count: u32) -> anyhow::Result<()> {
|
pub fn new_sub_account(name: &str, index: Option<u32>, count: u32) -> anyhow::Result<()> {
|
||||||
let c = CoinConfig::get_active();
|
let c = CoinConfig::get_active();
|
||||||
let db = c.db()?;
|
let db = c.db()?;
|
||||||
let (seed, _) = db.get_seed(c.id_account)?;
|
let AccountData { seed, .. } = db.get_account_info(c.id_account)?;
|
||||||
let seed = seed.ok_or_else(|| anyhow!("Account has no seed"))?;
|
let seed = seed.ok_or_else(|| anyhow!("Account has no seed"))?;
|
||||||
let index = index.unwrap_or_else(|| db.next_account_id(&seed).unwrap());
|
let index = index.unwrap_or_else(|| db.next_account_id(&seed).unwrap());
|
||||||
drop(db);
|
drop(db);
|
||||||
|
@ -61,7 +62,7 @@ fn new_account_with_key(coin: u8, name: &str, key: &str, index: u32) -> anyhow::
|
||||||
pub fn import_transparent_key(coin: u8, id_account: u32, path: &str) -> anyhow::Result<()> {
|
pub fn import_transparent_key(coin: u8, id_account: u32, path: &str) -> anyhow::Result<()> {
|
||||||
let c = CoinConfig::get(coin);
|
let c = CoinConfig::get(coin);
|
||||||
let db = c.db()?;
|
let db = c.db()?;
|
||||||
let (seed, _) = db.get_seed(c.id_account)?;
|
let AccountData { seed, .. } = db.get_account_info(c.id_account)?;
|
||||||
let seed = seed.ok_or_else(|| anyhow!("Account has no seed"))?;
|
let seed = seed.ok_or_else(|| anyhow!("Account has no seed"))?;
|
||||||
let (sk, addr) = derive_tkeys(c.chain.network(), &seed, path)?;
|
let (sk, addr) = derive_tkeys(c.chain.network(), &seed, path)?;
|
||||||
db.store_transparent_key(id_account, &sk, &addr)?;
|
db.store_transparent_key(id_account, &sk, &addr)?;
|
||||||
|
@ -79,10 +80,10 @@ pub fn import_transparent_secret_key(coin: u8, id_account: u32, sk: &str) -> any
|
||||||
pub fn new_diversified_address() -> anyhow::Result<String> {
|
pub fn new_diversified_address() -> anyhow::Result<String> {
|
||||||
let c = CoinConfig::get_active();
|
let c = CoinConfig::get_active();
|
||||||
let db = c.db()?;
|
let db = c.db()?;
|
||||||
let ivk = db.get_ivk(c.id_account)?;
|
let AccountData { fvk, .. } = db.get_account_info(c.id_account)?;
|
||||||
let fvk = decode_extended_full_viewing_key(
|
let fvk = decode_extended_full_viewing_key(
|
||||||
c.chain.network().hrp_sapling_extended_full_viewing_key(),
|
c.chain.network().hrp_sapling_extended_full_viewing_key(),
|
||||||
&ivk,
|
&fvk,
|
||||||
)?
|
)?
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let mut diversifier_index = db.get_diversifier(c.id_account)?;
|
let mut diversifier_index = db.get_diversifier(c.id_account)?;
|
||||||
|
@ -122,20 +123,20 @@ pub async fn scan_transparent_accounts(gap_limit: usize) -> anyhow::Result<()> {
|
||||||
|
|
||||||
pub fn get_backup(account: u32) -> anyhow::Result<String> {
|
pub fn get_backup(account: u32) -> anyhow::Result<String> {
|
||||||
let c = CoinConfig::get_active();
|
let c = CoinConfig::get_active();
|
||||||
let (seed, sk, ivk) = c.db()?.get_backup(account)?;
|
let AccountData { seed, sk, fvk, .. } = c.db()?.get_account_info(account)?;
|
||||||
if let Some(seed) = seed {
|
if let Some(seed) = seed {
|
||||||
return Ok(seed);
|
return Ok(seed);
|
||||||
}
|
}
|
||||||
if let Some(sk) = sk {
|
if let Some(sk) = sk {
|
||||||
return Ok(sk);
|
return Ok(sk);
|
||||||
}
|
}
|
||||||
Ok(ivk)
|
Ok(fvk)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_sk(account: u32) -> anyhow::Result<String> {
|
pub fn get_sk(account: u32) -> anyhow::Result<String> {
|
||||||
let c = CoinConfig::get_active();
|
let c = CoinConfig::get_active();
|
||||||
let sk = c.db()?.get_sk(account)?;
|
let AccountData { sk, .. } = c.db()?.get_account_info(account)?;
|
||||||
Ok(sk)
|
Ok(sk.unwrap_or(String::new()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reset_db(coin: u8) -> anyhow::Result<()> {
|
pub fn reset_db(coin: u8) -> anyhow::Result<()> {
|
||||||
|
@ -184,7 +185,7 @@ pub fn derive_keys(
|
||||||
) -> anyhow::Result<KeyPack> {
|
) -> anyhow::Result<KeyPack> {
|
||||||
let c = CoinConfig::get(coin);
|
let c = CoinConfig::get(coin);
|
||||||
let db = c.db()?;
|
let db = c.db()?;
|
||||||
let (seed, _) = db.get_seed(id_account)?;
|
let AccountData { seed, .. } = db.get_account_info(id_account)?;
|
||||||
let seed = seed.unwrap();
|
let seed = seed.unwrap();
|
||||||
derive_zip32(c.chain.network(), &seed, account, external, address)
|
derive_zip32(c.chain.network(), &seed, account, external, address)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ use crate::api::payment::{build_sign_send_multi_payment, RecipientMemo};
|
||||||
use crate::api::sync::get_latest_height;
|
use crate::api::sync::get_latest_height;
|
||||||
use crate::coinconfig::CoinConfig;
|
use crate::coinconfig::CoinConfig;
|
||||||
use crate::contact::{serialize_contacts, Contact};
|
use crate::contact::{serialize_contacts, Contact};
|
||||||
|
use crate::db::AccountData;
|
||||||
use zcash_primitives::memo::Memo;
|
use zcash_primitives::memo::Memo;
|
||||||
|
|
||||||
pub fn store_contact(id: u32, name: &str, address: &str, dirty: bool) -> anyhow::Result<()> {
|
pub fn store_contact(id: u32, name: &str, address: &str, dirty: bool) -> anyhow::Result<()> {
|
||||||
|
@ -26,7 +27,7 @@ pub async fn commit_unsaved_contacts(anchor_offset: u32) -> anyhow::Result<Strin
|
||||||
pub async fn save_contacts_tx(memos: &[Memo], anchor_offset: u32) -> anyhow::Result<String> {
|
pub async fn save_contacts_tx(memos: &[Memo], anchor_offset: u32) -> anyhow::Result<String> {
|
||||||
let c = CoinConfig::get_active();
|
let c = CoinConfig::get_active();
|
||||||
let last_height = get_latest_height().await?;
|
let last_height = get_latest_height().await?;
|
||||||
let address = c.db()?.get_address(c.id_account)?;
|
let AccountData { address, .. } = c.db()?.get_account_info(c.id_account)?;
|
||||||
let recipients: Vec<_> = memos
|
let recipients: Vec<_> = memos
|
||||||
.iter()
|
.iter()
|
||||||
.map(|m| RecipientMemo {
|
.map(|m| RecipientMemo {
|
||||||
|
|
|
@ -534,7 +534,7 @@ pub unsafe extern "C" fn parse_payment_uri(uri: *mut c_char) -> *mut c_char {
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn generate_random_enc_key() -> *mut c_char {
|
pub unsafe extern "C" fn generate_random_enc_key() -> *mut c_char {
|
||||||
to_c_str(log_string(crate::key2::generate_random_enc_key()))
|
to_c_str(log_string(crate::key::generate_random_enc_key()))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
|
|
@ -2,11 +2,12 @@ use zcash_client_backend::encoding::decode_extended_full_viewing_key;
|
||||||
use zcash_primitives::consensus::Parameters;
|
use zcash_primitives::consensus::Parameters;
|
||||||
|
|
||||||
use crate::coinconfig::CoinConfig;
|
use crate::coinconfig::CoinConfig;
|
||||||
|
use crate::db::AccountData;
|
||||||
use crate::get_latest_height;
|
use crate::get_latest_height;
|
||||||
|
|
||||||
pub async fn scan() -> anyhow::Result<i64> {
|
pub async fn scan() -> anyhow::Result<i64> {
|
||||||
let c = CoinConfig::get_active();
|
let c = CoinConfig::get_active();
|
||||||
let ivk = c.db()?.get_ivk(c.id_account)?;
|
let AccountData { fvk, .. } = c.db()?.get_account_info(c.id_account)?;
|
||||||
let mut client = c.connect_lwd().await?;
|
let mut client = c.connect_lwd().await?;
|
||||||
let height = get_latest_height(&mut client).await?;
|
let height = get_latest_height(&mut client).await?;
|
||||||
let mut mempool = c.mempool.lock().unwrap();
|
let mut mempool = c.mempool.lock().unwrap();
|
||||||
|
@ -17,7 +18,7 @@ pub async fn scan() -> anyhow::Result<i64> {
|
||||||
}
|
}
|
||||||
let fvk = decode_extended_full_viewing_key(
|
let fvk = decode_extended_full_viewing_key(
|
||||||
c.chain.network().hrp_sapling_extended_full_viewing_key(),
|
c.chain.network().hrp_sapling_extended_full_viewing_key(),
|
||||||
&ivk,
|
&fvk,
|
||||||
)?
|
)?
|
||||||
.unwrap();
|
.unwrap();
|
||||||
mempool
|
mempool
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use anyhow::anyhow;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use secp256k1::SecretKey;
|
use secp256k1::SecretKey;
|
||||||
|
@ -12,7 +13,7 @@ use zcash_client_backend::encoding::{
|
||||||
use zcash_primitives::consensus::Parameters;
|
use zcash_primitives::consensus::Parameters;
|
||||||
use zcash_primitives::transaction::builder::Progress;
|
use zcash_primitives::transaction::builder::Progress;
|
||||||
|
|
||||||
use crate::db::ZMessage;
|
use crate::db::{AccountData, ZMessage};
|
||||||
use crate::taddr::get_utxos;
|
use crate::taddr::get_utxos;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use zcash_primitives::memo::Memo;
|
use zcash_primitives::memo::Memo;
|
||||||
|
@ -29,7 +30,7 @@ async fn prepare_multi_payment(
|
||||||
let c = CoinConfig::get_active();
|
let c = CoinConfig::get_active();
|
||||||
let mut tx_builder = TxBuilder::new(c.coin_type, last_height);
|
let mut tx_builder = TxBuilder::new(c.coin_type, last_height);
|
||||||
|
|
||||||
let fvk = c.db()?.get_ivk(c.id_account)?;
|
let AccountData { fvk, .. } = c.db()?.get_account_info(c.id_account)?;
|
||||||
let fvk = decode_extended_full_viewing_key(
|
let fvk = decode_extended_full_viewing_key(
|
||||||
c.chain.network().hrp_sapling_extended_full_viewing_key(),
|
c.chain.network().hrp_sapling_extended_full_viewing_key(),
|
||||||
&fvk,
|
&fvk,
|
||||||
|
@ -62,7 +63,8 @@ fn sign(tx: &Tx, progress_callback: PaymentProgressCallback) -> anyhow::Result<V
|
||||||
let c = CoinConfig::get_active();
|
let c = CoinConfig::get_active();
|
||||||
let prover = get_prover();
|
let prover = get_prover();
|
||||||
let db = c.db()?;
|
let db = c.db()?;
|
||||||
let zsk = db.get_sk(c.id_account)?;
|
let AccountData { sk: zsk, .. } = db.get_account_info(c.id_account)?;
|
||||||
|
let zsk = zsk.ok_or(anyhow!("Cannot sign without secret key"))?;
|
||||||
let tsk = db
|
let tsk = db
|
||||||
.get_tsk(c.id_account)?
|
.get_tsk(c.id_account)?
|
||||||
.map(|tsk| SecretKey::from_str(&tsk).unwrap());
|
.map(|tsk| SecretKey::from_str(&tsk).unwrap());
|
||||||
|
@ -122,7 +124,7 @@ pub async fn shield_taddr() -> anyhow::Result<String> {
|
||||||
|
|
||||||
pub fn parse_recipients(recipients: &str) -> anyhow::Result<Vec<RecipientMemo>> {
|
pub fn parse_recipients(recipients: &str) -> anyhow::Result<Vec<RecipientMemo>> {
|
||||||
let c = CoinConfig::get_active();
|
let c = CoinConfig::get_active();
|
||||||
let address = c.db()?.get_address(c.id_account)?;
|
let AccountData { address, .. } = c.db()?.get_account_info(c.id_account)?;
|
||||||
let recipients: Vec<Recipient> = serde_json::from_str(recipients)?;
|
let recipients: Vec<Recipient> = serde_json::from_str(recipients)?;
|
||||||
let recipient_memos: Vec<_> = recipients
|
let recipient_memos: Vec<_> = recipients
|
||||||
.iter()
|
.iter()
|
||||||
|
|
|
@ -2,11 +2,13 @@
|
||||||
|
|
||||||
use crate::coinconfig::CoinConfig;
|
use crate::coinconfig::CoinConfig;
|
||||||
use crate::scan::AMProgressCallback;
|
use crate::scan::AMProgressCallback;
|
||||||
use crate::{BlockId, CTree, CompactTxStreamerClient, DbAdapter};
|
use crate::{BlockId, CTree, CompactTxStreamerClient, DbAdapter, AccountData};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
use tonic::transport::Channel;
|
use tonic::transport::Channel;
|
||||||
use tonic::Request;
|
use tonic::Request;
|
||||||
|
use zcash_primitives::sapling::Note;
|
||||||
|
use crate::db::PlainNote;
|
||||||
|
|
||||||
const DEFAULT_CHUNK_SIZE: u32 = 100_000;
|
const DEFAULT_CHUNK_SIZE: u32 = 100_000;
|
||||||
|
|
||||||
|
@ -90,7 +92,6 @@ pub async fn skip_to_last_height(coin: u8) -> anyhow::Result<()> {
|
||||||
|
|
||||||
pub async fn rewind_to_height(height: u32) -> anyhow::Result<u32> {
|
pub async fn rewind_to_height(height: u32) -> anyhow::Result<u32> {
|
||||||
let c = CoinConfig::get_active();
|
let c = CoinConfig::get_active();
|
||||||
let mut client = c.connect_lwd().await?;
|
|
||||||
let height = c.db()?.trim_to_height(height, false)?;
|
let height = c.db()?.trim_to_height(height, false)?;
|
||||||
Ok(height)
|
Ok(height)
|
||||||
}
|
}
|
||||||
|
@ -129,3 +130,10 @@ pub async fn get_block_by_time(time: u32) -> anyhow::Result<u32> {
|
||||||
let date_time = crate::chain::get_block_by_time(c.chain.network(), &mut client, time).await?;
|
let date_time = crate::chain::get_block_by_time(c.chain.network(), &mut client, time).await?;
|
||||||
Ok(date_time)
|
Ok(date_time)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn trial_decrypt(height: u32, cmu: &[u8], epk: &[u8], ciphertext: &[u8]) -> anyhow::Result<Option<Note>> {
|
||||||
|
let c = CoinConfig::get_active();
|
||||||
|
let AccountData { fvk, .. } = c.db().unwrap().get_account_info(c.id_account)?;
|
||||||
|
let note = crate::scan::trial_decrypt_one(c.chain.network(), height, &fvk, cmu, epk, ciphertext)?;
|
||||||
|
Ok(note)
|
||||||
|
}
|
||||||
|
|
135
src/db.rs
135
src/db.rs
|
@ -214,7 +214,7 @@ impl DbAdapter {
|
||||||
.query_row(
|
.query_row(
|
||||||
"SELECT 1 from blocks WHERE height = ?1",
|
"SELECT 1 from blocks WHERE height = ?1",
|
||||||
params![height],
|
params![height],
|
||||||
|row| Ok(()),
|
|_| Ok(()),
|
||||||
)
|
)
|
||||||
.map_err(wrap_query_no_rows("trim_to_height: height not found"))?;
|
.map_err(wrap_query_no_rows("trim_to_height: height not found"))?;
|
||||||
height
|
height
|
||||||
|
@ -644,97 +644,6 @@ impl DbAdapter {
|
||||||
Ok(contacts)
|
Ok(contacts)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_backup(
|
|
||||||
&self,
|
|
||||||
account: u32,
|
|
||||||
) -> anyhow::Result<(Option<String>, Option<String>, String)> {
|
|
||||||
log::debug!("+get_backup");
|
|
||||||
let (seed, sk, ivk) = self
|
|
||||||
.connection
|
|
||||||
.query_row(
|
|
||||||
"SELECT seed, sk, ivk FROM accounts WHERE id_account = ?1",
|
|
||||||
params![account],
|
|
||||||
|row| {
|
|
||||||
let seed: Option<String> = row.get(0)?;
|
|
||||||
let sk: Option<String> = row.get(1)?;
|
|
||||||
let ivk: String = row.get(2)?;
|
|
||||||
Ok((seed, sk, ivk))
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.map_err(wrap_query_no_rows("get_backup"))?;
|
|
||||||
log::debug!("-get_backup");
|
|
||||||
Ok((seed, sk, ivk))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_seed(&self, account: u32) -> anyhow::Result<(Option<String>, u32)> {
|
|
||||||
log::info!("+get_seed");
|
|
||||||
let (seed, index) = self
|
|
||||||
.connection
|
|
||||||
.query_row(
|
|
||||||
"SELECT seed, aindex FROM accounts WHERE id_account = ?1",
|
|
||||||
params![account],
|
|
||||||
|row| {
|
|
||||||
let sk: Option<String> = row.get(0)?;
|
|
||||||
let index: u32 = row.get(1)?;
|
|
||||||
Ok((sk, index))
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.map_err(wrap_query_no_rows("get_seed"))?;
|
|
||||||
log::info!("-get_seed");
|
|
||||||
Ok((seed, index))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_sk(&self, account: u32) -> anyhow::Result<String> {
|
|
||||||
log::info!("+get_sk");
|
|
||||||
let sk = self
|
|
||||||
.connection
|
|
||||||
.query_row(
|
|
||||||
"SELECT sk FROM accounts WHERE id_account = ?1",
|
|
||||||
params![account],
|
|
||||||
|row| {
|
|
||||||
let sk: String = row.get(0)?;
|
|
||||||
Ok(sk)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.map_err(wrap_query_no_rows("get_sk"))?;
|
|
||||||
log::info!("-get_sk");
|
|
||||||
Ok(sk)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_ivk(&self, account: u32) -> anyhow::Result<String> {
|
|
||||||
log::debug!("+get_ivk");
|
|
||||||
let ivk = self
|
|
||||||
.connection
|
|
||||||
.query_row(
|
|
||||||
"SELECT ivk FROM accounts WHERE id_account = ?1",
|
|
||||||
params![account],
|
|
||||||
|row| {
|
|
||||||
let ivk: String = row.get(0)?;
|
|
||||||
Ok(ivk)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.map_err(wrap_query_no_rows("get_ivk"))?;
|
|
||||||
log::debug!("-get_ivk");
|
|
||||||
Ok(ivk)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_address(&self, account: u32) -> anyhow::Result<String> {
|
|
||||||
log::debug!("+get_address");
|
|
||||||
let address = self
|
|
||||||
.connection
|
|
||||||
.query_row(
|
|
||||||
"SELECT address FROM accounts WHERE id_account = ?1",
|
|
||||||
params![account],
|
|
||||||
|row| {
|
|
||||||
let address: String = row.get(0)?;
|
|
||||||
Ok(address)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.map_err(wrap_query_no_rows("get_address"))?;
|
|
||||||
log::debug!("-get_address");
|
|
||||||
Ok(address)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_diversifier(&self, account: u32) -> anyhow::Result<DiversifierIndex> {
|
pub fn get_diversifier(&self, account: u32) -> anyhow::Result<DiversifierIndex> {
|
||||||
let diversifier_index = self
|
let diversifier_index = self
|
||||||
.connection
|
.connection
|
||||||
|
@ -753,6 +662,33 @@ impl DbAdapter {
|
||||||
Ok(DiversifierIndex(diversifier_index))
|
Ok(DiversifierIndex(diversifier_index))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_account_info(&self, account: u32) -> anyhow::Result<AccountData> {
|
||||||
|
let account_data = self
|
||||||
|
.connection
|
||||||
|
.query_row(
|
||||||
|
"SELECT name, seed, sk, ivk, address, aindex FROM accounts WHERE id_account = ?1",
|
||||||
|
params![account],
|
||||||
|
|row| {
|
||||||
|
let name: String = row.get(0)?;
|
||||||
|
let seed: Option<String> = row.get(1)?;
|
||||||
|
let sk: Option<String> = row.get(2)?;
|
||||||
|
let fvk: String = row.get(3)?;
|
||||||
|
let address: String = row.get(4)?;
|
||||||
|
let aindex: u32 = row.get(5)?;
|
||||||
|
Ok(AccountData {
|
||||||
|
name,
|
||||||
|
seed,
|
||||||
|
sk,
|
||||||
|
fvk,
|
||||||
|
address,
|
||||||
|
aindex,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.map_err(wrap_query_no_rows("get_account_info"))?;
|
||||||
|
Ok(account_data)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn store_diversifier(
|
pub fn store_diversifier(
|
||||||
&self,
|
&self,
|
||||||
account: u32,
|
account: u32,
|
||||||
|
@ -798,9 +734,9 @@ impl DbAdapter {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_taddr(&self, account: u32) -> anyhow::Result<()> {
|
pub fn create_taddr(&self, account: u32) -> anyhow::Result<()> {
|
||||||
let (seed, index) = self.get_seed(account)?;
|
let AccountData { seed, aindex, .. } = self.get_account_info(account)?;
|
||||||
if let Some(seed) = seed {
|
if let Some(seed) = seed {
|
||||||
let bip44_path = format!("m/44'/{}'/0'/0/{}", self.network().coin_type(), index);
|
let bip44_path = format!("m/44'/{}'/0'/0/{}", self.network().coin_type(), aindex);
|
||||||
let (sk, address) = derive_tkeys(self.network(), &seed, &bip44_path)?;
|
let (sk, address) = derive_tkeys(self.network(), &seed, &bip44_path)?;
|
||||||
self.connection.execute(
|
self.connection.execute(
|
||||||
"INSERT INTO taddrs(account, sk, address) VALUES (?1, ?2, ?3) \
|
"INSERT INTO taddrs(account, sk, address) VALUES (?1, ?2, ?3) \
|
||||||
|
@ -1181,7 +1117,7 @@ pub struct AccountRec {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[serde_as]
|
#[serde_as]
|
||||||
#[derive(Clone, Serialize, Deserialize)]
|
#[derive(Clone, Serialize, Deserialize, Debug)]
|
||||||
pub struct PlainNote {
|
pub struct PlainNote {
|
||||||
pub height: u32,
|
pub height: u32,
|
||||||
pub value: u64,
|
pub value: u64,
|
||||||
|
@ -1273,3 +1209,12 @@ mod tests {
|
||||||
println!("{}", balance);
|
println!("{}", balance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct AccountData {
|
||||||
|
pub name: String,
|
||||||
|
pub seed: Option<String>,
|
||||||
|
pub sk: Option<String>,
|
||||||
|
pub fvk: String,
|
||||||
|
pub address: String,
|
||||||
|
pub aindex: u32,
|
||||||
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use std::convert::TryInto;
|
||||||
use crate::chain::{DecryptedBlock, DecryptedNote, Nf};
|
use crate::chain::{DecryptedBlock, DecryptedNote, Nf};
|
||||||
use crate::db::AccountViewKey;
|
use crate::db::AccountViewKey;
|
||||||
use crate::CompactBlock;
|
use crate::CompactBlock;
|
||||||
|
@ -119,16 +120,16 @@ fn collect_decrypted_notes(
|
||||||
for db in decrypted_blocks {
|
for db in decrypted_blocks {
|
||||||
let b = &db.compact_block;
|
let b = &db.compact_block;
|
||||||
let mut decrypted_notes = vec![];
|
let mut decrypted_notes = vec![];
|
||||||
let mut position_in_block = 0;
|
|
||||||
let domain = SaplingDomain::for_height(*network, BlockHeight::from_u32(b.height as u32));
|
let domain = SaplingDomain::for_height(*network, BlockHeight::from_u32(b.height as u32));
|
||||||
for (tx_index, tx) in b.vtx.iter().enumerate() {
|
for (tx_index, tx) in b.vtx.iter().enumerate() {
|
||||||
for (output_index, co) in tx.outputs.iter().enumerate() {
|
for (output_index, co) in tx.outputs.iter().enumerate() {
|
||||||
let plaintext = &output_buffer[i * buffer_stride + 64..i * buffer_stride + 116];
|
let plaintext = &output_buffer[i * buffer_stride + 32..i * buffer_stride + 84];
|
||||||
// version and amount must be in range - 21 million ZEC is less than 0x0008 0000 0000 0000
|
// version and amount must be in range - 21 million ZEC is less than 0x0008 0000 0000 0000
|
||||||
if plaintext[0] <= 2 && plaintext[18] < 0x08 && plaintext[19] == 0 {
|
if plaintext[0] <= 2 && plaintext[18] < 0x08 && plaintext[19] == 0 {
|
||||||
if let Some((note, pa)) =
|
if let Some((note, pa)) =
|
||||||
domain.parse_note_plaintext_without_memo_ivk(&ivk, plaintext)
|
domain.parse_note_plaintext_without_memo_ivk(&ivk, plaintext)
|
||||||
{
|
{
|
||||||
|
let position_in_block = usize::from_le_bytes(plaintext[52..60].try_into().unwrap());
|
||||||
let cmu = note.cmu().to_bytes();
|
let cmu = note.cmu().to_bytes();
|
||||||
if &cmu == co.cmu.as_slice() {
|
if &cmu == co.cmu.as_slice() {
|
||||||
log::info!("Note {} {}", account, u64::from(note.value));
|
log::info!("Note {} {}", account, u64::from(note.value));
|
||||||
|
@ -148,7 +149,6 @@ fn collect_decrypted_notes(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
i += 1;
|
i += 1;
|
||||||
position_in_block += 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
db.notes.extend(decrypted_notes);
|
db.notes.extend(decrypted_notes);
|
||||||
|
|
|
@ -16,7 +16,7 @@ use zcash_primitives::consensus::Network;
|
||||||
use zcash_primitives::sapling::SaplingIvk;
|
use zcash_primitives::sapling::SaplingIvk;
|
||||||
|
|
||||||
const THREADS_PER_BLOCK: usize = 256usize;
|
const THREADS_PER_BLOCK: usize = 256usize;
|
||||||
const BUFFER_SIZE: usize = 128usize;
|
const BUFFER_SIZE: usize = 96usize;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
pub static ref CUDA_CONTEXT: Mutex<Option<CudaContext>> = Mutex::new(CudaContext::new().ok());
|
pub static ref CUDA_CONTEXT: Mutex<Option<CudaContext>> = Mutex::new(CudaContext::new().ok());
|
||||||
|
@ -159,15 +159,20 @@ impl CudaProcessor {
|
||||||
let decrypted_blocks = collect_nf(blocks)?;
|
let decrypted_blocks = collect_nf(blocks)?;
|
||||||
|
|
||||||
let mut data_buffer = vec![0u8; n * BUFFER_SIZE];
|
let mut data_buffer = vec![0u8; n * BUFFER_SIZE];
|
||||||
let mut i = 0;
|
|
||||||
for db in decrypted_blocks.iter() {
|
for db in decrypted_blocks.iter() {
|
||||||
|
let mut i = 0;
|
||||||
|
let mut position_in_block = 0;
|
||||||
let b = &db.compact_block;
|
let b = &db.compact_block;
|
||||||
for tx in b.vtx.iter() {
|
for tx in b.vtx.iter() {
|
||||||
for co in tx.outputs.iter() {
|
for co in tx.outputs.iter() {
|
||||||
|
if co.epk.is_empty() { break } // skip decryption
|
||||||
data_buffer[i * BUFFER_SIZE..i * BUFFER_SIZE + 32].copy_from_slice(&co.epk);
|
data_buffer[i * BUFFER_SIZE..i * BUFFER_SIZE + 32].copy_from_slice(&co.epk);
|
||||||
data_buffer[i * BUFFER_SIZE + 64..i * BUFFER_SIZE + 116]
|
data_buffer[i * BUFFER_SIZE + 32..i * BUFFER_SIZE + 84]
|
||||||
.copy_from_slice(&co.ciphertext);
|
.copy_from_slice(&co.ciphertext);
|
||||||
|
data_buffer[i * BUFFER_SIZE + 84..i * BUFFER_SIZE + 92]
|
||||||
|
.copy_from_slice(&usize::to_le_bytes(position_in_block));
|
||||||
i += 1;
|
i += 1;
|
||||||
|
position_in_block += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
10
src/key2.rs
10
src/key2.rs
|
@ -1,8 +1,5 @@
|
||||||
use crate::coinconfig::CoinConfig;
|
use crate::coinconfig::CoinConfig;
|
||||||
use bech32::{ToBase32, Variant};
|
|
||||||
use bip39::{Language, Mnemonic, Seed};
|
use bip39::{Language, Mnemonic, Seed};
|
||||||
use rand::rngs::OsRng;
|
|
||||||
use rand::RngCore;
|
|
||||||
use zcash_client_backend::address::RecipientAddress;
|
use zcash_client_backend::address::RecipientAddress;
|
||||||
use zcash_client_backend::encoding::{
|
use zcash_client_backend::encoding::{
|
||||||
decode_extended_full_viewing_key, decode_extended_spending_key,
|
decode_extended_full_viewing_key, decode_extended_spending_key,
|
||||||
|
@ -98,10 +95,3 @@ fn derive_address(network: &Network, fvk: &ExtendedFullViewingKey) -> anyhow::Re
|
||||||
let address = encode_payment_address(network.hrp_sapling_payment_address(), &payment_address);
|
let address = encode_payment_address(network.hrp_sapling_payment_address(), &payment_address);
|
||||||
Ok(address)
|
Ok(address)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_random_enc_key() -> anyhow::Result<String> {
|
|
||||||
let mut key = [0u8; 32];
|
|
||||||
OsRng.fill_bytes(&mut key);
|
|
||||||
let key = bech32::encode("zwk", key.to_base32(), Variant::Bech32)?;
|
|
||||||
Ok(key)
|
|
||||||
}
|
|
||||||
|
|
|
@ -71,7 +71,7 @@ pub use crate::coinconfig::{
|
||||||
init_coin, set_active, set_active_account, set_coin_lwd_url, CoinConfig,
|
init_coin, set_active, set_active_account, set_coin_lwd_url, CoinConfig,
|
||||||
};
|
};
|
||||||
pub use crate::commitment::{CTree, Witness};
|
pub use crate::commitment::{CTree, Witness};
|
||||||
pub use crate::db::{AccountInfo, AccountRec, DbAdapter, TxRec};
|
pub use crate::db::{AccountInfo, AccountRec, AccountData, DbAdapter, TxRec};
|
||||||
pub use crate::fountain::{put_drop, FountainCodes, RaptorQDrops};
|
pub use crate::fountain::{put_drop, FountainCodes, RaptorQDrops};
|
||||||
pub use crate::hash::{pedersen_hash, Hash, GENERATORS_EXP};
|
pub use crate::hash::{pedersen_hash, Hash, GENERATORS_EXP};
|
||||||
pub use crate::key::{generate_random_enc_key, KeyHelpers};
|
pub use crate::key::{generate_random_enc_key, KeyHelpers};
|
||||||
|
|
|
@ -15,10 +15,7 @@ use std::sync::Mutex;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use warp_api_ffi::api::payment::{Recipient, RecipientMemo};
|
use warp_api_ffi::api::payment::{Recipient, RecipientMemo};
|
||||||
use warp_api_ffi::api::payment_uri::PaymentURI;
|
use warp_api_ffi::api::payment_uri::PaymentURI;
|
||||||
use warp_api_ffi::{
|
use warp_api_ffi::{derive_zip32, get_best_server, AccountInfo, AccountRec, CoinConfig, KeyPack, RaptorQDrops, Tx, TxRec, AccountData};
|
||||||
derive_zip32, get_best_server, AccountInfo, AccountRec, CoinConfig, KeyPack, RaptorQDrops, Tx,
|
|
||||||
TxRec,
|
|
||||||
};
|
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref SYNC_CANCELED: Mutex<bool> = Mutex::new(false);
|
static ref SYNC_CANCELED: Mutex<bool> = Mutex::new(false);
|
||||||
|
@ -26,6 +23,8 @@ lazy_static! {
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
|
#[error(transparent)]
|
||||||
|
Hex(#[from] hex::FromHexError),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
Reqwest(#[from] reqwest::Error),
|
Reqwest(#[from] reqwest::Error),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
|
@ -69,6 +68,9 @@ async fn main() -> anyhow::Result<()> {
|
||||||
let yec: HashMap<String, String> = figment.extract_inner("yec")?;
|
let yec: HashMap<String, String> = figment.extract_inner("yec")?;
|
||||||
init(1, yec)?;
|
init(1, yec)?;
|
||||||
|
|
||||||
|
warp_api_ffi::set_active_account(0, 1);
|
||||||
|
warp_api_ffi::set_active(0);
|
||||||
|
|
||||||
let _ = rocket
|
let _ = rocket
|
||||||
.mount(
|
.mount(
|
||||||
"/",
|
"/",
|
||||||
|
@ -95,6 +97,7 @@ async fn main() -> anyhow::Result<()> {
|
||||||
merge_data,
|
merge_data,
|
||||||
derive_keys,
|
derive_keys,
|
||||||
instant_sync,
|
instant_sync,
|
||||||
|
trial_decrypt,
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
.attach(AdHoc::config::<Config>())
|
.attach(AdHoc::config::<Config>())
|
||||||
|
@ -169,7 +172,7 @@ pub async fn get_latest_height() -> Result<Json<Heights>, Error> {
|
||||||
pub fn get_address() -> Result<String, Error> {
|
pub fn get_address() -> Result<String, Error> {
|
||||||
let c = CoinConfig::get_active();
|
let c = CoinConfig::get_active();
|
||||||
let db = c.db()?;
|
let db = c.db()?;
|
||||||
let address = db.get_address(c.id_account)?;
|
let AccountData { address, .. } = db.get_account_info(c.id_account)?;
|
||||||
Ok(address)
|
Ok(address)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,7 +183,7 @@ pub fn get_backup(config: &State<Config>) -> Result<Json<Backup>, Error> {
|
||||||
} else {
|
} else {
|
||||||
let c = CoinConfig::get_active();
|
let c = CoinConfig::get_active();
|
||||||
let db = c.db()?;
|
let db = c.db()?;
|
||||||
let (seed, sk, fvk) = db.get_backup(c.id_account)?;
|
let AccountData { seed, sk, fvk, .. } = db.get_account_info(c.id_account)?;
|
||||||
Ok(Json(Backup { seed, sk, fvk }))
|
Ok(Json(Backup { seed, sk, fvk }))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -207,7 +210,8 @@ pub async fn create_offline_tx(payment: Json<Payment>) -> Result<Json<Tx>, Error
|
||||||
let latest = warp_api_ffi::api::sync::get_latest_height().await?;
|
let latest = warp_api_ffi::api::sync::get_latest_height().await?;
|
||||||
let from = {
|
let from = {
|
||||||
let db = c.db()?;
|
let db = c.db()?;
|
||||||
db.get_address(c.id_account)?
|
let AccountData { address, .. } = db.get_account_info(c.id_account)?;
|
||||||
|
address
|
||||||
};
|
};
|
||||||
let recipients: Vec<_> = payment
|
let recipients: Vec<_> = payment
|
||||||
.recipients
|
.recipients
|
||||||
|
@ -244,7 +248,8 @@ pub async fn pay(payment: Json<Payment>, config: &State<Config>) -> Result<Strin
|
||||||
let latest = warp_api_ffi::api::sync::get_latest_height().await?;
|
let latest = warp_api_ffi::api::sync::get_latest_height().await?;
|
||||||
let from = {
|
let from = {
|
||||||
let db = c.db()?;
|
let db = c.db()?;
|
||||||
db.get_address(c.id_account)?
|
let AccountData { address, .. } = db.get_account_info(c.id_account)?;
|
||||||
|
address
|
||||||
};
|
};
|
||||||
let recipients: Vec<_> = payment
|
let recipients: Vec<_> = payment
|
||||||
.recipients
|
.recipients
|
||||||
|
@ -323,12 +328,22 @@ pub fn derive_keys(
|
||||||
Ok(Json(result))
|
Ok(Json(result))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[post("/trial_decrypt?<height>&<cmu>&<epk>&<ciphertext>")]
|
||||||
|
pub async fn trial_decrypt(height: u32, cmu: String, epk: String, ciphertext: String) -> Result<String, Error> {
|
||||||
|
let epk = hex::decode(&epk)?;
|
||||||
|
let cmu = hex::decode(&cmu)?;
|
||||||
|
let ciphertext = hex::decode(&ciphertext)?;
|
||||||
|
let note = warp_api_ffi::api::sync::trial_decrypt(height, &cmu, &epk, &ciphertext)?;
|
||||||
|
log::info!("{:?}", note);
|
||||||
|
Ok(note.is_some().to_string())
|
||||||
|
}
|
||||||
|
|
||||||
#[post("/instant_sync")]
|
#[post("/instant_sync")]
|
||||||
pub async fn instant_sync() -> Result<(), Error> {
|
pub async fn instant_sync() -> Result<(), Error> {
|
||||||
let c = CoinConfig::get_active();
|
let c = CoinConfig::get_active();
|
||||||
let fvk = {
|
let fvk = {
|
||||||
let db = c.db()?;
|
let db = c.db()?;
|
||||||
let (_, _, fvk) = db.get_backup(c.id_account)?;
|
let AccountData { fvk, .. } = db.get_account_info(c.id_account)?;
|
||||||
fvk
|
fvk
|
||||||
};
|
};
|
||||||
let client = reqwest::Client::new();
|
let client = reqwest::Client::new();
|
||||||
|
|
55
src/scan.rs
55
src/scan.rs
|
@ -1,12 +1,10 @@
|
||||||
use crate::builder::BlockProcessor;
|
use crate::builder::BlockProcessor;
|
||||||
use crate::chain::{DecryptedBlock, Nf, NfRef, TRIAL_DECRYPTIONS};
|
use crate::chain::{DecryptedBlock, Nf, NfRef, TRIAL_DECRYPTIONS};
|
||||||
use crate::db::{DbAdapter, ReceivedNote};
|
use crate::db::{AccountViewKey, DbAdapter, PlainNote, ReceivedNote};
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
use crate::transaction::retrieve_tx_info;
|
use crate::transaction::retrieve_tx_info;
|
||||||
use crate::{
|
use crate::{connect_lightwalletd, download_chain, get_latest_height, CompactBlock, DecryptNode, Witness, CompactTx, CompactSaplingOutput};
|
||||||
connect_lightwalletd, download_chain, get_latest_height, CompactBlock, DecryptNode, Witness,
|
|
||||||
};
|
|
||||||
use ff::PrimeField;
|
use ff::PrimeField;
|
||||||
|
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
|
@ -14,12 +12,15 @@ use std::collections::HashMap;
|
||||||
use std::panic;
|
use std::panic;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
use anyhow::anyhow;
|
||||||
use tokio::runtime::{Builder, Runtime};
|
use tokio::runtime::{Builder, Runtime};
|
||||||
use tokio::sync::mpsc;
|
use tokio::sync::mpsc;
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
|
use zcash_client_backend::encoding::decode_extended_full_viewing_key;
|
||||||
|
use zcash_primitives::consensus::{Network, Parameters};
|
||||||
use zcash_params::coin::{get_coin_chain, CoinType};
|
use zcash_params::coin::{get_coin_chain, CoinType};
|
||||||
|
|
||||||
use zcash_primitives::sapling::Node;
|
use zcash_primitives::sapling::{Node, Note};
|
||||||
|
|
||||||
pub struct Blocks(pub Vec<CompactBlock>);
|
pub struct Blocks(pub Vec<CompactBlock>);
|
||||||
|
|
||||||
|
@ -66,7 +67,7 @@ pub async fn sync_async(
|
||||||
|
|
||||||
let mut client = connect_lightwalletd(&ld_url).await?;
|
let mut client = connect_lightwalletd(&ld_url).await?;
|
||||||
let (start_height, prev_hash, vks) = {
|
let (start_height, prev_hash, vks) = {
|
||||||
let mut db = DbAdapter::new(coin_type, &db_path)?;
|
let db = DbAdapter::new(coin_type, &db_path)?;
|
||||||
let height = db.get_db_height()?;
|
let height = db.get_db_height()?;
|
||||||
let hash = db.get_db_hash(height)?;
|
let hash = db.get_db_hash(height)?;
|
||||||
let vks = db.get_fvks()?;
|
let vks = db.get_fvks()?;
|
||||||
|
@ -357,3 +358,45 @@ pub async fn latest_height(ld_url: &str) -> anyhow::Result<u32> {
|
||||||
let height = get_latest_height(&mut client).await?;
|
let height = get_latest_height(&mut client).await?;
|
||||||
Ok(height)
|
Ok(height)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
// test function
|
||||||
|
pub fn trial_decrypt_one(network: &Network, height: u32, fvk: &str, cmu: &[u8], epk: &[u8], ciphertext: &[u8]) -> anyhow::Result<Option<Note>> {
|
||||||
|
let mut vks = HashMap::new();
|
||||||
|
let fvk = decode_extended_full_viewing_key(network.hrp_sapling_extended_full_viewing_key(), &fvk)?.ok_or(anyhow!("Invalid FVK"))?;
|
||||||
|
let ivk = fvk.fvk.vk.ivk();
|
||||||
|
vks.insert(0, AccountViewKey {
|
||||||
|
fvk,
|
||||||
|
ivk,
|
||||||
|
viewonly: false
|
||||||
|
});
|
||||||
|
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![],
|
||||||
|
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(),
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}];
|
||||||
|
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)
|
||||||
|
}
|
14
src/taddr.rs
14
src/taddr.rs
|
@ -1,4 +1,5 @@
|
||||||
use crate::coinconfig::CoinConfig;
|
use crate::coinconfig::CoinConfig;
|
||||||
|
use crate::db::AccountData;
|
||||||
use crate::{AddressList, CompactTxStreamerClient, GetAddressUtxosArg, GetAddressUtxosReply};
|
use crate::{AddressList, CompactTxStreamerClient, GetAddressUtxosArg, GetAddressUtxosReply};
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use base58check::FromBase58Check;
|
use base58check::FromBase58Check;
|
||||||
|
@ -52,17 +53,20 @@ pub async fn scan_transparent_accounts(
|
||||||
let c = CoinConfig::get_active();
|
let c = CoinConfig::get_active();
|
||||||
let mut addresses = vec![];
|
let mut addresses = vec![];
|
||||||
let db = c.db()?;
|
let db = c.db()?;
|
||||||
let (seed, mut index) = db.get_seed(c.id_account)?;
|
let account_data = db.get_account_info(c.id_account)?;
|
||||||
|
let AccountData {
|
||||||
|
seed, mut aindex, ..
|
||||||
|
} = account_data;
|
||||||
if let Some(seed) = seed {
|
if let Some(seed) = seed {
|
||||||
let mut gap = 0;
|
let mut gap = 0;
|
||||||
while gap < gap_limit {
|
while gap < gap_limit {
|
||||||
let bip44_path = format!("m/44'/{}'/0'/0/{}", network.coin_type(), index);
|
let bip44_path = format!("m/44'/{}'/0'/0/{}", network.coin_type(), aindex);
|
||||||
log::info!("{} {}", index, bip44_path);
|
log::info!("{} {}", aindex, bip44_path);
|
||||||
let (_, address) = derive_tkeys(network, &seed, &bip44_path)?;
|
let (_, address) = derive_tkeys(network, &seed, &bip44_path)?;
|
||||||
let balance = get_taddr_balance(client, &address).await?;
|
let balance = get_taddr_balance(client, &address).await?;
|
||||||
if balance > 0 {
|
if balance > 0 {
|
||||||
addresses.push(TBalance {
|
addresses.push(TBalance {
|
||||||
index,
|
index: aindex,
|
||||||
address,
|
address,
|
||||||
balance,
|
balance,
|
||||||
});
|
});
|
||||||
|
@ -70,7 +74,7 @@ pub async fn scan_transparent_accounts(
|
||||||
} else {
|
} else {
|
||||||
gap += 1;
|
gap += 1;
|
||||||
}
|
}
|
||||||
index += 1;
|
aindex += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
db.store_t_scan(&addresses)?;
|
db.store_t_scan(&addresses)?;
|
||||||
|
|
Loading…
Reference in New Issue