diff --git a/binding.h b/binding.h index 42542eb..2b3ce7e 100644 --- a/binding.h +++ b/binding.h @@ -226,6 +226,8 @@ struct CResult_u8 convert_to_watchonly(uint8_t coin, uint32_t id_account); struct CResult______u8 get_backup(uint8_t coin, uint32_t id_account); +struct CResult_u8 get_available_addrs(uint8_t coin, uint32_t account); + struct CResult_____c_char get_address(uint8_t coin, uint32_t id_account, uint8_t ua_type); void import_transparent_key(uint8_t coin, uint32_t id_account, char *path); diff --git a/src/api/account.rs b/src/api/account.rs index e28185d..3204322 100644 --- a/src/api/account.rs +++ b/src/api/account.rs @@ -3,9 +3,7 @@ // Account creation use crate::coinconfig::CoinConfig; -use crate::db::data_generated::fb::{ - BackupT, KeyPackT, AddressBalanceVecT, AddressBalanceT, -}; +use crate::db::data_generated::fb::{AddressBalanceT, AddressBalanceVecT, BackupT, KeyPackT}; use crate::db::AccountData; use crate::key2::decode_key; use crate::orchard::OrchardKeyBytes; @@ -265,22 +263,39 @@ 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(coin: u8, account: u32, gap_limit: usize) -> anyhow::Result { +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 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?); + addresses.extend( + crate::taddr::scan_transparent_accounts( + c.chain.network(), + &mut client, + &seed, + aindex, + gap_limit, + ) + .await?, + ); } - let addresses: Vec<_> = addresses.iter().map(|a| AddressBalanceT { index: a.index, - address: Some(a.address.clone()), balance: a.balance }).collect(); + 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) + values: Some(addresses), }; Ok(addresses) } diff --git a/src/api/dart_ffi.rs b/src/api/dart_ffi.rs index db23f85..f482d6b 100644 --- a/src/api/dart_ffi.rs +++ b/src/api/dart_ffi.rs @@ -20,6 +20,13 @@ static mut POST_COBJ: Option = None; const MAX_COINS: u8 = 2; +fn with_coin anyhow::Result>(coin: u8, f: F) -> anyhow::Result { + let c = CoinConfig::get(coin); + let db = c.db()?; + let connection = &db.connection; + f(connection) +} + #[no_mangle] pub unsafe extern "C" fn dummy_export() {} @@ -255,6 +262,15 @@ pub unsafe extern "C" fn get_backup(coin: u8, id_account: u32) -> CResult<*const to_cresult_bytes(res()) } +#[no_mangle] +pub unsafe extern "C" fn get_available_addrs(coin: u8, account: u32) -> CResult { + let res = |connection: &Connection| { + let res = crate::db::read::get_available_addrs(connection, account)?; + Ok(res) + }; + to_cresult(with_coin(coin, res)) +} + #[no_mangle] pub unsafe extern "C" fn get_address( coin: u8, @@ -507,9 +523,15 @@ pub async unsafe extern "C" fn shield_taddr( #[tokio::main] #[no_mangle] -pub async unsafe extern "C" fn scan_transparent_accounts(coin: u8, account: u32, gap_limit: u32) -> CResult<*const u8> { +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 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); @@ -877,13 +899,6 @@ pub unsafe extern "C" fn clear_tx_details(coin: u8, account: u32) -> CResult to_cresult(with_coin(coin, res)) } -fn with_coin anyhow::Result>(coin: u8, f: F) -> anyhow::Result { - let c = CoinConfig::get(coin); - let db = c.db()?; - let connection = &db.connection; - f(connection) -} - #[no_mangle] pub unsafe extern "C" fn get_account_list(coin: u8) -> CResult<*const u8> { let res = |connection: &Connection| { @@ -1142,10 +1157,7 @@ pub unsafe extern "C" fn clone_db_with_passwd( } #[no_mangle] -pub unsafe extern "C" fn get_property( - coin: u8, - name: *mut c_char, -) -> CResult<*mut c_char> { +pub unsafe extern "C" fn get_property(coin: u8, name: *mut c_char) -> CResult<*mut c_char> { from_c_str!(name); let res = |connection: &Connection| { let value = crate::db::read::get_property(connection, &name)?; diff --git a/src/db.rs b/src/db.rs index 356d204..bd595f3 100644 --- a/src/db.rs +++ b/src/db.rs @@ -1131,10 +1131,7 @@ impl DbAdapter { "UPDATE transactions SET address = NULL, memo = NULL WHERE account = ?1", [account], )?; - connection.execute( - "DELETE FROM messages WHERE account = ?1", - [account], - )?; + connection.execute("DELETE FROM messages WHERE account = ?1", [account])?; Ok(()) } diff --git a/src/db/read.rs b/src/db/read.rs index 5ba3070..2bc00ac 100644 --- a/src/db/read.rs +++ b/src/db/read.rs @@ -294,7 +294,8 @@ pub fn get_messages(network: &Network, connection: &Connection, id: u32) -> Resu let mut stmt = connection.prepare( "SELECT m.id, m.id_tx, m.timestamp, m.sender, m.recipient, m.incoming, \ subject, body, height, read FROM messages m \ - WHERE account = ?1 ORDER BY timestamp DESC")?; + WHERE account = ?1 ORDER BY timestamp DESC", + )?; let rows = stmt.query_map(params![id], |row| { let id_msg: u32 = row.get("id")?; let id_tx: Option = row.get("id_tx")?; @@ -329,7 +330,9 @@ pub fn get_messages(network: &Network, connection: &Connection, id: u32) -> Resu for r in rows { messages.push(r?); } - let messages = MessageVecT { messages: Some(messages) }; + let messages = MessageVecT { + messages: Some(messages), + }; Ok(messages) } @@ -660,15 +663,48 @@ pub fn resolve_addresses( } pub fn get_property(connection: &Connection, name: &str) -> anyhow::Result { - let url = connection.query_row("SELECT value FROM properties WHERE name = ?1", [name], |row| { - let url: String = row.get(0)?; - Ok(url) - }).optional()?; + let url = connection + .query_row( + "SELECT value FROM properties WHERE name = ?1", + [name], + |row| { + let url: String = row.get(0)?; + Ok(url) + }, + ) + .optional()?; Ok(url.unwrap_or(String::new())) } pub fn set_property(connection: &Connection, name: &str, value: &str) -> anyhow::Result<()> { - connection.execute("INSERT INTO properties(name, value) VALUES (?1, ?2) ON CONFLICT (name) \ - DO UPDATE SET value = excluded.value", params![name, value])?; + connection.execute( + "INSERT INTO properties(name, value) VALUES (?1, ?2) ON CONFLICT (name) \ + DO UPDATE SET value = excluded.value", + params![name, value], + )?; Ok(()) } + +pub fn get_available_addrs(connection: &Connection, account: u32) -> anyhow::Result { + let has_transparent = connection + .query_row( + "SELECT 1 FROM taddrs WHERE account = ?1", + [account], + |_row| Ok(()), + ) + .optional()? + .is_some(); + let has_sapling = true; + let has_orchard = connection + .query_row( + "SELECT 1 FROM orchard_addrs WHERE account = ?1", + [account], + |_row| Ok(()), + ) + .optional()? + .is_some(); + let res = if has_transparent { 1 } else { 0 } + | if has_sapling { 2 } else { 0 } + | if has_orchard { 4 } else { 0 }; + Ok(res) +} diff --git a/src/taddr.rs b/src/taddr.rs index d2675ba..a5658ec 100644 --- a/src/taddr.rs +++ b/src/taddr.rs @@ -1,14 +1,14 @@ use crate::api::payment_v2::build_tx_plan_with_utxos; use crate::api::recipient::RecipientMemo; -use crate::chain::{get_checkpoint_height, EXPIRY_HEIGHT_OFFSET, get_latest_height}; +use crate::chain::{get_checkpoint_height, get_latest_height, EXPIRY_HEIGHT_OFFSET}; use crate::coinconfig::CoinConfig; use crate::db::AccountData; use crate::key2::split_key; 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, BlockRange, + broadcast_tx, build_tx, AddressList, BlockId, BlockRange, CompactTxStreamerClient, + GetAddressUtxosArg, GetAddressUtxosReply, Hash, TransparentAddressBlockFilter, TxFilter, }; 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, NetworkUpgrade}; +use zcash_primitives::consensus::{Network, NetworkUpgrade, Parameters}; use zcash_primitives::legacy::TransparentAddress; use zcash_primitives::memo::Memo; use zcash_primitives::transaction::components::OutPoint; @@ -178,12 +178,23 @@ pub async fn scan_transparent_accounts( mut aindex: u32, gap_limit: usize, ) -> anyhow::Result> { - let start: u32 = network.activation_height(NetworkUpgrade::Sapling).unwrap().into(); + 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 }; + 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 mut gap = 0;