-
Notifications
You must be signed in to change notification settings - Fork 251
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
New component: zcash_address crate #352
Changes from 2 commits
c754363
ec77175
a366460
f7b1058
c7fcee2
b9f7049
ff07eea
ce8797e
9f7398c
ae2b8bf
6717cd8
e982d72
c2b5704
ff8695d
ff94f66
f36034c
1590565
af02e11
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
# Seeds for failure cases proptest has generated in the past. It is | ||
# automatically read and these particular cases re-run before any | ||
# novel cases are generated. | ||
# | ||
# It is recommended to check this file in to source control so that | ||
# everyone who runs the test benefits from these saved cases. | ||
cc e08469bc301313ef868b97a5c37d9a9746d9720c915a9127c89db25c3be778fd # shrinks to ua = Address([Sapling([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), P2pkh([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])]) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -120,22 +120,77 @@ impl TryFrom<&[u8]> for Address { | |
impl Address { | ||
/// Returns the raw encoding of this Unified Address. | ||
pub(crate) fn to_bytes(&self) -> Vec<u8> { | ||
self.0 | ||
let encoded: Vec<_> = self | ||
.0 | ||
.iter() | ||
.flat_map(|receiver| { | ||
let addr = receiver.addr(); | ||
// Holds by construction. | ||
assert!(addr.len() < 256); | ||
|
||
let encoded: Vec<_> = iter::empty() | ||
iter::empty() | ||
.chain(Some(receiver.typecode())) | ||
.chain(Some(addr.len() as u8)) | ||
.chain(addr.into_iter().cloned()) | ||
.chain(iter::repeat(0).take(PADDING_LEN)) | ||
.collect(); | ||
|
||
f4jumble::f4jumble(&encoded).unwrap() | ||
}) | ||
.collect() | ||
.chain(iter::repeat(0).take(PADDING_LEN)) | ||
.collect(); | ||
|
||
f4jumble::f4jumble(&encoded).unwrap() | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use std::convert::TryFrom; | ||
|
||
use proptest::{ | ||
array::{uniform11, uniform20, uniform32}, | ||
prelude::*, | ||
}; | ||
|
||
use super::{Address, Receiver}; | ||
|
||
prop_compose! { | ||
fn uniform43()(a in uniform11(0u8..), b in uniform32(0u8..)) -> [u8; 43] { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, this is a nice technique for larger byte arrays, I should have thought of this before! I've used There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One downside to this is the separate halves shrink separately (though that's less of an issue here given that these addresses are composite types). In theory we can implement our own custom array sizes directly, but I couldn't figure out how to set up the |
||
let mut c = [0; 43]; | ||
c[..11].copy_from_slice(&a); | ||
c[11..].copy_from_slice(&b); | ||
c | ||
} | ||
} | ||
|
||
fn arb_shielded_receiver() -> BoxedStrategy<Receiver> { | ||
prop_oneof![ | ||
uniform43().prop_map(Receiver::Sapling), | ||
uniform43().prop_map(Receiver::Orchard), | ||
] | ||
.boxed() | ||
} | ||
|
||
fn arb_transparent_receiver() -> BoxedStrategy<Receiver> { | ||
prop_oneof![ | ||
uniform20(0u8..).prop_map(Receiver::P2pkh), | ||
uniform20(0u8..).prop_map(Receiver::P2sh), | ||
] | ||
.boxed() | ||
} | ||
|
||
prop_compose! { | ||
fn arb_unified_address()( | ||
shielded in prop::collection::hash_set(arb_shielded_receiver(), 1..2), | ||
transparent in prop::option::of(arb_transparent_receiver()), | ||
) -> Address { | ||
Address(shielded.into_iter().chain(transparent).collect()) | ||
} | ||
} | ||
|
||
proptest! { | ||
#[test] | ||
fn ua_roundtrip(ua in arb_unified_address()) { | ||
let bytes = ua.to_bytes(); | ||
let decoded = Address::try_from(&bytes[..]); | ||
prop_assert_eq!(decoded, Ok(ua)); | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe this could panic if the length of
encoded
were greater than 16448 bytes.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently there is no way to construct a
unified::Address
other than decoding one (which checks the length), so this cannot panic. When we add other constructors, we can similarly enforce correctness there.