diff --git a/core/src/proto/types.rs b/core/src/proto/types.rs index a4e7b6df85b..b7310e2e950 100644 --- a/core/src/proto/types.rs +++ b/core/src/proto/types.rs @@ -4,6 +4,7 @@ use std::collections::{BTreeMap, HashMap, HashSet}; use std::convert::TryFrom; use std::hash::{Hash, Hasher}; use std::marker::PhantomData; +use std::ops::Deref; use borsh::schema::{add_definition, Declaration, Definition}; use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; @@ -805,6 +806,47 @@ impl borsh::BorshSchema for MaspBuilder { } } +/// Memo field that may be populated with arbitrary data. +#[derive( + Clone, + Debug, + BorshSerialize, + BorshDeserialize, + BorshSchema, + Serialize, + Deserialize, +)] +pub struct Memo { + inner: Vec, +} + +impl Memo { + /// Up to 1 KiB of data. + pub const MAX_CAPACITY: usize = 1024; + + /// Build a new memo field. + pub fn new(data: &[u8]) -> Option { + (data.len() <= Self::MAX_CAPACITY).then(|| Memo { + inner: data.to_vec(), + }) + } + + /// Hash this memo section. + pub fn hash<'a>(&self, hasher: &'a mut Sha256) -> &'a mut Sha256 { + hasher.update(&self.inner); + hasher + } +} + +impl Deref for Memo { + type Target = [u8]; + + #[inline] + fn deref(&self) -> &[u8] { + &self.inner + } +} + /// A section of a transaction. Carries an independent piece of information /// necessary for the processing of a transaction. #[derive( @@ -838,6 +880,8 @@ pub enum Section { MaspBuilder(MaspBuilder), /// Wrap a header with a section for the purposes of computing hashes Header(Header), + /// Memo containing arbitrary data. + Memo(Memo), } impl Section { @@ -859,6 +903,7 @@ impl Section { hasher.update(tx.txid().as_ref()); hasher } + Self::Memo(memo) => memo.hash(hasher), Self::Header(header) => header.hash(hasher), } } @@ -1169,6 +1214,18 @@ impl Tx { None } + /// Look-up the first memo field found in the transaction's + /// sections. + pub fn get_memo(&self) -> Option<&Memo> { + self.sections.iter().find_map(|sec| { + if let Section::Memo(memo) = sec { + Some(memo) + } else { + None + } + }) + } + /// Add a new section to the transaction pub fn add_section(&mut self, section: Section) -> &mut Section { self.sections.push(section); @@ -1486,6 +1543,15 @@ impl Tx { (self, sechash) } + /// Add a memo section to the transaction + pub fn add_memo( + &mut self, + memo: Memo, + ) -> (&mut Self, crate::types::hash::Hash) { + let sechash = self.add_section(Section::Memo(memo)).get_hash(); + (self, sechash) + } + /// Add a masp tx section to the tx builder pub fn add_masp_tx_section( &mut self,