This commit is contained in:
Hanh 2022-12-22 06:54:25 +08:00
parent 9ae96e7d88
commit c51c98138a
10 changed files with 130 additions and 67 deletions

View File

@ -206,8 +206,12 @@ pub fn new_diversified_address(ua_type: u8) -> anyhow::Result<String> {
db.store_diversifier(c.id_account, &new_diversifier_index)?;
let orchard_keys = db.get_orchard(c.id_account)?;
if ua_type == 2 || orchard_keys.is_none() { // sapling only
return Ok(encode_payment_address(c.chain.network().hrp_sapling_payment_address(), &pa));
if ua_type == 2 || orchard_keys.is_none() {
// sapling only
return Ok(encode_payment_address(
c.chain.network().hrp_sapling_payment_address(),
&pa,
));
}
let orchard_keys = orchard_keys.unwrap();
@ -371,11 +375,7 @@ pub fn derive_keys(
/// * t, s, o: include transparent, sapling, orchard receivers?
///
/// The address depends on the UA settings and may include transparent, sapling & orchard receivers
pub fn get_unified_address(
coin: u8,
id_account: u32,
address_type: u8,
) -> anyhow::Result<String> {
pub fn get_unified_address(coin: u8, id_account: u32, address_type: u8) -> anyhow::Result<String> {
let c = CoinConfig::get(coin);
let db = c.db()?;
let tpe = UnifiedAddressType {

View File

@ -414,7 +414,8 @@ pub async unsafe extern "C" fn get_taddr_balance(coin: u8, id_account: u32) -> C
pub async unsafe extern "C" fn transfer_pools(
coin: u8,
account: u32,
from_pool: u8, to_pool: u8,
from_pool: u8,
to_pool: u8,
amount: u64,
fee_included: bool,
memo: *mut c_char,
@ -423,9 +424,18 @@ pub async unsafe extern "C" fn transfer_pools(
) -> CResult<*mut c_char> {
from_c_str!(memo);
let res = async move {
let tx_plan = crate::api::payment_v2::transfer_pools(coin, account, from_pool, to_pool,
amount, fee_included,
&memo, split_amount, confirmations).await?;
let tx_plan = crate::api::payment_v2::transfer_pools(
coin,
account,
from_pool,
to_pool,
amount,
fee_included,
&memo,
split_amount,
confirmations,
)
.await?;
let tx_plan = serde_json::to_string(&tx_plan)?;
Ok::<_, anyhow::Error>(tx_plan)
};

View File

@ -32,7 +32,9 @@ pub async fn build_tx_plan(
let mut recipient_fee = false;
for r in recipients {
if r.fee_included {
if recipient_fee { return Err(TransactionBuilderError::DuplicateRecipientFee) }
if recipient_fee {
return Err(TransactionBuilderError::DuplicateRecipientFee);
}
recipient_fee = true;
}
}
@ -154,8 +156,17 @@ pub async fn build_max_tx(
Err(TransactionBuilderError::TxTooComplex)
}
pub async fn transfer_pools(coin: u8, account: u32, from_pool: u8, to_pool: u8, amount: u64,
fee_included: bool, memo: &str, split_amount: u64, confirmations: u32) -> anyhow::Result<TransactionPlan> {
pub async fn transfer_pools(
coin: u8,
account: u32,
from_pool: u8,
to_pool: u8,
amount: u64,
fee_included: bool,
memo: &str,
split_amount: u64,
confirmations: u32,
) -> anyhow::Result<TransactionPlan> {
let address = get_unified_address(coin, account, to_pool)?; // get our own unified address
let recipient = RecipientMemo {
address,
@ -165,14 +176,37 @@ pub async fn transfer_pools(coin: u8, account: u32, from_pool: u8, to_pool: u8,
max_amount_per_note: split_amount,
};
let last_height = get_latest_height().await?;
let tx_plan = build_tx_plan(coin, account, last_height, slice::from_ref(&recipient),
!from_pool, confirmations).await?;
let tx_plan = build_tx_plan(
coin,
account,
last_height,
slice::from_ref(&recipient),
!from_pool,
confirmations,
)
.await?;
Ok(tx_plan)
}
/// Make a transaction that shields the transparent balance
pub async fn shield_taddr(coin: u8, account: u32, amount: u64, confirmations: u32) -> anyhow::Result<String> {
let tx_plan = transfer_pools(coin, account, 1, 6, amount, true, "Shield Transparent Balance", 0, confirmations).await?;
pub async fn shield_taddr(
coin: u8,
account: u32,
amount: u64,
confirmations: u32,
) -> anyhow::Result<String> {
let tx_plan = transfer_pools(
coin,
account,
1,
6,
amount,
true,
"Shield Transparent Balance",
0,
confirmations,
)
.await?;
let tx_id = sign_and_broadcast(coin, account, &tx_plan).await?;
log::info!("TXID: {}", tx_id);
Ok(tx_id)

View File

@ -651,8 +651,7 @@ impl DbAdapter {
let note = r?;
notes.push(note);
}
}
else {
} else {
let mut statement = self.connection.prepare(
"SELECT id_note, diversifier, value, rcm, rho, witness FROM received_notes r, orchard_witnesses w WHERE spent IS NULL AND account = ?2 AND rho IS NOT NULL
AND (r.excluded IS NULL OR NOT r.excluded) AND w.height = ?1
@ -707,36 +706,54 @@ impl DbAdapter {
pub fn purge_old_witnesses(&mut self, height: u32) -> anyhow::Result<()> {
log::debug!("+purge_old_witnesses");
let min_height: Option<u32> = self.connection.query_row(
"SELECT MAX(height) FROM blocks WHERE height <= ?1",
params![height],
const BLOCKS_PER_HOUR: u32 = 60*60/75;
const BLOCKS_PER_DAY: u32 = 24*BLOCKS_PER_HOUR;
const BLOCKS_PER_MONTH: u32 = 30*BLOCKS_PER_DAY;
for i in 1..=24 { // 1 checkpoint per hour
self.prune_interval(height - i*BLOCKS_PER_HOUR, height - (i-1)*BLOCKS_PER_HOUR)?;
}
for i in 2..=30 { // 1 checkpoint per day
self.prune_interval(height - i*BLOCKS_PER_DAY, height - (i-1)*BLOCKS_PER_DAY)?;
}
for i in 2..=12 { // 1 checkpoint per 30 days
self.prune_interval(height - i*BLOCKS_PER_MONTH, height - (i-1)*BLOCKS_PER_MONTH)?;
}
log::debug!("-purge_old_witnesses");
Ok(())
}
// Only keep the oldest checkpoint in [low, high)
fn prune_interval(&mut self, low: u32, high: u32) -> anyhow::Result<()> {
log::info!("prune_interval {} {}", low, high);
let keep_height: Option<u32> = self.connection.query_row(
"SELECT MIN(height) FROM blocks WHERE height >= ?1 AND height < ?2",
params![low, high],
|row| row.get(0),
)?;
// Leave at least one sapling witness
if let Some(min_height) = min_height {
log::debug!("Purging witnesses older than {}", min_height);
if let Some(keep_height) = keep_height {
log::info!("keep {}", keep_height);
let transaction = self.connection.transaction()?;
transaction.execute(
"DELETE FROM sapling_witnesses WHERE height < ?1",
params![min_height],
"DELETE FROM sapling_witnesses WHERE height >= ?1 AND height < ?2 AND height != ?3",
params![low, high, keep_height],
)?;
transaction.execute(
"DELETE FROM orchard_witnesses WHERE height < ?1",
params![min_height],
"DELETE FROM orchard_witnesses WHERE height >= ?1 AND height < ?2 AND height != ?3",
params![low, high, keep_height],
)?;
transaction.execute("DELETE FROM blocks WHERE height < ?1", params![min_height])?;
transaction.execute("DELETE FROM blocks WHERE height >= ?1 AND height < ?2 AND height != ?3",
params![low, high, keep_height])?;
transaction.execute(
"DELETE FROM sapling_tree WHERE height < ?1",
params![min_height],
"DELETE FROM sapling_tree WHERE height >= ?1 AND height < ?2 AND height != ?3",
params![low, high, keep_height],
)?;
transaction.execute(
"DELETE FROM orchard_tree WHERE height < ?1",
params![min_height],
"DELETE FROM orchard_tree WHERE height >= ?1 AND height < ?2 AND height != ?3",
params![low, high, keep_height],
)?;
transaction.commit()?;
}
log::debug!("-purge_old_witnesses");
Ok(())
}

View File

@ -1,7 +1,11 @@
use crate::coinconfig::CoinConfig;
use anyhow::anyhow;
use bip39::{Language, Mnemonic, Seed};
use zcash_client_backend::encoding::{decode_extended_full_viewing_key, decode_extended_spending_key, decode_payment_address, decode_transparent_address, encode_extended_full_viewing_key, encode_extended_spending_key, encode_payment_address};
use zcash_client_backend::encoding::{
decode_extended_full_viewing_key, decode_extended_spending_key, decode_payment_address,
decode_transparent_address, encode_extended_full_viewing_key, encode_extended_spending_key,
encode_payment_address,
};
use zcash_client_backend::keys::UnifiedFullViewingKey;
use zcash_primitives::consensus::{Network, Parameters};
use zcash_primitives::zip32::{ChildIndex, ExtendedFullViewingKey, ExtendedSpendingKey};
@ -79,17 +83,15 @@ pub fn is_valid_address(coin: u8, address: &str) -> bool {
let network = c.chain.network();
if decode_payment_address(network.hrp_sapling_payment_address(), address).is_ok() {
true
}
else if let Ok(Some(_)) = decode_transparent_address(
} else if let Ok(Some(_)) = decode_transparent_address(
&network.b58_pubkey_address_prefix(),
&network.b58_script_address_prefix(),
address) {
address,
) {
true
}
else if zcash_client_backend::address::RecipientAddress::decode(network, address).is_some() {
} else if zcash_client_backend::address::RecipientAddress::decode(network, address).is_some() {
true
}
else {
} else {
false
}
}

View File

@ -15,8 +15,8 @@ use thiserror::Error;
use warp_api_ffi::api::payment_uri::PaymentURI;
use warp_api_ffi::api::recipient::{Recipient, RecipientMemo, RecipientShort};
use warp_api_ffi::{
build_tx, get_secret_keys, AccountData, AccountRec, CoinConfig, KeyPack,
RaptorQDrops, TransactionPlan, TxRec,
build_tx, get_secret_keys, AccountData, AccountRec, CoinConfig, KeyPack, RaptorQDrops,
TransactionPlan, TxRec,
};
lazy_static! {
@ -187,11 +187,8 @@ pub fn get_address() -> Result<String, Error> {
#[get("/unified_address?<t>&<s>&<o>")]
pub fn get_unified_address(t: u8, s: u8, o: u8) -> Result<String, Error> {
let c = CoinConfig::get_active();
let address = warp_api_ffi::api::account::get_unified_address(
c.coin,
c.id_account,
t & s << 1 & o << 2,
)?;
let address =
warp_api_ffi::api::account::get_unified_address(c.coin, c.id_account, t & s << 1 & o << 2)?;
Ok(address)
}

View File

@ -35,10 +35,7 @@ pub fn group_orders(orders: &[Order], fee: u64) -> Result<(Vec<OrderInfo>, Order
}
}
let amount = order.amount(fee)?;
order_info.push(OrderInfo {
group_type,
amount,
});
order_info.push(OrderInfo { group_type, amount });
}
let mut t0 = 0u64;
@ -190,7 +187,7 @@ pub fn fill(
order_infos: &[OrderInfo],
amounts: &OrderGroupAmounts,
allocation: &FundAllocation,
fee: u64
fee: u64,
) -> Result<Vec<Fill>> {
assert_eq!(orders.len(), order_infos.len());
let mut fills = vec![];

View File

@ -6,10 +6,7 @@ use zcash_primitives::memo::MemoBytes;
#[derive(Serialize, Deserialize)]
#[serde(remote = "MemoBytes")]
pub struct MemoBytesProxy(
#[serde(getter = "get_memo_bytes")]
pub String,
);
pub struct MemoBytesProxy(#[serde(getter = "get_memo_bytes")] pub String);
fn get_memo_bytes(memo: &MemoBytes) -> String {
hex::encode(memo.as_slice())

View File

@ -201,7 +201,14 @@ impl Destination {
}
impl Order {
pub fn new(network: &Network, id: u32, address: &str, amount: u64, take_fee: bool, memo: MemoBytes) -> Self {
pub fn new(
network: &Network,
id: u32,
address: &str,
amount: u64,
take_fee: bool,
memo: MemoBytes,
) -> Self {
let destinations = decode(network, address).unwrap();
Order {
id,
@ -214,10 +221,11 @@ impl Order {
pub fn amount(&self, fee: u64) -> Result<u64, TransactionBuilderError> {
if self.take_fee {
if self.raw_amount < fee { return Err(TransactionBuilderError::RecipientCannotPayFee) }
if self.raw_amount < fee {
return Err(TransactionBuilderError::RecipientCannotPayFee);
}
Ok(self.raw_amount - fee)
}
else {
} else {
Ok(self.raw_amount)
}
}

View File

@ -207,9 +207,8 @@ async fn sync_async_inner<'a>(
}
}
let mut db = db_builder.build()?;
let db = db_builder.build()?;
db.store_block_timestamp(last_height, &last_hash, last_timestamp)?;
db.purge_old_witnesses(last_height - 500)?;
height = last_height;
let cb = progress_callback.lock().await;
cb(progress.clone());
@ -220,6 +219,8 @@ async fn sync_async_inner<'a>(
if get_tx {
get_transaction_details(coin).await?;
}
let mut db = db_builder.build()?;
db.purge_old_witnesses(height)?;
Ok(())
}