feat: add helper to create bootstrap addresses (#269)

This commit is contained in:
Santiago Carmuega 2023-07-29 23:15:00 +02:00 committed by GitHub
parent ea9c4e8b59
commit e117a2723a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 69 additions and 25 deletions

View file

@ -17,3 +17,4 @@ pallas-codec = { version = "0.19.0-alpha.0", path = "../pallas-codec" }
base58 = "0.2.0"
bech32 = "0.9.1"
thiserror = "1.0.31"
crc = "3.0.1"

View file

@ -14,8 +14,8 @@ pub type StakeholderId = Blake2b224;
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum AddrDistr {
Variant0(StakeholderId),
Variant1,
SingleKeyDistribution(StakeholderId),
BootstrapEraDistribution,
}
impl<'b, C> minicbor::Decode<'b, C> for AddrDistr {
@ -24,8 +24,8 @@ impl<'b, C> minicbor::Decode<'b, C> for AddrDistr {
let variant = d.u32()?;
match variant {
0 => Ok(AddrDistr::Variant0(d.decode_with(ctx)?)),
1 => Ok(AddrDistr::Variant1),
0 => Ok(AddrDistr::SingleKeyDistribution(d.decode_with(ctx)?)),
1 => Ok(AddrDistr::BootstrapEraDistribution),
_ => Err(minicbor::decode::Error::message(
"invalid variant for addrdstr",
)),
@ -40,14 +40,14 @@ impl minicbor::Encode<()> for AddrDistr {
_ctx: &mut (),
) -> Result<(), minicbor::encode::Error<W::Error>> {
match self {
AddrDistr::Variant0(x) => {
AddrDistr::SingleKeyDistribution(x) => {
e.array(2)?;
e.u32(0)?;
e.encode(x)?;
Ok(())
}
AddrDistr::Variant1 => {
AddrDistr::BootstrapEraDistribution => {
e.array(1)?;
e.u32(1)?;
@ -101,8 +101,8 @@ impl<C> minicbor::Encode<C> for AddrType {
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum AddrAttrProperty {
AddrDistr(AddrDistr),
Bytes(ByteVec),
Unparsed(u8, ByteVec),
DerivationPath(ByteVec),
NetworkTag(ByteVec),
}
impl<'b, C> minicbor::Decode<'b, C> for AddrAttrProperty {
@ -111,8 +111,11 @@ impl<'b, C> minicbor::Decode<'b, C> for AddrAttrProperty {
match key {
0 => Ok(AddrAttrProperty::AddrDistr(d.decode_with(ctx)?)),
1 => Ok(AddrAttrProperty::Bytes(d.decode_with(ctx)?)),
x => Ok(AddrAttrProperty::Unparsed(x, d.decode_with(ctx)?)),
1 => Ok(AddrAttrProperty::DerivationPath(d.decode_with(ctx)?)),
2 => Ok(AddrAttrProperty::NetworkTag(d.decode_with(ctx)?)),
_ => Err(minicbor::decode::Error::message(
"unknown tag for address attribute",
)),
}
}
}
@ -125,19 +128,19 @@ impl<C> minicbor::Encode<C> for AddrAttrProperty {
) -> Result<(), minicbor::encode::Error<W::Error>> {
match self {
AddrAttrProperty::AddrDistr(x) => {
e.u32(0)?;
e.u8(0)?;
e.encode(x)?;
Ok(())
}
AddrAttrProperty::Bytes(x) => {
e.u32(1)?;
AddrAttrProperty::DerivationPath(x) => {
e.u8(1)?;
e.encode(x)?;
Ok(())
}
AddrAttrProperty::Unparsed(a, b) => {
e.encode(a)?;
AddrAttrProperty::NetworkTag(b) => {
e.u8(2)?;
e.encode(b)?;
Ok(())
@ -146,7 +149,7 @@ impl<C> minicbor::Encode<C> for AddrAttrProperty {
}
}
pub type AddrAttr = OrderPreservingProperties<AddrAttrProperty>;
pub type AddrAttrs = OrderPreservingProperties<AddrAttrProperty>;
#[derive(Debug, Encode, Decode, Clone, PartialEq, Eq, PartialOrd)]
pub struct AddressPayload {
@ -154,7 +157,7 @@ pub struct AddressPayload {
pub root: AddressId,
#[n(1)]
pub attributes: AddrAttr,
pub attributes: AddrAttrs,
#[n(2)]
pub addrtype: AddrType,
@ -167,19 +170,49 @@ pub struct ByronAddress {
payload: TagWrap<ByteVec, 24>,
#[n(1)]
crc: u64,
crc: u32,
}
const CRC: crc::Crc<u32> = crc::Crc::<u32>::new(&crc::CRC_32_ISO_HDLC);
impl ByronAddress {
pub fn new(payload: &[u8], crc: u64) -> Self {
pub fn new(payload: &[u8], crc: u32) -> Self {
Self {
payload: TagWrap(ByteVec::from(Vec::from(payload))),
crc,
}
}
pub fn new_bootstrap(
root: AddressId,
addrtype: AddrType,
network_tag: Option<Vec<u8>>,
) -> Self {
let payload = AddressPayload {
root,
attributes: match network_tag {
Some(x) => vec![
AddrAttrProperty::AddrDistr(AddrDistr::BootstrapEraDistribution),
AddrAttrProperty::NetworkTag(x.into()),
]
.into(),
None => vec![AddrAttrProperty::AddrDistr(
AddrDistr::BootstrapEraDistribution,
)]
.into(),
},
addrtype,
};
let payload = minicbor::to_vec(payload).unwrap();
let c = CRC.checksum(&payload);
ByronAddress::new(&payload, c)
}
pub fn from_bytes(value: &[u8]) -> Result<Self, Error> {
pallas_codec::minicbor::decode(value).map_err(|_| Error::InvalidByronCbor)
pallas_codec::minicbor::decode(value).map_err(Error::InvalidByronCbor)
}
// Tries to decode an address from its hex representation
@ -208,7 +241,7 @@ impl ByronAddress {
}
pub fn decode(&self) -> Result<AddressPayload, Error> {
minicbor::decode(&self.payload.0).map_err(|_| Error::InvalidByronCbor)
minicbor::decode(&self.payload.0).map_err(Error::InvalidByronCbor)
}
}
@ -230,6 +263,10 @@ mod tests {
#[test]
fn payload_matches() {
let addr = ByronAddress::from_base58(TEST_VECTOR).unwrap();
let crc2 = CRC.checksum(addr.payload.as_ref());
assert_eq!(crc2, addr.crc);
let payload = addr.decode().unwrap();
assert_eq!(payload.root.to_string(), ROOT_HASH);
}

View file

@ -41,8 +41,8 @@ pub enum Error {
#[error("invalid operation for address content")]
InvalidForContent,
#[error("invalid CBOR for Byron address")]
InvalidByronCbor,
#[error("invalid CBOR for Byron address {0}")]
InvalidByronCbor(pallas_codec::minicbor::decode::Error),
#[error("unkown hrp for network {0:08b}")]
UnknownNetworkHrp(u8),
@ -377,7 +377,7 @@ parse_shelley_fn!(parse_type_7, script_hash);
// type 8 (1000) are Byron addresses
fn parse_type_8(header: u8, payload: &[u8]) -> Result<Address, Error> {
let vec = [&[header], payload].concat();
let inner = pallas_codec::minicbor::decode(&vec).map_err(|_| Error::InvalidByronCbor)?;
let inner = pallas_codec::minicbor::decode(&vec).map_err(Error::InvalidByronCbor)?;
Ok(Address::Byron(inner))
}

View file

@ -254,6 +254,12 @@ impl<P> Deref for OrderPreservingProperties<P> {
}
}
impl<P> From<Vec<P>> for OrderPreservingProperties<P> {
fn from(value: Vec<P>) -> Self {
OrderPreservingProperties(value)
}
}
impl<'b, C, P> minicbor::decode::Decode<'b, C> for OrderPreservingProperties<P>
where
P: Decode<'b, C>,

View file

@ -58,7 +58,7 @@ pub struct Address {
pub payload: TagWrap<ByteVec, 24>,
#[n(1)]
pub crc: u64,
pub crc: u32,
}
// Transactions