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.
This commit is contained in:
Luke Parker 2023-01-07 05:37:43 -05:00
parent 7b0b8a20ec
commit 4be3290e40
No known key found for this signature in database
5 changed files with 93 additions and 33 deletions

View file

@ -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

View file

@ -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<SubaddressIndex>, Option<[u8; 8]>, bool),
Featured { subaddress: Option<SubaddressIndex>, 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<B: AddressBytes> AddressMeta<B> {
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<B: AddressBytes> AddressMeta<B> {
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<Self, AddressError> {
let mut meta = None;
for network in [Network::Mainnet, Network::Testnet, Network::Stagenet] {
@ -155,7 +156,9 @@ impl<B: AddressBytes> AddressMeta<B> {
_ 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<B: AddressBytes> ToString for Address<B> {
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<B: AddressBytes> Address<B> {
.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<B: AddressBytes> Address<B> {
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<B: AddressBytes> Address<B> {
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]);
}

View file

@ -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 },
)
}
};

View file

@ -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,
);

View file

@ -106,7 +106,10 @@ impl Monero {
spend: dfg::EdwardsPoint,
subaddress: Option<SubaddressIndex>,
) -> 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 {