From 4be3290e408ddd138fd47e5db95a31b0419dfd20 Mon Sep 17 00:00:00 2001 From: Luke Parker Date: Sat, 7 Jan 2023 05:37:43 -0500 Subject: [PATCH] Convert the FeaturedAddress tuple to a struct Not only did we already have multiple booleans in it, yet it theoretically could expand in the future. Not only is this more explicit, it actually cleans some existing code. --- coins/monero/src/tests/address.rs | 17 +++++--- coins/monero/src/wallet/address.rs | 34 ++++++++------- coins/monero/src/wallet/mod.rs | 4 +- coins/monero/tests/scan.rs | 66 +++++++++++++++++++++++++----- processor/src/coin/monero.rs | 5 ++- 5 files changed, 93 insertions(+), 33 deletions(-) diff --git a/coins/monero/src/tests/address.rs b/coins/monero/src/tests/address.rs index 3c005735..3950d6d1 100644 --- a/coins/monero/src/tests/address.rs +++ b/coins/monero/src/tests/address.rs @@ -83,13 +83,14 @@ fn featured() { let subaddress = (features & SUBADDRESS_FEATURE_BIT) == SUBADDRESS_FEATURE_BIT; - let mut id = [0; 8]; - OsRng.fill_bytes(&mut id); - let id = Some(id).filter(|_| (features & INTEGRATED_FEATURE_BIT) == INTEGRATED_FEATURE_BIT); + let mut payment_id = [0; 8]; + OsRng.fill_bytes(&mut payment_id); + let payment_id = Some(payment_id) + .filter(|_| (features & INTEGRATED_FEATURE_BIT) == INTEGRATED_FEATURE_BIT); let guaranteed = (features & GUARANTEED_FEATURE_BIT) == GUARANTEED_FEATURE_BIT; - let kind = AddressType::Featured(subaddress, id, guaranteed); + let kind = AddressType::Featured { subaddress, payment_id, guaranteed }; let meta = AddressMeta::new(network, kind); let addr = MoneroAddress::new(meta, spend, view); @@ -100,7 +101,7 @@ fn featured() { assert_eq!(addr.view, view); assert_eq!(addr.subaddress(), subaddress); - assert_eq!(addr.payment_id(), id); + assert_eq!(addr.payment_id(), payment_id); assert_eq!(addr.guaranteed(), guaranteed); } } @@ -159,7 +160,11 @@ fn featured_vectors() { MoneroAddress::new( AddressMeta::new( network, - AddressType::Featured(vector.subaddress, vector.payment_id, vector.guaranteed) + AddressType::Featured { + subaddress: vector.subaddress, + payment_id: vector.payment_id, + guaranteed: vector.guaranteed + } ), spend, view diff --git a/coins/monero/src/wallet/address.rs b/coins/monero/src/wallet/address.rs index b0f09927..ad7777d2 100644 --- a/coins/monero/src/wallet/address.rs +++ b/coins/monero/src/wallet/address.rs @@ -24,7 +24,7 @@ pub enum AddressType { Standard, Integrated([u8; 8]), Subaddress, - Featured(bool, Option<[u8; 8]>, bool), + Featured { subaddress: bool, payment_id: Option<[u8; 8]>, guaranteed: bool }, } #[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)] @@ -56,26 +56,27 @@ pub enum AddressSpec { Standard, Integrated([u8; 8]), Subaddress(SubaddressIndex), - Featured(Option, Option<[u8; 8]>, bool), + Featured { subaddress: Option, payment_id: Option<[u8; 8]>, guaranteed: bool }, } impl AddressType { pub fn subaddress(&self) -> bool { - matches!(self, AddressType::Subaddress) || matches!(self, AddressType::Featured(true, ..)) + matches!(self, AddressType::Subaddress) || + matches!(self, AddressType::Featured { subaddress: true, .. }) } pub fn payment_id(&self) -> Option<[u8; 8]> { if let AddressType::Integrated(id) = self { Some(*id) - } else if let AddressType::Featured(_, id, _) = self { - *id + } else if let AddressType::Featured { payment_id, .. } = self { + *payment_id } else { None } } pub fn guaranteed(&self) -> bool { - matches!(self, AddressType::Featured(_, _, true)) + matches!(self, AddressType::Featured { guaranteed: true, .. }) } } @@ -137,7 +138,7 @@ impl AddressMeta { AddressType::Standard => bytes.0, AddressType::Integrated(_) => bytes.1, AddressType::Subaddress => bytes.2, - AddressType::Featured(..) => bytes.3, + AddressType::Featured { .. } => bytes.3, } } @@ -146,7 +147,7 @@ impl AddressMeta { AddressMeta { _bytes: PhantomData, network, kind } } - // Returns an incomplete type in the case of Integrated/Featured addresses + // Returns an incomplete instantiation in the case of Integrated/Featured addresses fn from_byte(byte: u8) -> Result { let mut meta = None; for network in [Network::Mainnet, Network::Testnet, Network::Stagenet] { @@ -155,7 +156,9 @@ impl AddressMeta { _ if byte == standard => Some(AddressType::Standard), _ if byte == integrated => Some(AddressType::Integrated([0; 8])), _ if byte == subaddress => Some(AddressType::Subaddress), - _ if byte == featured => Some(AddressType::Featured(false, None, false)), + _ if byte == featured => { + Some(AddressType::Featured { subaddress: false, payment_id: None, guaranteed: false }) + } _ => None, } { meta = Some(AddressMeta::new(network, kind)); @@ -200,7 +203,7 @@ impl ToString for Address { let mut data = vec![self.meta.to_byte()]; data.extend(self.spend.compress().to_bytes()); data.extend(self.view.compress().to_bytes()); - if let AddressType::Featured(subaddress, payment_id, guaranteed) = self.meta.kind { + if let AddressType::Featured { subaddress, payment_id, guaranteed } = self.meta.kind { // Technically should be a VarInt, yet we don't have enough features it's needed data.push( u8::from(subaddress) + (u8::from(payment_id.is_some()) << 1) + (u8::from(guaranteed) << 2), @@ -233,7 +236,7 @@ impl Address { .ok_or(AddressError::InvalidKey)?; let mut read = 65; - if matches!(meta.kind, AddressType::Featured(..)) { + if matches!(meta.kind, AddressType::Featured { .. }) { if raw[read] >= (2 << 3) { Err(AddressError::UnknownFeatures)?; } @@ -242,8 +245,11 @@ impl Address { let integrated = ((raw[read] >> 1) & 1) == 1; let guaranteed = ((raw[read] >> 2) & 1) == 1; - meta.kind = - AddressType::Featured(subaddress, Some([0; 8]).filter(|_| integrated), guaranteed); + meta.kind = AddressType::Featured { + subaddress, + payment_id: Some([0; 8]).filter(|_| integrated), + guaranteed, + }; read += 1; } @@ -258,7 +264,7 @@ impl Address { if let AddressType::Integrated(ref mut id) = meta.kind { id.copy_from_slice(&raw[(read - 8) .. read]); } - if let AddressType::Featured(_, Some(ref mut id), _) = meta.kind { + if let AddressType::Featured { payment_id: Some(ref mut id), .. } = meta.kind { id.copy_from_slice(&raw[(read - 8) .. read]); } diff --git a/coins/monero/src/wallet/mod.rs b/coins/monero/src/wallet/mod.rs index 48ee3a34..a30f6be0 100644 --- a/coins/monero/src/wallet/mod.rs +++ b/coins/monero/src/wallet/mod.rs @@ -140,13 +140,13 @@ impl ViewPair { (spend, view) = self.subaddress_keys(index); AddressMeta::new(network, AddressType::Subaddress) } - AddressSpec::Featured(subaddress, payment_id, guaranteed) => { + AddressSpec::Featured { subaddress, payment_id, guaranteed } => { if let Some(index) = subaddress { (spend, view) = self.subaddress_keys(index); } AddressMeta::new( network, - AddressType::Featured(subaddress.is_some(), payment_id, guaranteed), + AddressType::Featured { subaddress: subaddress.is_some(), payment_id, guaranteed }, ) } }; diff --git a/coins/monero/tests/scan.rs b/coins/monero/tests/scan.rs index af42ea96..0938b95b 100644 --- a/coins/monero/tests/scan.rs +++ b/coins/monero/tests/scan.rs @@ -68,8 +68,13 @@ test!( |_, mut builder: Builder, _| async move { let view = runner::random_address().1; let scanner = Scanner::from_view(view.clone(), Some(HashSet::new())); - builder - .add_payment(view.address(Network::Mainnet, AddressSpec::Featured(None, None, false)), 5); + builder.add_payment( + view.address( + Network::Mainnet, + AddressSpec::Featured { subaddress: None, payment_id: None, guaranteed: false }, + ), + 5, + ); (builder.build().unwrap(), scanner) }, |_, tx: Transaction, _, mut state: Scanner| async move { @@ -90,7 +95,14 @@ test!( scanner.register_subaddress(subaddress); builder.add_payment( - view.address(Network::Mainnet, AddressSpec::Featured(Some(subaddress), None, false)), + view.address( + Network::Mainnet, + AddressSpec::Featured { + subaddress: Some(subaddress), + payment_id: None, + guaranteed: false, + }, + ), 5, ); (builder.build().unwrap(), (scanner, subaddress)) @@ -113,7 +125,14 @@ test!( OsRng.fill_bytes(&mut payment_id); builder.add_payment( - view.address(Network::Mainnet, AddressSpec::Featured(None, Some(payment_id), false)), + view.address( + Network::Mainnet, + AddressSpec::Featured { + subaddress: None, + payment_id: Some(payment_id), + guaranteed: false, + }, + ), 5, ); (builder.build().unwrap(), (scanner, payment_id)) @@ -142,7 +161,11 @@ test!( builder.add_payment( view.address( Network::Mainnet, - AddressSpec::Featured(Some(subaddress), Some(payment_id), false), + AddressSpec::Featured { + subaddress: Some(subaddress), + payment_id: Some(payment_id), + guaranteed: false, + }, ), 5, ); @@ -164,8 +187,13 @@ test!( let view = runner::random_address().1; let scanner = Scanner::from_view(view.clone(), None); - builder - .add_payment(view.address(Network::Mainnet, AddressSpec::Featured(None, None, true)), 5); + builder.add_payment( + view.address( + Network::Mainnet, + AddressSpec::Featured { subaddress: None, payment_id: None, guaranteed: true }, + ), + 5, + ); (builder.build().unwrap(), scanner) }, |_, tx: Transaction, _, mut state: Scanner| async move { @@ -186,7 +214,14 @@ test!( scanner.register_subaddress(subaddress); builder.add_payment( - view.address(Network::Mainnet, AddressSpec::Featured(Some(subaddress), None, true)), + view.address( + Network::Mainnet, + AddressSpec::Featured { + subaddress: Some(subaddress), + payment_id: None, + guaranteed: true, + }, + ), 5, ); (builder.build().unwrap(), (scanner, subaddress)) @@ -209,7 +244,14 @@ test!( OsRng.fill_bytes(&mut payment_id); builder.add_payment( - view.address(Network::Mainnet, AddressSpec::Featured(None, Some(payment_id), true)), + view.address( + Network::Mainnet, + AddressSpec::Featured { + subaddress: None, + payment_id: Some(payment_id), + guaranteed: true, + }, + ), 5, ); (builder.build().unwrap(), (scanner, payment_id)) @@ -238,7 +280,11 @@ test!( builder.add_payment( view.address( Network::Mainnet, - AddressSpec::Featured(Some(subaddress), Some(payment_id), true), + AddressSpec::Featured { + subaddress: Some(subaddress), + payment_id: Some(payment_id), + guaranteed: true, + }, ), 5, ); diff --git a/processor/src/coin/monero.rs b/processor/src/coin/monero.rs index 58afe3d8..5f364f7e 100644 --- a/processor/src/coin/monero.rs +++ b/processor/src/coin/monero.rs @@ -106,7 +106,10 @@ impl Monero { spend: dfg::EdwardsPoint, subaddress: Option, ) -> MoneroAddress { - self.view_pair(spend).address(Network::Mainnet, AddressSpec::Featured(subaddress, None, true)) + self.view_pair(spend).address( + Network::Mainnet, + AddressSpec::Featured { subaddress, payment_id: None, guaranteed: true }, + ) } fn scanner(&self, spend: dfg::EdwardsPoint) -> Scanner {