feat: add helper to create bootstrap addresses (#269)
This commit is contained in:
parent
97adb181b1
commit
5a3246eb3c
5 changed files with 69 additions and 25 deletions
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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>,
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue