2020-02-12 17:21:59 -08:00
use std ::{ cmp , convert ::TryFrom , fmt } ;
2020-08-15 18:50:18 -07:00
/// A 512-byte (plaintext) memo associated with a note, as described in
2020-02-12 17:21:59 -08:00
/// [protocol specification §5.5][ps].
///
/// The _Memo_ field of a note is a plaintext type; the parent note is
/// what is encrypted and stored on the blockchain. The underlying
/// usage of the memo field is by agreement between the sender and
/// recipient of the note.
///
/// [ps]: https://zips.z.cash/protocol/protocol.pdf#notept
2020-02-12 18:30:29 -08:00
#[ derive(Clone) ]
2020-07-15 01:50:05 -07:00
pub struct Memo ( pub ( crate ) Box < [ u8 ; 512 ] > ) ;
2020-02-12 17:21:59 -08:00
impl < ' a > TryFrom < & ' a [ u8 ] > for Memo {
type Error = & 'static str ;
fn try_from ( input : & ' a [ u8 ] ) -> Result < Self , Self ::Error > {
let mut full_bytes = [ 0 ; 512 ] ;
match input . len ( ) . cmp ( & 512 ) {
cmp ::Ordering ::Less = > {
full_bytes [ 0 .. input . len ( ) ] . copy_from_slice ( input ) ;
2020-02-12 18:30:29 -08:00
Ok ( Memo ( Box ::new ( full_bytes ) ) )
2020-02-12 17:21:59 -08:00
}
cmp ::Ordering ::Equal = > {
full_bytes [ .. ] . copy_from_slice ( input ) ;
2020-02-12 18:30:29 -08:00
Ok ( Memo ( Box ::new ( full_bytes ) ) )
2020-02-12 17:21:59 -08:00
}
cmp ::Ordering ::Greater = > Err ( " Memos have a max length of 512 bytes. " ) ,
}
}
}
impl fmt ::Debug for Memo {
fn fmt ( & self , f : & mut fmt ::Formatter ) -> fmt ::Result {
let output : String ;
// This saves work but if the 'valid utf8 string' is just a
// bunch of numbers, it prints them out like
// 'Memo("\u{0}\u{0}..")', so. ¯\_(ツ)_/¯
match std ::str ::from_utf8 ( & self . 0 [ .. ] ) {
Ok ( memo ) = > output = String ::from ( memo ) ,
_ = > output = hex ::encode ( & self . 0 [ .. ] ) ,
}
f . debug_tuple ( " Memo " ) . field ( & output ) . finish ( )
}
}
#[ test ]
fn memo_fmt ( ) {
2020-11-09 16:29:25 -08:00
zebra_test ::init ( ) ;
2020-02-12 18:30:29 -08:00
let memo = Memo ( Box ::new (
2020-02-12 17:21:59 -08:00
* b " thiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiis \
iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiis \
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa \
veeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeryyyyyyyyyyyyyyyyyyyyyyyyyy \
looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong \
meeeeeeeeeeeeeeeeeeemooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo \
but it ' s just short enough " ,
2020-02-12 18:30:29 -08:00
) ) ;
2020-02-12 17:21:59 -08:00
assert_eq! ( format! ( " {:?} " , memo ) ,
" Memo( \" thiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiis iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiis aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa veeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeryyyyyyyyyyyyyyyyyyyyyyyyyy looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong meeeeeeeeeeeeeeeeeeemooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo but it \\ \' s just short enough \" ) "
) ;
let mut some_bytes = [ 0 u8 ; 512 ] ;
some_bytes [ 0 ] = 0xF6 ;
2020-02-12 18:30:29 -08:00
assert_eq! ( format! ( " {:?} " , Memo ( Box ::new ( some_bytes ) ) ) ,
2020-02-12 17:21:59 -08:00
" Memo( \" f600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \" ) "
) ;
}
#[ test ]
fn memo_from_string ( ) {
2020-11-09 16:29:25 -08:00
zebra_test ::init ( ) ;
2020-02-12 17:21:59 -08:00
let memo = Memo ::try_from ( " foo bar baz " . as_ref ( ) ) . unwrap ( ) ;
let mut bytes = [ 0 ; 512 ] ;
bytes [ 0 .. 11 ] . copy_from_slice ( & [ 102 , 111 , 111 , 32 , 98 , 97 , 114 , 32 , 98 , 97 , 122 ] ) ;
assert! ( memo . 0. iter ( ) . eq ( bytes . iter ( ) ) ) ;
}