diff --git a/binding.h b/binding.h index 229c0a5..1e65acf 100644 --- a/binding.h +++ b/binding.h @@ -271,7 +271,9 @@ struct CResult_____c_char shield_taddr(uint8_t coin, uint64_t amount, uint32_t confirmations); -struct CResult______u8 scan_transparent_accounts(uint32_t gap_limit); +struct CResult______u8 scan_transparent_accounts(uint8_t coin, + uint32_t account, + uint32_t gap_limit); struct CResult_____c_char prepare_multi_payment(uint8_t coin, uint32_t account, diff --git a/src/api/account.rs b/src/api/account.rs index cae419f..e28185d 100644 --- a/src/api/account.rs +++ b/src/api/account.rs @@ -4,7 +4,7 @@ use crate::coinconfig::CoinConfig; use crate::db::data_generated::fb::{ - AddressBalance, AddressBalanceArgs, AddressBalanceVec, AddressBalanceVecArgs, BackupT, KeyPackT, + BackupT, KeyPackT, AddressBalanceVecT, AddressBalanceT, }; use crate::db::AccountData; use crate::key2::decode_key; @@ -265,35 +265,24 @@ pub async fn get_taddr_balance(coin: u8, id_account: u32) -> anyhow::Result /// is exceeded and no balance was found /// # Arguments /// * `gap_limit`: number of accounts with 0 balance before the scan stops -pub async fn scan_transparent_accounts(gap_limit: usize) -> anyhow::Result> { - let c = CoinConfig::get_active(); - let mut client = c.connect_lwd().await?; - let addresses = - crate::taddr::scan_transparent_accounts(c.chain.network(), &mut client, gap_limit).await?; - let mut builder = flatbuffers::FlatBufferBuilder::new(); - let mut addrs = vec![]; - for a in addresses { - let address = builder.create_string(&a.address); - let ab = AddressBalance::create( - &mut builder, - &AddressBalanceArgs { - index: a.index, - address: Some(address), - balance: a.balance, - }, - ); - addrs.push(ab); +pub async fn scan_transparent_accounts(coin: u8, account: u32, gap_limit: usize) -> anyhow::Result { + let c = CoinConfig::get(coin); + let db = c.db()?; + let account_data = db.get_account_info(account)?; + let AccountData { + seed, aindex, .. + } = account_data; + let mut addresses = vec![]; + if let Some(seed) = seed { + let mut client = c.connect_lwd().await?; + addresses.extend(crate::taddr::scan_transparent_accounts(c.chain.network(), &mut client, &seed, aindex, gap_limit).await?); } - let addrs = builder.create_vector(&addrs); - let addrs = AddressBalanceVec::create( - &mut builder, - &AddressBalanceVecArgs { - values: Some(addrs), - }, - ); - builder.finish(addrs, None); - let data = builder.finished_data().to_vec(); - Ok(data) + let addresses: Vec<_> = addresses.iter().map(|a| AddressBalanceT { index: a.index, + address: Some(a.address.clone()), balance: a.balance }).collect(); + let addresses = AddressBalanceVecT { + values: Some(addresses) + }; + Ok(addresses) } /// Get the backup string. It is either the passphrase, the secret key or the viewing key diff --git a/src/api/dart_ffi.rs b/src/api/dart_ffi.rs index be46521..17000ed 100644 --- a/src/api/dart_ffi.rs +++ b/src/api/dart_ffi.rs @@ -507,9 +507,15 @@ pub async unsafe extern "C" fn shield_taddr( #[tokio::main] #[no_mangle] -pub async unsafe extern "C" fn scan_transparent_accounts(gap_limit: u32) -> CResult<*const u8> { - let res = crate::api::account::scan_transparent_accounts(gap_limit as usize).await; - to_cresult_bytes(res) +pub async unsafe extern "C" fn scan_transparent_accounts(coin: u8, account: u32, gap_limit: u32) -> CResult<*const u8> { + let res = async { + let addresses = crate::api::account::scan_transparent_accounts(coin, account, gap_limit as usize).await?; + let mut builder = FlatBufferBuilder::new(); + let root = addresses.pack(&mut builder); + builder.finish(root, None); + Ok(builder.finished_data().to_vec()) + }; + to_cresult_bytes(res.await) } #[tokio::main] diff --git a/src/taddr.rs b/src/taddr.rs index edaff7c..d2675ba 100644 --- a/src/taddr.rs +++ b/src/taddr.rs @@ -1,6 +1,6 @@ use crate::api::payment_v2::build_tx_plan_with_utxos; use crate::api::recipient::RecipientMemo; -use crate::chain::{get_checkpoint_height, EXPIRY_HEIGHT_OFFSET}; +use crate::chain::{get_checkpoint_height, EXPIRY_HEIGHT_OFFSET, get_latest_height}; use crate::coinconfig::CoinConfig; use crate::db::AccountData; use crate::key2::split_key; @@ -8,7 +8,7 @@ use crate::note_selection::{SecretKeys, Source, UTXO}; use crate::unified::orchard_as_unified; use crate::{ broadcast_tx, build_tx, AddressList, BlockId, CompactTxStreamerClient, GetAddressUtxosArg, - GetAddressUtxosReply, Hash, TransparentAddressBlockFilter, TxFilter, + GetAddressUtxosReply, Hash, TransparentAddressBlockFilter, TxFilter, BlockRange, }; use anyhow::anyhow; use base58check::FromBase58Check; @@ -25,7 +25,7 @@ use tonic::transport::Channel; use tonic::Request; use zcash_client_backend::encoding::encode_transparent_address; use zcash_params::coin::get_branch; -use zcash_primitives::consensus::{Network, Parameters}; +use zcash_primitives::consensus::{Network, Parameters, NetworkUpgrade}; use zcash_primitives::legacy::TransparentAddress; use zcash_primitives::memo::Memo; use zcash_primitives::transaction::components::OutPoint; @@ -141,10 +141,11 @@ pub async fn get_ttx_history( pub async fn get_taddr_tx_count( client: &mut CompactTxStreamerClient, address: &str, + range: &BlockRange, ) -> anyhow::Result { let req = TransparentAddressBlockFilter { address: address.to_string(), - range: None, + range: Some(range.clone()), }; let rep = client .get_taddress_txids(Request::new(req)) @@ -173,39 +174,40 @@ pub async fn get_utxos( pub async fn scan_transparent_accounts( network: &Network, client: &mut CompactTxStreamerClient, + seed: &str, + mut aindex: u32, gap_limit: usize, ) -> anyhow::Result> { - let c = CoinConfig::get_active(); + let start: u32 = network.activation_height(NetworkUpgrade::Sapling).unwrap().into(); + let end = get_latest_height(client).await?; + + let range = BlockRange { + start: Some(BlockId { height: start as u64, hash: vec![] }), + end: Some(BlockId { height: end as u64, hash: vec![] }), spam_filter_threshold: 0 }; + let mut addresses = vec![]; - let db = c.db()?; - let account_data = db.get_account_info(c.id_account)?; - let AccountData { - seed, mut aindex, .. - } = account_data; - if let Some(seed) = seed { - let mut gap = 0; - while gap < gap_limit { - let bip44_path = format!("m/44'/{}'/0'/0/{}", network.coin_type(), aindex); - log::info!("{} {}", aindex, bip44_path); - let (_, address) = derive_tkeys(network, &seed, &bip44_path)?; - let balance = get_taddr_balance(client, &address).await?; - if balance > 0 { - addresses.push(TBalance { - index: aindex, - address, - balance, - }); + let mut gap = 0; + while gap < gap_limit { + let bip44_path = format!("m/44'/{}'/0'/0/{}", network.coin_type(), aindex); + log::info!("{} {}", aindex, bip44_path); + let (_, address) = derive_tkeys(network, &seed, &bip44_path)?; + let balance = get_taddr_balance(client, &address).await?; + if balance > 0 { + addresses.push(TBalance { + index: aindex, + address, + balance, + }); + gap = 0; + } else { + let tx_count = get_taddr_tx_count(client, &address, &range).await?; + if tx_count != 0 { gap = 0; } else { - let tx_count = get_taddr_tx_count(client, &address).await?; - if tx_count != 0 { - gap = 0; - } else { - gap += 1; - } + gap += 1; } - aindex += 1; } + aindex += 1; } Ok(addresses) }