mirror of
https://github.com/Qortal/piratewallet-light-cli.git
synced 2025-02-14 10:55:47 +00:00
Write outgoing metadata
This commit is contained in:
parent
3ad99c7a3d
commit
b0f7d8fcf6
@ -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),
|
||||
})
|
||||
);
|
||||
|
||||
|
@ -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(())
|
||||
}
|
||||
}
|
||||
|
@ -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…
x
Reference in New Issue
Block a user