diff --git a/lib/src/lightclient.rs b/lib/src/lightclient.rs index 9d5419c..20f23ed 100644 --- a/lib/src/lightclient.rs +++ b/lib/src/lightclient.rs @@ -1015,11 +1015,18 @@ impl LightClient { // Collect outgoing metadata let outgoing_json = wtx.outgoing_metadata.iter() - .map(|om| - object!{ + .map(|om| { + let mut o = object!{ "address" => om.address.clone(), "value" => om.value, "memo" => LightWallet::memo_str(&Some(om.memo.clone())), + }; + + if include_memo_hex { + o.insert("memohex", hex::encode(om.memo.as_bytes())).unwrap(); + } + + return o; }).collect::>(); object! { diff --git a/lib/src/lightwallet.rs b/lib/src/lightwallet.rs index d5a957d..b383fa9 100644 --- a/lib/src/lightwallet.rs +++ b/lib/src/lightwallet.rs @@ -2074,22 +2074,12 @@ impl LightWallet { Some(s) => { // If the string starts with an "0x", and contains only hex chars ([a-f0-9]+) then // interpret it as a hex - let s_bytes = if s.to_lowercase().starts_with("0x") { - match hex::decode(&s[2..s.len()]) { - Ok(data) => data, - Err(_) => Vec::from(s.as_bytes()) - } - } else { - Vec::from(s.as_bytes()) - }; - - match Memo::from_bytes(&s_bytes) { - None => { - let e = format!("Error creating output. Memo {:?} is too long", s); + match utils::interpret_memo_string(&s) { + Ok(m) => Some(m), + Err(e) => { error!("{}", e); return Err(e); - }, - Some(m) => Some(m) + } } } }; @@ -2162,10 +2152,16 @@ impl LightWallet { None => Memo::default(), Some(s) => { // If the address is not a z-address, then drop the memo - if LightWallet::is_shielded_address(&addr.to_string(), &self.config) { - Memo::from_bytes(s.as_bytes()).unwrap() - } else { + if !LightWallet::is_shielded_address(&addr.to_string(), &self.config) { Memo::default() + } else { + match utils::interpret_memo_string(s) { + Ok(m) => m, + Err(e) => { + error!("{}", e); + Memo::default() + } + } } } }, diff --git a/lib/src/lightwallet/tests.rs b/lib/src/lightwallet/tests.rs index c74bf25..d8ec8f7 100644 --- a/lib/src/lightwallet/tests.rs +++ b/lib/src/lightwallet/tests.rs @@ -1412,6 +1412,16 @@ fn test_z_incoming_hex_memo() { let sent_tx = Transaction::read(&raw_tx[..]).unwrap(); let sent_txid = sent_tx.txid(); + // Make sure it is in the mempool properly + { + let mempool = wallet.mempool_txs.read().unwrap(); + + let wtx = mempool.get(&sent_txid).unwrap(); + assert_eq!(wtx.outgoing_metadata.get(0).unwrap().address, my_address); + assert_eq!(wtx.outgoing_metadata.get(0).unwrap().value, AMOUNT1 - fee); + assert_eq!(wtx.outgoing_metadata.get(0).unwrap().memo.to_utf8().unwrap().unwrap(), orig_memo); + } + // Add it to a block let mut cb3 = FakeCompactBlock::new(2, block_hash); cb3.add_tx(&sent_tx); diff --git a/lib/src/lightwallet/utils.rs b/lib/src/lightwallet/utils.rs index 1ece11e..7fd464c 100644 --- a/lib/src/lightwallet/utils.rs +++ b/lib/src/lightwallet/utils.rs @@ -1,5 +1,6 @@ use std::io::{self, Read, Write}; use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; +use zcash_primitives::note_encryption::Memo; pub fn read_string(mut reader: R) -> io::Result { // Strings are written as len + bytes @@ -18,4 +19,26 @@ pub fn write_string(mut writer: W, s: &String) -> io::Result<()> { // Strings are written as len + utf8 writer.write_u64::(s.as_bytes().len() as u64)?; writer.write_all(s.as_bytes()) +} + +// Interpret a string or hex-encoded memo, and return a Memo object +pub fn interpret_memo_string(memo_str: &String) -> Result { + // If the string starts with an "0x", and contains only hex chars ([a-f0-9]+) then + // interpret it as a hex + let s_bytes = if memo_str.to_lowercase().starts_with("0x") { + match hex::decode(&memo_str[2..memo_str.len()]) { + Ok(data) => data, + Err(_) => Vec::from(memo_str.as_bytes()) + } + } else { + Vec::from(memo_str.as_bytes()) + }; + + match Memo::from_bytes(&s_bytes) { + None => { + let e = format!("Error creating output. Memo {:?} is too long", memo_str); + return Err(e); + }, + Some(m) => Ok(m) + } } \ No newline at end of file