diversifier address by time
This commit is contained in:
parent
cda240c8e9
commit
39266e766e
|
@ -190,7 +190,7 @@ int8_t is_valid_key(uint8_t coin, char *key);
|
|||
|
||||
bool valid_address(uint8_t coin, char *address);
|
||||
|
||||
struct CResult_____c_char new_diversified_address(uint8_t ua_type);
|
||||
struct CResult_____c_char get_diversified_address(uint8_t ua_type, uint32_t time);
|
||||
|
||||
struct CResult_u32 get_latest_height(void);
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ use zcash_address::{ToAddress, ZcashAddress};
|
|||
use zcash_client_backend::encoding::{decode_extended_full_viewing_key, encode_payment_address};
|
||||
use zcash_client_backend::keys::UnifiedFullViewingKey;
|
||||
use zcash_primitives::consensus::Parameters;
|
||||
use zcash_primitives::zip32::DiversifierIndex;
|
||||
|
||||
/// Create a new account
|
||||
/// # Arguments
|
||||
|
@ -188,7 +189,7 @@ pub fn import_transparent_secret_key(coin: u8, id_account: u32, sk: &str) -> any
|
|||
}
|
||||
|
||||
/// Generate a new diversified address
|
||||
pub fn new_diversified_address(ua_type: u8) -> anyhow::Result<String> {
|
||||
pub fn get_diversified_address(ua_type: u8, time: u32) -> anyhow::Result<String> {
|
||||
let ua_type = ua_type & 6; // don't include transparent component
|
||||
if ua_type == 0 {
|
||||
anyhow::bail!("Must include a shielded receiver");
|
||||
|
@ -201,12 +202,12 @@ pub fn new_diversified_address(ua_type: u8) -> anyhow::Result<String> {
|
|||
&fvk,
|
||||
)
|
||||
.map_err(|_| anyhow!("Bech32 Decode Error"))?;
|
||||
let mut diversifier_index = db.get_diversifier(c.id_account)?;
|
||||
diversifier_index.increment().unwrap();
|
||||
let (new_diversifier_index, pa) = fvk
|
||||
let mut di = [0u8; 11];
|
||||
di[4..8].copy_from_slice(&time.to_le_bytes());
|
||||
let diversifier_index = DiversifierIndex(di);
|
||||
let (_, pa) = fvk
|
||||
.find_address(diversifier_index)
|
||||
.ok_or_else(|| anyhow::anyhow!("Cannot generate new address"))?;
|
||||
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() {
|
||||
|
|
|
@ -348,8 +348,8 @@ pub unsafe extern "C" fn valid_address(coin: u8, address: *mut c_char) -> bool {
|
|||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn new_diversified_address(ua_type: u8) -> CResult<*mut c_char> {
|
||||
let res = || crate::api::account::new_diversified_address(ua_type);
|
||||
pub unsafe extern "C" fn get_diversified_address(ua_type: u8, time: u32) -> CResult<*mut c_char> {
|
||||
let res = || crate::api::account::get_diversified_address(ua_type, time);
|
||||
to_cresult_str(res())
|
||||
}
|
||||
|
||||
|
|
42
src/db.rs
42
src/db.rs
|
@ -5,7 +5,7 @@ use crate::orchard::{derive_orchard_keys, OrchardKeyBytes, OrchardViewKey};
|
|||
use crate::prices::Quote;
|
||||
use crate::sapling::SaplingViewKey;
|
||||
use crate::sync::tree::{CTree, TreeCheckpoint};
|
||||
use crate::taddr::derive_tkeys;
|
||||
use crate::taddr::{derive_tkeys, TransparentTxInfo};
|
||||
use crate::transaction::{GetTransactionDetailRequest, TransactionDetails};
|
||||
use crate::unified::UnifiedAddressType;
|
||||
use crate::{sync, BlockId, CoinConfig, CompactTxStreamerClient, Hash};
|
||||
|
@ -486,6 +486,14 @@ impl DbAdapter {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn store_transparent_tx(
|
||||
_account: u32,
|
||||
_tx: &TransparentTxInfo,
|
||||
_db_tx: &Transaction,
|
||||
) -> anyhow::Result<()> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn add_value(id_tx: u32, value: i64, db_tx: &Transaction) -> anyhow::Result<()> {
|
||||
db_tx.execute(
|
||||
"UPDATE transactions SET value = value + ?2 WHERE id_tx = ?1",
|
||||
|
@ -825,38 +833,6 @@ impl DbAdapter {
|
|||
Ok(contacts)
|
||||
}
|
||||
|
||||
pub fn get_diversifier(&self, account: u32) -> anyhow::Result<DiversifierIndex> {
|
||||
let diversifier_index = self
|
||||
.connection
|
||||
.query_row(
|
||||
"SELECT diversifier_index FROM diversifiers WHERE account = ?1",
|
||||
params![account],
|
||||
|row| {
|
||||
let d: Vec<u8> = row.get(0)?;
|
||||
let mut div = [0u8; 11];
|
||||
div.copy_from_slice(&d);
|
||||
Ok(div)
|
||||
},
|
||||
)
|
||||
.optional()?
|
||||
.unwrap_or([0u8; 11]);
|
||||
Ok(DiversifierIndex(diversifier_index))
|
||||
}
|
||||
|
||||
pub fn store_diversifier(
|
||||
&self,
|
||||
account: u32,
|
||||
diversifier_index: &DiversifierIndex,
|
||||
) -> anyhow::Result<()> {
|
||||
let diversifier_bytes = diversifier_index.0.to_vec();
|
||||
self.connection.execute(
|
||||
"INSERT INTO diversifiers(account, diversifier_index) VALUES (?1, ?2) ON CONFLICT \
|
||||
(account) DO UPDATE SET diversifier_index = excluded.diversifier_index",
|
||||
params![account, diversifier_bytes],
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_account_info(&self, account: u32) -> anyhow::Result<AccountData> {
|
||||
assert_ne!(account, 0);
|
||||
log::info!("get_account_info {} {}", self.db_path, account);
|
||||
|
|
|
@ -356,7 +356,7 @@ pub async fn build_from_plan(tx_plan: Json<TransactionPlan>) -> Result<String, E
|
|||
|
||||
#[get("/new_diversified_address")]
|
||||
pub fn new_diversified_address() -> Result<String, Error> {
|
||||
let address = warp_api_ffi::api::account::new_diversified_address()?;
|
||||
let address = warp_api_ffi::api::account::get_diversified_address()?;
|
||||
Ok(address)
|
||||
}
|
||||
|
||||
|
|
101
src/taddr.rs
101
src/taddr.rs
|
@ -6,8 +6,8 @@ use crate::db::AccountData;
|
|||
use crate::note_selection::{SecretKeys, Source, UTXO};
|
||||
use crate::unified::orchard_as_unified;
|
||||
use crate::{
|
||||
broadcast_tx, build_tx, AddressList, CompactTxStreamerClient, GetAddressUtxosArg,
|
||||
GetAddressUtxosReply, TransparentAddressBlockFilter,
|
||||
broadcast_tx, build_tx, AddressList, BlockId, CompactTxStreamerClient, GetAddressUtxosArg,
|
||||
GetAddressUtxosReply, Hash, TransparentAddressBlockFilter, TxFilter,
|
||||
};
|
||||
use anyhow::anyhow;
|
||||
use base58check::FromBase58Check;
|
||||
|
@ -18,13 +18,17 @@ use rand::rngs::OsRng;
|
|||
use ripemd::{Digest, Ripemd160};
|
||||
use secp256k1::{All, PublicKey, Secp256k1, SecretKey};
|
||||
use sha2::Sha256;
|
||||
use std::collections::HashMap;
|
||||
use tiny_hderive::bip32::ExtendedPrivKey;
|
||||
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::legacy::TransparentAddress;
|
||||
use zcash_primitives::memo::Memo;
|
||||
use zcash_primitives::transaction::components::OutPoint;
|
||||
use zcash_primitives::transaction::Transaction;
|
||||
|
||||
pub async fn get_taddr_balance(
|
||||
client: &mut CompactTxStreamerClient<Channel>,
|
||||
|
@ -40,6 +44,99 @@ pub async fn get_taddr_balance(
|
|||
Ok(rep.value_zat as u64)
|
||||
}
|
||||
|
||||
pub struct TransparentTxInfo {
|
||||
pub txid: Hash,
|
||||
pub height: u32,
|
||||
pub timestamp: u32,
|
||||
pub inputs: Vec<OutPoint>,
|
||||
pub in_value: u64,
|
||||
pub out_value: u64,
|
||||
}
|
||||
|
||||
/* With the current LWD API, this function performs poorly because
|
||||
the server does not return tx timestamp, height and value
|
||||
*/
|
||||
#[allow(unused)]
|
||||
pub async fn get_ttx_history(
|
||||
network: &Network,
|
||||
client: &mut CompactTxStreamerClient<Channel>,
|
||||
address: &str,
|
||||
) -> anyhow::Result<Vec<TransparentTxInfo>> {
|
||||
let mut rep = client
|
||||
.get_taddress_txids(Request::new(TransparentAddressBlockFilter {
|
||||
address: address.to_string(),
|
||||
range: None,
|
||||
}))
|
||||
.await?
|
||||
.into_inner();
|
||||
let mut heights: HashMap<u32, u32> = HashMap::new();
|
||||
let mut txs = vec![];
|
||||
while let Some(raw_tx) = rep.message().await? {
|
||||
let height = raw_tx.height as u32;
|
||||
heights.insert(height, 0);
|
||||
let consensus_branch_id = get_branch(network, height);
|
||||
let tx = Transaction::read(&*raw_tx.data, consensus_branch_id)?;
|
||||
let txid = tx.txid();
|
||||
let tx_data = tx.into_data();
|
||||
let mut inputs = vec![];
|
||||
if let Some(transparent_bundle) = tx_data.transparent_bundle() {
|
||||
for vin in transparent_bundle.vin.iter() {
|
||||
inputs.push(vin.prevout.clone());
|
||||
}
|
||||
let out_value = transparent_bundle
|
||||
.vout
|
||||
.iter()
|
||||
.map(|vout| i64::from(vout.value))
|
||||
.sum::<i64>() as u64;
|
||||
txs.push(TransparentTxInfo {
|
||||
txid: txid.as_ref().clone(),
|
||||
height,
|
||||
timestamp: 0,
|
||||
inputs,
|
||||
in_value: 0,
|
||||
out_value,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
for (h, timestamp) in heights.iter_mut() {
|
||||
let block = client
|
||||
.get_block(Request::new(BlockId {
|
||||
height: *h as u64,
|
||||
hash: vec![],
|
||||
}))
|
||||
.await?
|
||||
.into_inner();
|
||||
*timestamp = block.time;
|
||||
}
|
||||
|
||||
for tx in txs.iter_mut() {
|
||||
let mut in_value = 0;
|
||||
for input in tx.inputs.iter() {
|
||||
let raw_tx = client
|
||||
.get_transaction(Request::new(TxFilter {
|
||||
block: None,
|
||||
index: 0,
|
||||
hash: input.hash().to_vec(),
|
||||
}))
|
||||
.await?
|
||||
.into_inner();
|
||||
let consensus_branch_id = get_branch(network, raw_tx.height as u32);
|
||||
let tx = Transaction::read(&*raw_tx.data, consensus_branch_id)?;
|
||||
let tx_data = tx.into_data();
|
||||
let transparent_bundle = tx_data
|
||||
.transparent_bundle()
|
||||
.ok_or(anyhow!("No transparent bundle"))?;
|
||||
let value = i64::from(transparent_bundle.vout[input.n() as usize].value);
|
||||
in_value += value;
|
||||
}
|
||||
tx.timestamp = heights[&tx.height];
|
||||
tx.in_value = in_value as u64;
|
||||
tx.inputs.clear();
|
||||
}
|
||||
Ok(txs)
|
||||
}
|
||||
|
||||
pub async fn get_taddr_tx_count(
|
||||
client: &mut CompactTxStreamerClient<Channel>,
|
||||
address: &str,
|
||||
|
|
Loading…
Reference in New Issue