API: get_available_addrs

This commit is contained in:
Hanh 2023-03-14 22:07:37 +10:00
parent dbaa1c02c9
commit 8a2f2b7fea
6 changed files with 116 additions and 43 deletions

View File

@ -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_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); 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); void import_transparent_key(uint8_t coin, uint32_t id_account, char *path);

View File

@ -3,9 +3,7 @@
// Account creation // Account creation
use crate::coinconfig::CoinConfig; use crate::coinconfig::CoinConfig;
use crate::db::data_generated::fb::{ use crate::db::data_generated::fb::{AddressBalanceT, AddressBalanceVecT, BackupT, KeyPackT};
BackupT, KeyPackT, AddressBalanceVecT, AddressBalanceT,
};
use crate::db::AccountData; use crate::db::AccountData;
use crate::key2::decode_key; use crate::key2::decode_key;
use crate::orchard::OrchardKeyBytes; use crate::orchard::OrchardKeyBytes;
@ -265,22 +263,39 @@ pub async fn get_taddr_balance(coin: u8, id_account: u32) -> anyhow::Result<u64>
/// is exceeded and no balance was found /// is exceeded and no balance was found
/// # Arguments /// # Arguments
/// * `gap_limit`: number of accounts with 0 balance before the scan stops /// * `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<AddressBalanceVecT> { pub async fn scan_transparent_accounts(
coin: u8,
account: u32,
gap_limit: usize,
) -> anyhow::Result<AddressBalanceVecT> {
let c = CoinConfig::get(coin); let c = CoinConfig::get(coin);
let db = c.db()?; let db = c.db()?;
let account_data = db.get_account_info(account)?; let account_data = db.get_account_info(account)?;
let AccountData { let AccountData { seed, aindex, .. } = account_data;
seed, aindex, ..
} = account_data;
let mut addresses = vec![]; let mut addresses = vec![];
if let Some(seed) = seed { if let Some(seed) = seed {
let mut client = c.connect_lwd().await?; 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, let addresses: Vec<_> = addresses
address: Some(a.address.clone()), balance: a.balance }).collect(); .iter()
.map(|a| AddressBalanceT {
index: a.index,
address: Some(a.address.clone()),
balance: a.balance,
})
.collect();
let addresses = AddressBalanceVecT { let addresses = AddressBalanceVecT {
values: Some(addresses) values: Some(addresses),
}; };
Ok(addresses) Ok(addresses)
} }

View File

@ -20,6 +20,13 @@ static mut POST_COBJ: Option<ffi::DartPostCObjectFnType> = None;
const MAX_COINS: u8 = 2; const MAX_COINS: u8 = 2;
fn with_coin<T, F: Fn(&Connection) -> anyhow::Result<T>>(coin: u8, f: F) -> anyhow::Result<T> {
let c = CoinConfig::get(coin);
let db = c.db()?;
let connection = &db.connection;
f(connection)
}
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn dummy_export() {} 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()) to_cresult_bytes(res())
} }
#[no_mangle]
pub unsafe extern "C" fn get_available_addrs(coin: u8, account: u32) -> CResult<u8> {
let res = |connection: &Connection| {
let res = crate::db::read::get_available_addrs(connection, account)?;
Ok(res)
};
to_cresult(with_coin(coin, res))
}
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn get_address( pub unsafe extern "C" fn get_address(
coin: u8, coin: u8,
@ -507,9 +523,15 @@ pub async unsafe extern "C" fn shield_taddr(
#[tokio::main] #[tokio::main]
#[no_mangle] #[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 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 mut builder = FlatBufferBuilder::new();
let root = addresses.pack(&mut builder); let root = addresses.pack(&mut builder);
builder.finish(root, None); builder.finish(root, None);
@ -877,13 +899,6 @@ pub unsafe extern "C" fn clear_tx_details(coin: u8, account: u32) -> CResult<u8>
to_cresult(with_coin(coin, res)) to_cresult(with_coin(coin, res))
} }
fn with_coin<T, F: Fn(&Connection) -> anyhow::Result<T>>(coin: u8, f: F) -> anyhow::Result<T> {
let c = CoinConfig::get(coin);
let db = c.db()?;
let connection = &db.connection;
f(connection)
}
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn get_account_list(coin: u8) -> CResult<*const u8> { pub unsafe extern "C" fn get_account_list(coin: u8) -> CResult<*const u8> {
let res = |connection: &Connection| { let res = |connection: &Connection| {
@ -1142,10 +1157,7 @@ pub unsafe extern "C" fn clone_db_with_passwd(
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn get_property( pub unsafe extern "C" fn get_property(coin: u8, name: *mut c_char) -> CResult<*mut c_char> {
coin: u8,
name: *mut c_char,
) -> CResult<*mut c_char> {
from_c_str!(name); from_c_str!(name);
let res = |connection: &Connection| { let res = |connection: &Connection| {
let value = crate::db::read::get_property(connection, &name)?; let value = crate::db::read::get_property(connection, &name)?;

View File

@ -1131,10 +1131,7 @@ impl DbAdapter {
"UPDATE transactions SET address = NULL, memo = NULL WHERE account = ?1", "UPDATE transactions SET address = NULL, memo = NULL WHERE account = ?1",
[account], [account],
)?; )?;
connection.execute( connection.execute("DELETE FROM messages WHERE account = ?1", [account])?;
"DELETE FROM messages WHERE account = ?1",
[account],
)?;
Ok(()) Ok(())
} }

View File

@ -294,7 +294,8 @@ pub fn get_messages(network: &Network, connection: &Connection, id: u32) -> Resu
let mut stmt = connection.prepare( let mut stmt = connection.prepare(
"SELECT m.id, m.id_tx, m.timestamp, m.sender, m.recipient, m.incoming, \ "SELECT m.id, m.id_tx, m.timestamp, m.sender, m.recipient, m.incoming, \
subject, body, height, read FROM messages m \ 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 rows = stmt.query_map(params![id], |row| {
let id_msg: u32 = row.get("id")?; let id_msg: u32 = row.get("id")?;
let id_tx: Option<u32> = row.get("id_tx")?; let id_tx: Option<u32> = row.get("id_tx")?;
@ -329,7 +330,9 @@ pub fn get_messages(network: &Network, connection: &Connection, id: u32) -> Resu
for r in rows { for r in rows {
messages.push(r?); messages.push(r?);
} }
let messages = MessageVecT { messages: Some(messages) }; let messages = MessageVecT {
messages: Some(messages),
};
Ok(messages) Ok(messages)
} }
@ -660,15 +663,48 @@ pub fn resolve_addresses(
} }
pub fn get_property(connection: &Connection, name: &str) -> anyhow::Result<String> { pub fn get_property(connection: &Connection, name: &str) -> anyhow::Result<String> {
let url = connection.query_row("SELECT value FROM properties WHERE name = ?1", [name], |row| { let url = connection
.query_row(
"SELECT value FROM properties WHERE name = ?1",
[name],
|row| {
let url: String = row.get(0)?; let url: String = row.get(0)?;
Ok(url) Ok(url)
}).optional()?; },
)
.optional()?;
Ok(url.unwrap_or(String::new())) Ok(url.unwrap_or(String::new()))
} }
pub fn set_property(connection: &Connection, name: &str, value: &str) -> anyhow::Result<()> { 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) \ connection.execute(
DO UPDATE SET value = excluded.value", params![name, value])?; "INSERT INTO properties(name, value) VALUES (?1, ?2) ON CONFLICT (name) \
DO UPDATE SET value = excluded.value",
params![name, value],
)?;
Ok(()) Ok(())
} }
pub fn get_available_addrs(connection: &Connection, account: u32) -> anyhow::Result<u8> {
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)
}

View File

@ -1,14 +1,14 @@
use crate::api::payment_v2::build_tx_plan_with_utxos; use crate::api::payment_v2::build_tx_plan_with_utxos;
use crate::api::recipient::RecipientMemo; 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::coinconfig::CoinConfig;
use crate::db::AccountData; use crate::db::AccountData;
use crate::key2::split_key; use crate::key2::split_key;
use crate::note_selection::{SecretKeys, Source, UTXO}; use crate::note_selection::{SecretKeys, Source, UTXO};
use crate::unified::orchard_as_unified; use crate::unified::orchard_as_unified;
use crate::{ use crate::{
broadcast_tx, build_tx, AddressList, BlockId, CompactTxStreamerClient, GetAddressUtxosArg, broadcast_tx, build_tx, AddressList, BlockId, BlockRange, CompactTxStreamerClient,
GetAddressUtxosReply, Hash, TransparentAddressBlockFilter, TxFilter, BlockRange, GetAddressUtxosArg, GetAddressUtxosReply, Hash, TransparentAddressBlockFilter, TxFilter,
}; };
use anyhow::anyhow; use anyhow::anyhow;
use base58check::FromBase58Check; use base58check::FromBase58Check;
@ -25,7 +25,7 @@ use tonic::transport::Channel;
use tonic::Request; use tonic::Request;
use zcash_client_backend::encoding::encode_transparent_address; use zcash_client_backend::encoding::encode_transparent_address;
use zcash_params::coin::get_branch; 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::legacy::TransparentAddress;
use zcash_primitives::memo::Memo; use zcash_primitives::memo::Memo;
use zcash_primitives::transaction::components::OutPoint; use zcash_primitives::transaction::components::OutPoint;
@ -178,12 +178,23 @@ pub async fn scan_transparent_accounts(
mut aindex: u32, mut aindex: u32,
gap_limit: usize, gap_limit: usize,
) -> anyhow::Result<Vec<TBalance>> { ) -> anyhow::Result<Vec<TBalance>> {
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 end = get_latest_height(client).await?;
let range = BlockRange { let range = BlockRange {
start: Some(BlockId { height: start as u64, hash: vec![] }), start: Some(BlockId {
end: Some(BlockId { height: end as u64, hash: vec![] }), spam_filter_threshold: 0 }; 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 addresses = vec![];
let mut gap = 0; let mut gap = 0;