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 97adb181b1
commit 5a3246eb3c
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" base58 = "0.2.0"
bech32 = "0.9.1" bech32 = "0.9.1"
thiserror = "1.0.31" 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)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum AddrDistr { pub enum AddrDistr {
Variant0(StakeholderId), SingleKeyDistribution(StakeholderId),
Variant1, BootstrapEraDistribution,
} }
impl<'b, C> minicbor::Decode<'b, C> for AddrDistr { 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()?; let variant = d.u32()?;
match variant { match variant {
0 => Ok(AddrDistr::Variant0(d.decode_with(ctx)?)), 0 => Ok(AddrDistr::SingleKeyDistribution(d.decode_with(ctx)?)),
1 => Ok(AddrDistr::Variant1), 1 => Ok(AddrDistr::BootstrapEraDistribution),
_ => Err(minicbor::decode::Error::message( _ => Err(minicbor::decode::Error::message(
"invalid variant for addrdstr", "invalid variant for addrdstr",
)), )),
@ -40,14 +40,14 @@ impl minicbor::Encode<()> for AddrDistr {
_ctx: &mut (), _ctx: &mut (),
) -> Result<(), minicbor::encode::Error<W::Error>> { ) -> Result<(), minicbor::encode::Error<W::Error>> {
match self { match self {
AddrDistr::Variant0(x) => { AddrDistr::SingleKeyDistribution(x) => {
e.array(2)?; e.array(2)?;
e.u32(0)?; e.u32(0)?;
e.encode(x)?; e.encode(x)?;
Ok(()) Ok(())
} }
AddrDistr::Variant1 => { AddrDistr::BootstrapEraDistribution => {
e.array(1)?; e.array(1)?;
e.u32(1)?; e.u32(1)?;
@ -101,8 +101,8 @@ impl<C> minicbor::Encode<C> for AddrType {
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum AddrAttrProperty { pub enum AddrAttrProperty {
AddrDistr(AddrDistr), AddrDistr(AddrDistr),
Bytes(ByteVec), DerivationPath(ByteVec),
Unparsed(u8, ByteVec), NetworkTag(ByteVec),
} }
impl<'b, C> minicbor::Decode<'b, C> for AddrAttrProperty { impl<'b, C> minicbor::Decode<'b, C> for AddrAttrProperty {
@ -111,8 +111,11 @@ impl<'b, C> minicbor::Decode<'b, C> for AddrAttrProperty {
match key { match key {
0 => Ok(AddrAttrProperty::AddrDistr(d.decode_with(ctx)?)), 0 => Ok(AddrAttrProperty::AddrDistr(d.decode_with(ctx)?)),
1 => Ok(AddrAttrProperty::Bytes(d.decode_with(ctx)?)), 1 => Ok(AddrAttrProperty::DerivationPath(d.decode_with(ctx)?)),
x => Ok(AddrAttrProperty::Unparsed(x, 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>> { ) -> Result<(), minicbor::encode::Error<W::Error>> {
match self { match self {
AddrAttrProperty::AddrDistr(x) => { AddrAttrProperty::AddrDistr(x) => {
e.u32(0)?; e.u8(0)?;
e.encode(x)?; e.encode(x)?;
Ok(()) Ok(())
} }
AddrAttrProperty::Bytes(x) => { AddrAttrProperty::DerivationPath(x) => {
e.u32(1)?; e.u8(1)?;
e.encode(x)?; e.encode(x)?;
Ok(()) Ok(())
} }
AddrAttrProperty::Unparsed(a, b) => { AddrAttrProperty::NetworkTag(b) => {
e.encode(a)?; e.u8(2)?;
e.encode(b)?; e.encode(b)?;
Ok(()) 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)] #[derive(Debug, Encode, Decode, Clone, PartialEq, Eq, PartialOrd)]
pub struct AddressPayload { pub struct AddressPayload {
@ -154,7 +157,7 @@ pub struct AddressPayload {
pub root: AddressId, pub root: AddressId,
#[n(1)] #[n(1)]
pub attributes: AddrAttr, pub attributes: AddrAttrs,
#[n(2)] #[n(2)]
pub addrtype: AddrType, pub addrtype: AddrType,
@ -167,19 +170,49 @@ pub struct ByronAddress {
payload: TagWrap<ByteVec, 24>, payload: TagWrap<ByteVec, 24>,
#[n(1)] #[n(1)]
crc: u64, crc: u32,
} }
const CRC: crc::Crc<u32> = crc::Crc::<u32>::new(&crc::CRC_32_ISO_HDLC);
impl ByronAddress { impl ByronAddress {
pub fn new(payload: &[u8], crc: u64) -> Self { pub fn new(payload: &[u8], crc: u32) -> Self {
Self { Self {
payload: TagWrap(ByteVec::from(Vec::from(payload))), payload: TagWrap(ByteVec::from(Vec::from(payload))),
crc, 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> { 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 // Tries to decode an address from its hex representation
@ -208,7 +241,7 @@ impl ByronAddress {
} }
pub fn decode(&self) -> Result<AddressPayload, Error> { 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] #[test]
fn payload_matches() { fn payload_matches() {
let addr = ByronAddress::from_base58(TEST_VECTOR).unwrap(); 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(); let payload = addr.decode().unwrap();
assert_eq!(payload.root.to_string(), ROOT_HASH); assert_eq!(payload.root.to_string(), ROOT_HASH);
} }

View file

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

View file

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