Clean up some dead code

This commit is contained in:
Hanh 2022-11-06 10:55:53 +08:00
parent b61772b639
commit f23cd2376f
4 changed files with 114 additions and 444 deletions

View File

@ -29,51 +29,53 @@ async fn prepare_multi_payment(
use_transparent: bool,
anchor_offset: u32,
) -> anyhow::Result<(Tx, Vec<u32>)> {
let c = CoinConfig::get_active();
let mut tx_builder = TxBuilder::new(c.coin_type, last_height);
let AccountData { fvk, .. } = c.db()?.get_account_info(c.id_account)?;
let fvk = decode_extended_full_viewing_key(
c.chain.network().hrp_sapling_extended_full_viewing_key(),
&fvk,
)
.unwrap();
let utxos = if use_transparent {
let mut client = c.connect_lwd().await?;
let t_address = c.db()?.get_taddr(c.id_account)?;
if let Some(t_address) = t_address {
get_utxos(&mut client, &t_address, c.id_account).await?
} else {
vec![]
}
} else {
vec![]
};
let target_amount: u64 = recipients.iter().map(|r| r.amount).sum();
let anchor_height = last_height.saturating_sub(anchor_offset);
let spendable_notes = c
.db()?
.get_spendable_notes(c.id_account, anchor_height, &fvk)?;
let note_ids = tx_builder.select_inputs(&fvk, &spendable_notes, &utxos, target_amount)?;
tx_builder.select_outputs(&fvk, recipients)?;
Ok((tx_builder.tx, note_ids))
// let c = CoinConfig::get_active();
// let mut tx_builder = TxBuilder::new(c.coin_type, last_height);
//
// let AccountData { fvk, .. } = c.db()?.get_account_info(c.id_account)?;
// let fvk = decode_extended_full_viewing_key(
// c.chain.network().hrp_sapling_extended_full_viewing_key(),
// &fvk,
// )
// .unwrap();
// let utxos = if use_transparent {
// let mut client = c.connect_lwd().await?;
// let t_address = c.db()?.get_taddr(c.id_account)?;
// if let Some(t_address) = t_address {
// get_utxos(&mut client, &t_address, c.id_account).await?
// } else {
// vec![]
// }
// } else {
// vec![]
// };
//
// let target_amount: u64 = recipients.iter().map(|r| r.amount).sum();
// let anchor_height = last_height.saturating_sub(anchor_offset);
// let spendable_notes = c
// .db()?
// .get_spendable_notes(c.id_account, anchor_height, &fvk)?;
// let note_ids = tx_builder.select_inputs(&fvk, &spendable_notes, &utxos, target_amount)?;
// tx_builder.select_outputs(&fvk, recipients)?;
// Ok((tx_builder.tx, note_ids))
todo!()
}
fn sign(tx: &Tx, progress_callback: PaymentProgressCallback) -> anyhow::Result<Vec<u8>> {
let c = CoinConfig::get_active();
let prover = get_prover();
let db = c.db()?;
let AccountData { sk: zsk, .. } = db.get_account_info(c.id_account)?;
let zsk = zsk.ok_or(anyhow!("Cannot sign without secret key"))?;
let tsk = db
.get_tsk(c.id_account)?
.map(|tsk| SecretKey::from_str(&tsk).unwrap());
let extsk =
decode_extended_spending_key(c.chain.network().hrp_sapling_extended_spending_key(), &zsk)
.unwrap();
let raw_tx = tx.sign(tsk, &extsk, prover, progress_callback)?;
Ok(raw_tx)
// let c = CoinConfig::get_active();
// let prover = get_prover();
// let db = c.db()?;
// let AccountData { sk: zsk, .. } = db.get_account_info(c.id_account)?;
// let zsk = zsk.ok_or(anyhow!("Cannot sign without secret key"))?;
// let tsk = db
// .get_tsk(c.id_account)?
// .map(|tsk| SecretKey::from_str(&tsk).unwrap());
// let extsk =
// decode_extended_spending_key(c.chain.network().hrp_sapling_extended_spending_key(), &zsk)
// .unwrap();
// let raw_tx = tx.sign(tsk, &extsk, prover, progress_callback)?;
// Ok(raw_tx)
todo!()
}
/// Build a multi payment for offline signing

273
src/db.rs
View File

@ -157,8 +157,7 @@ impl DbAdapter {
.prepare("SELECT id_account FROM accounts WHERE ivk = ?1")?;
let exists = statement.exists(params![ivk])?;
self.connection.execute(
"INSERT INTO accounts(name, seed, aindex, sk, ivk, address) VALUES (?1, ?2, ?3, ?4, ?5, ?6)
ON CONFLICT DO NOTHING",
"INSERT INTO accounts(name, seed, aindex, sk, ivk, address) VALUES (?1, ?2, ?3, ?4, ?5, ?6)",
params![name, seed, index, sk, ivk, address],
)?;
let id_account: u32 = self
@ -246,24 +245,6 @@ impl DbAdapter {
Ok(fvks)
}
pub fn get_seeds(&self) -> anyhow::Result<Vec<AccountSeed>> {
let mut statement = self
.connection
.prepare("SELECT id_account, seed FROM accounts WHERE seed IS NOT NULL")?;
let rows = statement.query_map([], |row| {
let id_account: u32 = row.get(0)?;
let seed: String = row.get(1)?;
Ok(AccountSeed {
id_account,
seed})
})?;
let mut accounts = vec![];
for row in rows {
accounts.push(row?);
}
Ok(accounts)
}
pub fn trim_to_height(&mut self, height: u32) -> anyhow::Result<u32> {
// snap height to an existing checkpoint
let height = self.connection.query_row(
@ -307,22 +288,6 @@ impl DbAdapter {
Ok(height)
}
pub fn get_txhash(&self, id_tx: u32) -> anyhow::Result<(u32, u32, u32, Vec<u8>, String)> {
let (account, height, timestamp, tx_hash, ivk) = self.connection.query_row(
"SELECT account, height, timestamp, txid, ivk FROM transactions t, accounts a WHERE id_tx = ?1 AND t.account = a.id_account",
params![id_tx],
|row| {
let account: u32 = row.get(0)?;
let height: u32 = row.get(1)?;
let timestamp: u32 = row.get(2)?;
let tx_hash: Vec<u8> = row.get(3)?;
let ivk: String = row.get(4)?;
Ok((account, height, timestamp, tx_hash, ivk))
},
).map_err(wrap_query_no_rows("get_txhash"))?;
Ok((account, height, timestamp, tx_hash, ivk))
}
pub fn store_block(
connection: &Connection,
height: u32,
@ -341,34 +306,7 @@ impl DbAdapter {
});
connection.execute(
"INSERT INTO blocks(height, hash, timestamp, sapling_tree, orchard_tree)
VALUES (?1, ?2, ?3, ?4, ?5)
ON CONFLICT DO NOTHING",
params![height, hash, timestamp, &sapling_bb, orchard_bb],
)?;
log::debug!("-block");
Ok(())
}
pub fn store_block2(
height: u32,
hash: &[u8],
timestamp: u32,
sapling_tree: &sync::CTree,
orchard_tree: Option<&sync::CTree>,
connection: &Connection,
) -> anyhow::Result<()> {
log::debug!("+block");
let mut sapling_bb: Vec<u8> = vec![];
sapling_tree.write(&mut sapling_bb)?;
let orchard_bb = orchard_tree.map(|tree| {
let mut bb: Vec<u8> = vec![];
tree.write(&mut bb).unwrap();
bb
});
connection.execute(
"INSERT INTO blocks(height, hash, timestamp, sapling_tree, orchard_tree)
VALUES (?1, ?2, ?3, ?4, ?5)
ON CONFLICT DO NOTHING",
VALUES (?1, ?2, ?3, ?4, ?5)",
params![height, hash, timestamp, &sapling_bb, orchard_bb],
)?;
log::debug!("-block");
@ -386,8 +324,7 @@ impl DbAdapter {
log::debug!("+transaction");
db_tx.execute(
"INSERT INTO transactions(account, txid, height, timestamp, tx_index, value)
VALUES (?1, ?2, ?3, ?4, ?5, 0)
ON CONFLICT DO NOTHING",
VALUES (?1, ?2, ?3, ?4, ?5, 0)",
params![account, txid, height, timestamp, tx_index],
)?;
let id_tx: u32 = db_tx
@ -423,25 +360,6 @@ impl DbAdapter {
Ok(id_note)
}
// TODO: Depends on the type of witness
pub fn store_witnesses(
connection: &Connection,
witness: &Witness,
height: u32,
id_note: u32,
) -> anyhow::Result<()> {
log::debug!("+witnesses");
let mut bb: Vec<u8> = vec![];
witness.write(&mut bb)?;
connection.execute(
"INSERT INTO sapling_witnesses(note, height, witness) VALUES (?1, ?2, ?3)
ON CONFLICT DO NOTHING",
params![id_note, height, bb],
)?;
log::debug!("-witnesses");
Ok(())
}
pub fn store_witness(
witness: &sync::Witness,
height: u32,
@ -453,8 +371,7 @@ impl DbAdapter {
let mut bb: Vec<u8> = vec![];
witness.write(&mut bb)?;
connection.execute(
&format!("INSERT INTO {}_witnesses(note, height, witness) VALUES (?1, ?2, ?3)
ON CONFLICT DO NOTHING", shielded_pool),
&format!("INSERT INTO {}_witnesses(note, height, witness) VALUES (?1, ?2, ?3)", shielded_pool),
params![id_note, height, bb],
)?;
log::debug!("-store_witness");
@ -473,8 +390,8 @@ impl DbAdapter {
Ok(())
}
pub fn update_transaction_with_memo(&self, id_tx: u32, details: &TransactionDetails) -> anyhow::Result<()> {
self.connection.execute("UPDATE transactions SET address = ?1, memo = ?2 WHERE id_tx = ?3", params![details.address, details.memo, id_tx])?;
pub fn update_transaction_with_memo(&self, details: &TransactionDetails) -> anyhow::Result<()> {
self.connection.execute("UPDATE transactions SET address = ?1, memo = ?2 WHERE id_tx = ?3", params![details.address, details.memo, details.id_tx])?;
Ok(())
}
@ -486,21 +403,7 @@ impl DbAdapter {
Ok(())
}
pub fn get_received_note_value(nf: &Nf, db_tx: &Transaction) -> anyhow::Result<(u32, i64)> {
let (account, value) = db_tx
.query_row(
"SELECT account, value FROM received_notes WHERE nf = ?1",
params![nf.0.to_vec()],
|row| {
let account: u32 = row.get(0)?;
let value: i64 = row.get(1)?;
Ok((account, value))
},
)
.map_err(wrap_query_no_rows("get_received_note_value"))?;
Ok((account, value))
}
#[allow(dead_code)]
pub fn get_balance(&self, account: u32) -> anyhow::Result<u64> {
let balance: Option<i64> = self.connection.query_row(
"SELECT SUM(value) FROM received_notes WHERE (spent IS NULL OR spent = 0) AND account = ?1",
@ -575,28 +478,6 @@ impl DbAdapter {
}
}
pub fn get_nullifiers(&self) -> anyhow::Result<HashMap<Nf, NfRef>> {
let mut statement = self.connection.prepare(
"SELECT id_note, account, nf FROM received_notes WHERE spent IS NULL OR spent = 0",
)?;
let nfs_res = statement.query_map([], |row| {
let id_note: u32 = row.get(0)?;
let account: u32 = row.get(1)?;
let nf_vec: Vec<u8> = row.get(2)?;
let mut nf = [0u8; 32];
nf.clone_from_slice(&nf_vec);
let nf_ref = NfRef { id_note, account };
Ok((nf_ref, nf))
})?;
let mut nfs: HashMap<Nf, NfRef> = HashMap::new();
for n in nfs_res {
let n = n?;
nfs.insert(Nf(n.1), n.0);
}
Ok(nfs)
}
pub fn get_nullifier_amounts(
&self,
account: u32,
@ -648,69 +529,6 @@ impl DbAdapter {
Ok(nfs)
}
pub fn get_nullifiers_raw(&self) -> anyhow::Result<Vec<(u32, u64, Vec<u8>)>> {
let mut statement = self
.connection
.prepare("SELECT account, value, nf FROM received_notes")?;
let res = statement.query_map([], |row| {
let account: u32 = row.get(0)?;
let amount: i64 = row.get(1)?;
let nf: Vec<u8> = row.get(2)?;
Ok((account, amount as u64, nf))
})?;
let mut v: Vec<(u32, u64, Vec<u8>)> = vec![];
for r in res {
v.push(r?);
}
Ok(v)
}
// TODO: Depends on the type of witness - Should it returned any spendable note? sapling or orchard
pub fn get_spendable_notes(
&self,
account: u32,
anchor_height: u32,
fvk: &ExtendedFullViewingKey,
) -> anyhow::Result<Vec<SpendableNote>> {
let mut statement = self.connection.prepare(
"SELECT id_note, diversifier, value, rcm, witness FROM received_notes r, sapling_witnesses w WHERE spent IS NULL AND account = ?2
AND (r.excluded IS NULL OR NOT r.excluded) AND w.height = (
SELECT MAX(height) FROM sapling_witnesses WHERE height <= ?1
) AND r.id_note = w.note")?;
let notes = statement.query_map(params![anchor_height, account], |row| {
let id_note: u32 = row.get(0)?;
let diversifier: Vec<u8> = row.get(1)?;
let value: i64 = row.get(2)?;
let rcm: Vec<u8> = row.get(3)?;
let witness: Vec<u8> = row.get(4)?;
let mut diversifer_bytes = [0u8; 11];
diversifer_bytes.copy_from_slice(&diversifier);
let diversifier = Diversifier(diversifer_bytes);
let mut rcm_bytes = [0u8; 32];
rcm_bytes.copy_from_slice(&rcm);
let rcm = jubjub::Fr::from_bytes(&rcm_bytes).unwrap();
let rseed = Rseed::BeforeZip212(rcm);
let witness = IncrementalWitness::<Node>::read(&*witness).unwrap();
let pa = fvk.fvk.vk.to_payment_address(diversifier).unwrap();
let note = pa.create_note(value as u64, rseed).unwrap();
Ok(SpendableNote {
id: id_note,
note,
diversifier,
witness,
})
})?;
let mut spendable_notes: Vec<SpendableNote> = vec![];
for n in notes {
spendable_notes.push(n?);
}
Ok(spendable_notes)
}
pub fn get_unspent_received_notes(&self, account: u32, anchor_height: u32) -> anyhow::Result<Vec<UTXO>> {
let mut notes = vec![];
let mut statement = self.connection.prepare(
@ -855,7 +673,6 @@ impl DbAdapter {
Ok(contacts)
}
// TODO: Orchard diversifiers have a different space
pub fn get_diversifier(&self, account: u32) -> anyhow::Result<DiversifierIndex> {
let diversifier_index = self
.connection
@ -874,7 +691,6 @@ impl DbAdapter {
Ok(DiversifierIndex(diversifier_index))
}
// TODO: See get_diversifier
pub fn store_diversifier(
&self,
account: u32,
@ -952,7 +768,7 @@ impl DbAdapter {
let bip44_path = format!("m/44'/{}'/0'/0/{}", self.network().coin_type(), aindex);
let (sk, address) = derive_tkeys(self.network(), &seed, &bip44_path)?;
self.connection.execute(
"INSERT INTO taddrs(account, sk, address) VALUES (?1, ?2, ?3) ON CONFLICT DO NOTHING",
"INSERT INTO taddrs(account, sk, address) VALUES (?1, ?2, ?3)",
params![account, &sk, &address],
)?;
}
@ -964,7 +780,7 @@ impl DbAdapter {
if let Some(seed) = seed {
let keys = derive_orchard_keys(self.network().coin_type(), &seed, aindex);
self.connection.execute(
"INSERT INTO orchard_addrs(account, sk, fvk) VALUES (?1, ?2, ?3) ON CONFLICT DO NOTHING",
"INSERT INTO orchard_addrs(account, sk, fvk) VALUES (?1, ?2, ?3)",
params![account, &keys.sk, &keys.fvk],
)?;
}
@ -985,7 +801,7 @@ impl DbAdapter {
pub fn store_ua_settings(&self, account: u32, transparent: bool, sapling: bool, orchard: bool) -> anyhow::Result<()> {
self.connection.execute(
"INSERT INTO ua_settings(account, transparent, sapling, orchard) VALUES (?1, ?2, ?3, ?4) ON CONFLICT DO NOTHING",
"INSERT INTO ua_settings(account, transparent, sapling, orchard) VALUES (?1, ?2, ?3, ?4)",
params![account, transparent, sapling, orchard],
)?;
Ok(())
@ -1035,37 +851,6 @@ impl DbAdapter {
Ok(quote)
}
pub fn store_share_secret(
&self,
account: u32,
secret: &str,
index: usize,
threshold: usize,
participants: usize,
) -> anyhow::Result<()> {
self.connection.execute(
"INSERT INTO secret_shares(account, secret, idx, threshold, participants) VALUES (?1, ?2, ?3, ?4, ?5) \
ON CONFLICT (account) DO UPDATE SET secret = excluded.secret, threshold = excluded.threshold, participants = excluded.participants",
params![account, &secret, index as u32, threshold as u32, participants as u32],
)?;
Ok(())
}
pub fn get_share_secret(&self, account: u32) -> anyhow::Result<String> {
let secret = self
.connection
.query_row(
"SELECT secret FROM secret_shares WHERE account = ?1",
params![account],
|row| {
let secret: String = row.get(0)?;
Ok(secret)
},
)
.optional()?;
Ok(secret.unwrap_or("".to_string()))
}
pub fn truncate_data(&self) -> anyhow::Result<()> {
self.truncate_sync_data()?;
self.connection.execute("DELETE FROM diversifiers", [])?;
@ -1442,44 +1227,6 @@ mod tests {
use zcash_params::coin::CoinType;
use crate::sync::{CTree, Witness};
#[test]
fn test_db() {
let mut db = DbAdapter::new(CoinType::Zcash, DEFAULT_DB_PATH).unwrap();
db.init_db().unwrap();
db.trim_to_height(0).unwrap();
let db_tx = db.begin_transaction().unwrap();
DbAdapter::store_block(&db_tx, 1, &[0u8; 32], 0, &CTree::new(), None).unwrap();
let id_tx = DbAdapter::store_transaction(&[0; 32], 1, 1, 0, 20, &db_tx).unwrap();
DbAdapter::store_received_note(
&ReceivedNote {
account: 1,
height: 1,
output_index: 0,
diversifier: vec![],
value: 0,
rcm: vec![],
nf: vec![],
rho: None,
spent: None,
},
id_tx,
5,
&db_tx,
)
.unwrap();
let witness = Witness {
position: 10,
id_note: 0,
tree: CTree::new(),
filled: vec![],
cursor: CTree::new(),
cmx: [0u8; 32]
};
DbAdapter::store_witnesses(&db_tx, &witness, 1000, 1).unwrap();
db_tx.commit().unwrap();
}
#[test]
fn test_balance() {
let db = DbAdapter::new(CoinType::Zcash, DEFAULT_DB_PATH).unwrap();

View File

@ -1,116 +0,0 @@
use std::collections::HashMap;
use std::fs::File;
use std::io::{BufReader, BufWriter, Read, Write};
use byteorder::{LE, ReadBytesExt, WriteBytesExt};
use tonic::Request;
use prost::Message;
use zcash_client_backend::encoding::{decode_extended_full_viewing_key, decode_extended_spending_key, encode_extended_full_viewing_key, encode_payment_address};
use zcash_primitives::consensus::{Network, NetworkUpgrade, Parameters};
use zcash_primitives::sapling::note_encryption::SaplingDomain;
use zcash_primitives::zip32::ExtendedFullViewingKey;
use warp_api_ffi::{BlockId, BlockRange, ChainSpec, COIN_CONFIG, CoinConfig, CompactBlock, connect_lightwalletd, DbAdapter, DbAdapterBuilder, derive_zip32, init_coin};
use warp_api_ffi::sapling::{DecryptedSaplingNote, SaplingDecrypter, SaplingHasher, SaplingViewKey};
use warp_api_ffi::sync::{WarpProcessor, Synchronizer, CTree};
type SaplingSynchronizer = Synchronizer<Network, SaplingDomain<Network>, SaplingViewKey, DecryptedSaplingNote,
SaplingDecrypter<Network>, SaplingHasher>;
#[allow(dead_code)]
async fn write_block_file() {
init_coin(1, "yec-new.db").unwrap();
let coin = COIN_CONFIG[1].lock().unwrap();
let mut client = connect_lightwalletd("https://lite.ycash.xyz:9067").await.unwrap();
let network = coin.chain.network();
let start = u32::from(network.activation_height(NetworkUpgrade::Sapling).unwrap()) + 1;
let end = client.get_latest_block(Request::new(ChainSpec {})).await.unwrap().into_inner();
let end = end.height as u32;
let mut blocks = client.get_block_range(Request::new(BlockRange {
start: Some(BlockId { height: start as u64, hash: vec![] }),
end: Some(BlockId { height: end as u64, hash: vec![] }),
spam_filter_threshold: 0
})).await.unwrap().into_inner();
let file = File::create("ycash.bin").unwrap();
let mut writer = BufWriter::new(file);
while let Some(block) = blocks.message().await.unwrap() {
println!("{}", block.height);
let mut buf = prost::bytes::BytesMut::new();
block.encode(&mut buf).unwrap();
writer.write_u32::<LE>(buf.len() as u32).unwrap();
writer.write_all(&buf).unwrap();
}
}
fn read_block_file(coin: &CoinConfig, fvk: ExtendedFullViewingKey) {
let network = coin.chain.network();
let file = File::open("/home/hanh/ycash.bin").unwrap();
let mut reader = BufReader::new(file);
let db_builder = DbAdapterBuilder { coin_type: coin.coin_type, db_path: coin.db_path.as_ref().unwrap().to_owned() };
let mut synchronizer = SaplingSynchronizer {
decrypter: SaplingDecrypter::new(*network),
warper: WarpProcessor::new(SaplingHasher::default()),
vks: vec![SaplingViewKey {
account: 1,
fvk: fvk.clone(),
ivk: fvk.fvk.vk.ivk()
}],
tree: CTree::new(),
witnesses: vec![],
db: db_builder.clone(),
shielded_pool: "sapling".to_string(),
note_position: 0,
nullifiers: HashMap::new(),
_phantom: Default::default()
};
synchronizer.initialize().unwrap();
let mut blocks = vec![];
let mut height = 0;
let mut hash = [0u8; 32];
let mut time = 0;
while let Ok(len) = reader.read_u32::<LE>() {
let mut buf = vec![0u8; len as usize];
reader.read_exact(&mut buf).unwrap();
let cb: CompactBlock = CompactBlock::decode(&*buf).unwrap();
height = cb.height;
hash.copy_from_slice(&cb.hash);
time = cb.time;
blocks.push(cb);
if height % 100_000 == 0 {
synchronizer.process(blocks).unwrap();
blocks = vec![];
}
}
synchronizer.process(blocks).unwrap();
let db = db_builder.build().unwrap();
DbAdapter::store_block2(height as u32, &hash, time, &synchronizer.tree, None, &db.connection).unwrap();
}
#[tokio::main]
async fn main() {
env_logger::init();
init_coin(1, "yec-new.db").unwrap();
let coin = COIN_CONFIG[1].lock().unwrap();
let network = coin.chain.network();
let _ = dotenv::dotenv();
let seed_str = dotenv::var("SEED").unwrap();
let kp = derive_zip32(&network, &seed_str, 0, 0, None).unwrap();
let zk = kp.z_key.clone();
let sk = decode_extended_spending_key(network.hrp_sapling_extended_spending_key(), &zk).unwrap().unwrap();
let fvk = ExtendedFullViewingKey::from(&sk);
let fvk_str = encode_extended_full_viewing_key(network.hrp_sapling_extended_full_viewing_key(), &fvk);
let (_, pa) = fvk.default_address();
let address = encode_payment_address(network.hrp_sapling_payment_address(), &pa);
let db_builder = DbAdapterBuilder { coin_type: coin.coin_type, db_path: coin.db_path.as_ref().unwrap().to_owned() };
let db = db_builder.build().unwrap();
db.store_account("test", Some(&seed_str), 0, Some(&zk), &fvk_str, &address).unwrap();
// write_block_file().await;
read_block_file(&coin, fvk);
}

View File

@ -1,8 +1,9 @@
use std::collections::HashMap;
use crate::contact::{Contact, ContactDecoder};
use crate::{AccountData, CoinConfig, CompactTxStreamerClient, DbAdapter, Hash, TxFilter};
use std::convert::TryFrom;
use serde::Serialize;
use orchard::keys::{FullViewingKey, Scope};
use orchard::keys::{FullViewingKey, IncomingViewingKey, OutgoingViewingKey, Scope};
use orchard::note_encryption::OrchardDomain;
use orchard::value::ValueCommitment;
use tonic::transport::Channel;
@ -16,6 +17,7 @@ use zcash_params::coin::get_branch;
use zcash_primitives::consensus::{BlockHeight, Network, Parameters};
use zcash_primitives::memo::{Memo, MemoBytes};
use zcash_primitives::sapling::note_encryption::{PreparedIncomingViewingKey, try_sapling_note_decryption, try_sapling_output_recovery};
use zcash_primitives::sapling::SaplingIvk;
use zcash_primitives::transaction::Transaction;
use crate::unified::orchard_as_unified;
@ -29,18 +31,37 @@ pub struct ContactRef {
pub async fn get_transaction_details(coin: u8) -> anyhow::Result<()> {
let c = CoinConfig::get(coin);
let network = c.chain.network();
let mut client = c.connect_lwd().await?;
let mut keys = HashMap::new();
let reqs = {
let db = c.db.as_ref().unwrap();
let db = db.lock().unwrap();
let reqs = db.get_txid_without_memo()?;
for req in reqs.iter() {
let decryption_keys = get_decryption_keys(network, req.account, &db)?;
keys.insert(req.account, decryption_keys);
}
reqs
// Make sure we don't hold a mutex across await
};
let mut details = vec![];
for req in reqs.iter() {
let tx_details = retrieve_tx_info(network, &mut client, req.height, req.id_tx, &req.txid, &keys[&req.account]).await?;
log::info!("{:?}", tx_details);
details.push(tx_details);
}
let db = c.db.as_ref().unwrap();
let db = db.lock().unwrap();
let mut client = c.connect_lwd().await?;
let reqs = db.get_txid_without_memo()?;
for req in reqs {
let tx_details = retrieve_tx_info(network, &mut client, &db, req.account, req.height, &req.txid).await?;
log::info!("{:?}", tx_details);
db.update_transaction_with_memo(req.id_tx, &tx_details)?;
for tx_details in details.iter() {
db.update_transaction_with_memo(tx_details)?;
for c in tx_details.contacts.iter() {
db.store_contact(c, false)?;
}
}
Ok(())
}
@ -59,23 +80,20 @@ async fn fetch_raw_transaction(network: &Network, client: &mut CompactTxStreamer
Ok(tx)
}
#[derive(Clone)]
pub struct DecryptionKeys {
sapling_keys: (SaplingIvk, zcash_primitives::keys::OutgoingViewingKey),
orchard_keys: Option<(IncomingViewingKey, OutgoingViewingKey)>
}
pub fn decode_transaction(
network: &Network,
account: u32,
height: u32,
id_tx: u32,
tx: Transaction,
db: &DbAdapter,
decryption_keys: &DecryptionKeys,
) -> anyhow::Result<TransactionDetails> {
let AccountData { fvk, .. } = db.get_account_info(account)?;
let fvk = decode_extended_full_viewing_key(network.hrp_sapling_extended_full_viewing_key(), &fvk).unwrap();
let sapling_ivk = fvk.fvk.vk.ivk();
let sapling_ovk = fvk.fvk.ovk;
let okey = db.get_orchard(account)?;
let okey = okey.map(|okey| {
let fvk = FullViewingKey::from_bytes(&okey.fvk).unwrap();
(fvk.to_ivk(Scope::External), fvk.to_ovk(Scope::External))
});
let (sapling_ivk, sapling_ovk) = decryption_keys.sapling_keys.clone();
let height = BlockHeight::from_u32(height);
let mut taddress: Option<String> = None;
@ -126,7 +144,7 @@ pub fn decode_transaction(
}
if let Some(orchard_bundle) = tx.orchard_bundle() {
if let Some((orchard_ivk, orchard_ovk)) = okey {
if let Some((orchard_ivk, orchard_ovk)) = decryption_keys.orchard_keys.clone() {
for action in orchard_bundle.actions().iter() {
let domain = OrchardDomain::for_action(action);
if let Some((_note, pa, memo)) = try_note_decryption(&domain, &orchard_ivk, action) {
@ -159,6 +177,7 @@ pub fn decode_transaction(
Memo::Arbitrary(_) => "Unrecognized".to_string(),
};
let tx_details = TransactionDetails {
id_tx,
address,
memo,
contacts,
@ -167,16 +186,33 @@ pub fn decode_transaction(
Ok(tx_details)
}
fn get_decryption_keys(network: &Network, account: u32, db: &DbAdapter) -> anyhow::Result<DecryptionKeys> {
let AccountData { fvk, .. } = db.get_account_info(account)?;
let fvk = decode_extended_full_viewing_key(network.hrp_sapling_extended_full_viewing_key(), &fvk).unwrap();
let (sapling_ivk, sapling_ovk) = (fvk.fvk.vk.ivk(), fvk.fvk.ovk);
let okey = db.get_orchard(account)?;
let okey = okey.map(|okey| {
let fvk = FullViewingKey::from_bytes(&okey.fvk).unwrap();
(fvk.to_ivk(Scope::External), fvk.to_ovk(Scope::External))
});
let decryption_keys = DecryptionKeys {
sapling_keys: (sapling_ivk, sapling_ovk),
orchard_keys: okey,
};
Ok(decryption_keys)
}
pub async fn retrieve_tx_info(
network: &Network,
client: &mut CompactTxStreamerClient<Channel>,
db: &DbAdapter,
account: u32,
height: u32,
id_tx: u32,
txid: &Hash,
decryption_keys: &DecryptionKeys
) -> anyhow::Result<TransactionDetails> {
let transaction = fetch_raw_transaction(network, client, height, txid).await?;
let tx_details = decode_transaction(network, account, height, transaction, db)?;
let tx_details = decode_transaction(network, height, id_tx, transaction, &decryption_keys)?;
Ok(tx_details)
}
@ -190,6 +226,7 @@ pub struct GetTransactionDetailRequest {
#[derive(Serialize, Debug)]
pub struct TransactionDetails {
pub id_tx: u32,
pub address: String,
pub memo: String,
pub contacts: Vec<Contact>,