Browse Source

Write outgoing metadata

master
Aditya Kulkarni 5 years ago
parent
commit
b0f7d8fcf6
  1. 23
      src/lightclient.rs
  2. 59
      src/lightwallet/data.rs
  3. 57
      src/lightwallet/mod.rs

23
src/lightclient.rs

@ -441,14 +441,23 @@ impl LightClient {
// TODO: What happens if change is > than sent ?
// Collect outgoing metadata
let outgoing_json = v.outgoing_metadata.iter()
.map(|om|
object!{
"address" => om.address.clone(),
"value" => om.value,
"memo" => LightWallet::memo_str(&Some(om.memo.clone())),
})
.collect::<Vec<JsonValue>>();
txns.push(object! {
"block_height" => v.block,
"txid" => format!("{}", v.txid),
"amount" => total_change as i64
- v.total_shielded_value_spent as i64
- v.total_transparent_value_spent as i64,
"address" => None::<String>, // TODO: For send, we don't have an address
"memo" => None::<String>
"outgoing_metadata" => outgoing_json,
});
}
@ -461,15 +470,7 @@ impl LightClient {
"txid" => format!("{}", v.txid),
"amount" => nd.note.value as i64,
"address" => self.wallet.note_address(nd),
"memo" => match &nd.memo {
Some(memo) => {
match memo.to_utf8() {
Some(Ok(memo_str)) => Some(memo_str),
_ => None
}
}
_ => None
}
"memo" => LightWallet::memo_str(&nd.memo),
})
);

59
src/lightwallet/data.rs

@ -324,6 +324,42 @@ impl Utxo {
}
}
pub struct OutgoingTxMetadata {
pub address: String,
pub value : u64,
pub memo : Memo,
}
impl OutgoingTxMetadata {
pub fn read<R: Read>(mut reader: R) -> io::Result<Self> {
let address_len = reader.read_u64::<LittleEndian>()?;
let mut address_bytes = vec![0; address_len as usize];
reader.read_exact(&mut address_bytes)?;
let address = String::from_utf8(address_bytes).unwrap();
let value = reader.read_u64::<LittleEndian>()?;
let mut memo_bytes = [0u8; 512];
reader.read_exact(&mut memo_bytes)?;
let memo = Memo::from_bytes(&memo_bytes).unwrap();
Ok(OutgoingTxMetadata{
address,
value,
memo,
})
}
pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
// Strings are written as len + utf8
writer.write_u64::<LittleEndian>(self.address.as_bytes().len() as u64)?;
writer.write_all(self.address.as_bytes())?;
writer.write_u64::<LittleEndian>(self.value)?;
writer.write_all(self.memo.as_bytes())
}
}
pub struct WalletTx {
pub block: i32,
@ -345,11 +381,14 @@ pub struct WalletTx {
// Total amount of transparent funds that belong to us that were spent in this Tx.
pub total_transparent_value_spent : u64,
// All outgoing sapling sends to addresses outside this wallet
pub outgoing_metadata: Vec<OutgoingTxMetadata>,
}
impl WalletTx {
pub fn serialized_version() -> u64 {
return 1;
return 2;
}
pub fn new(height: i32, txid: &TxId) -> Self {
@ -359,13 +398,14 @@ impl WalletTx {
notes: vec![],
utxos: vec![],
total_shielded_value_spent: 0,
total_transparent_value_spent: 0
total_transparent_value_spent: 0,
outgoing_metadata: vec![],
}
}
pub fn read<R: Read>(mut reader: R) -> io::Result<Self> {
let version = reader.read_u64::<LittleEndian>()?;
assert_eq!(version, WalletTx::serialized_version());
assert!(version <= WalletTx::serialized_version());
let block = reader.read_i32::<LittleEndian>()?;
@ -380,13 +420,21 @@ impl WalletTx {
let total_shielded_value_spent = reader.read_u64::<LittleEndian>()?;
let total_transparent_value_spent = reader.read_u64::<LittleEndian>()?;
// Outgoing metadata was only added in version 2
let outgoing_metadata = match version {
1 => vec![],
_ => Vector::read(&mut reader, |r| OutgoingTxMetadata::read(r))?
};
Ok(WalletTx{
block,
txid,
notes,
utxos,
total_shielded_value_spent,
total_transparent_value_spent
total_transparent_value_spent,
outgoing_metadata,
})
}
@ -403,6 +451,9 @@ impl WalletTx {
writer.write_u64::<LittleEndian>(self.total_shielded_value_spent)?;
writer.write_u64::<LittleEndian>(self.total_transparent_value_spent)?;
// Write the outgoing metadata
Vector::write(&mut writer, &self.outgoing_metadata, |w, om| om.write(w))?;
Ok(())
}
}

57
src/lightwallet/mod.rs

@ -34,7 +34,7 @@ use zcash_primitives::{
primitives::{PaymentAddress},
};
use data::{BlockData, WalletTx, Utxo, SaplingNoteData, SpendableNote};
use data::{BlockData, WalletTx, Utxo, SaplingNoteData, SpendableNote, OutgoingTxMetadata};
use crate::address;
use crate::prover;
@ -354,6 +354,18 @@ impl LightWallet {
}
}
pub fn memo_str(memo: &Option<Memo>) -> Option<String> {
match memo {
Some(memo) => {
match memo.to_utf8() {
Some(Ok(memo_str)) => Some(memo_str),
_ => None
}
}
_ => None
}
}
pub fn address_from_sk(&self, sk: &secp256k1::SecretKey) -> String {
let secp = secp256k1::Secp256k1::new();
let pk = secp256k1::PublicKey::from_secret_key(&secp, &sk);
@ -593,6 +605,14 @@ impl LightWallet {
// Also scan the output to see if it can be decoded with our OutgoingViewKey
// If it can, then we sent this transaction, so we should be able to get
// the memo and value for our records
// First, collect all our z addresses, to check for change
// Collect z addresses
let z_addresses = self.address.iter().map( |ad| {
encode_payment_address(self.config.hrp_sapling_address(), &ad)
}).collect::<HashSet<String>>();
// Search all ovks that we have
let ovks: Vec<_> = self.extfvks.iter().map(|extfvk| extfvk.fvk.ovk).collect();
for (_account, ovk) in ovks.iter().enumerate() {
match try_sapling_output_recovery(ovk,
@ -601,12 +621,35 @@ impl LightWallet {
&output.ephemeral_key.as_prime_order(&JUBJUB).unwrap(),
&output.enc_ciphertext,
&output.out_ciphertext) {
Some((note, address, memo)) => {
// This could be a chane or an outgoing transaction
println!("Recovered outgoing for {} to {} :{:?}",
note.value,
encode_payment_address(self.config.hrp_sapling_address(), &address),
memo.to_utf8())
Some((note, payment_address, memo)) => {
let address = encode_payment_address(self.config.hrp_sapling_address(),
&payment_address);
// Check if this is a change address
if z_addresses.contains(&address) {
continue;
}
{
// Update the WalletTx
// Do it in a short scope because of the write lock.
info!("A sapling output was sent in {}", tx.txid());
let mut txs = self.txs.write().unwrap();
if txs.get(&tx.txid()).unwrap().outgoing_metadata.iter()
.find(|om| om.address == address && om.value == note.value)
.is_some() {
warn!("Duplicate outgoing metadata");
continue;
}
// Write the outgoing metadata
txs.get_mut(&tx.txid()).unwrap()
.outgoing_metadata
.push(OutgoingTxMetadata{
address, value: note.value, memo,
});
}
},
None => {}
};

Loading…
Cancel
Save