feat: Introduce Byron library (#39)
Co-authored-by: rvcas <x@rvcas.dev>
This commit is contained in:
parent
0872dcc6fa
commit
de41bd8ad6
15 changed files with 1381 additions and 0 deletions
|
|
@ -10,6 +10,7 @@ members = [
|
||||||
"pallas-localstate",
|
"pallas-localstate",
|
||||||
"pallas-crypto",
|
"pallas-crypto",
|
||||||
"pallas-alonzo",
|
"pallas-alonzo",
|
||||||
|
"pallas-byron",
|
||||||
"pallas",
|
"pallas",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
||||||
4
examples/byron-decoder/.gitignore
vendored
Normal file
4
examples/byron-decoder/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
/target
|
||||||
|
|
||||||
|
scratchpad
|
||||||
|
.DS_Store
|
||||||
14
examples/byron-decoder/Cargo.toml
Normal file
14
examples/byron-decoder/Cargo.toml
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
[package]
|
||||||
|
name = "byron-decoder"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
pallas = { path = "../../pallas" }
|
||||||
|
net2 = "0.2.37"
|
||||||
|
env_logger = "0.9.0"
|
||||||
|
hex = "0.4.3"
|
||||||
|
|
||||||
|
[workspace]
|
||||||
60
examples/byron-decoder/src/main.rs
Normal file
60
examples/byron-decoder/src/main.rs
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
use net2::TcpStreamExt;
|
||||||
|
|
||||||
|
use pallas::ledger::byron::*;
|
||||||
|
use pallas::ouroboros::network::blockfetch::{BatchClient, Observer};
|
||||||
|
use pallas::ouroboros::network::handshake::{
|
||||||
|
n2n::{Client, VersionTable},
|
||||||
|
MAINNET_MAGIC,
|
||||||
|
};
|
||||||
|
use pallas::ouroboros::network::machines::primitives::Point;
|
||||||
|
use pallas::ouroboros::network::machines::run_agent;
|
||||||
|
use pallas::ouroboros::network::multiplexer::Multiplexer;
|
||||||
|
use std::net::TcpStream;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct BlockPrinter;
|
||||||
|
|
||||||
|
impl Observer for BlockPrinter {
|
||||||
|
fn on_block_received(&self, body: Vec<u8>) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
println!("{}", hex::encode(&body));
|
||||||
|
println!("----------");
|
||||||
|
|
||||||
|
let block = Block::decode_fragment(body.as_slice()).unwrap();
|
||||||
|
println!("{:?}", block);
|
||||||
|
println!("===========\n\n");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
env_logger::init();
|
||||||
|
|
||||||
|
let bearer = TcpStream::connect("relays-new.cardano-mainnet.iohk.io:3001").unwrap();
|
||||||
|
bearer.set_nodelay(true).unwrap();
|
||||||
|
bearer.set_keepalive_ms(Some(30_000u32)).unwrap();
|
||||||
|
|
||||||
|
let mut muxer = Multiplexer::setup(bearer, &vec![0, 3]).unwrap();
|
||||||
|
|
||||||
|
let mut hs_channel = muxer.use_channel(0);
|
||||||
|
let versions = VersionTable::v4_and_above(MAINNET_MAGIC);
|
||||||
|
let last = run_agent(Client::initial(versions), &mut hs_channel).unwrap();
|
||||||
|
|
||||||
|
let range = (
|
||||||
|
Point(
|
||||||
|
3240000,
|
||||||
|
hex::decode("b7096a881f77ced24bdd285758646c0e059545b54855bd3a2307ece518bd6317")
|
||||||
|
.unwrap(),
|
||||||
|
),
|
||||||
|
Point(
|
||||||
|
4492794,
|
||||||
|
hex::decode("5c196e7394ace0449ba5a51c919369699b13896e97432894b4f0354dce8670b6")
|
||||||
|
.unwrap(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut bf_channel = muxer.use_channel(3);
|
||||||
|
let bf = BatchClient::initial(range, BlockPrinter {});
|
||||||
|
let bf_last = run_agent(bf, &mut bf_channel);
|
||||||
|
println!("{:?}", bf_last);
|
||||||
|
}
|
||||||
22
pallas-byron/Cargo.toml
Normal file
22
pallas-byron/Cargo.toml
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
[package]
|
||||||
|
name = "pallas-byron"
|
||||||
|
description = "Ledger primitives and cbor codec for the Byron era"
|
||||||
|
version = "0.4.0"
|
||||||
|
edition = "2021"
|
||||||
|
repository = "https://github.com/txpipe/pallas"
|
||||||
|
homepage = "https://github.com/txpipe/pallas"
|
||||||
|
documentation = "https://docs.rs/pallas-byron"
|
||||||
|
license = "Apache-2.0"
|
||||||
|
readme = "README.md"
|
||||||
|
authors = [
|
||||||
|
"Santiago Carmuega <santiago@carmuega.me>",
|
||||||
|
"Lucas Rosa <x@rvcas.dev>",
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
minicbor = { version = "0.13", features = ["std"] }
|
||||||
|
minicbor-derive = "0.8.0"
|
||||||
|
hex = "0.4.3"
|
||||||
|
log = "0.4.14"
|
||||||
|
pallas-crypto = { version = "0.4.0", path = "../pallas-crypto" }
|
||||||
2
pallas-byron/README.md
Normal file
2
pallas-byron/README.md
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
# Pallas Byron
|
||||||
|
|
||||||
22
pallas-byron/src/framework.rs
Normal file
22
pallas-byron/src/framework.rs
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
pub type Error = Box<dyn std::error::Error>;
|
||||||
|
|
||||||
|
pub trait Fragment<'a>
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
fn encode_fragment(&self) -> Result<Vec<u8>, Error>;
|
||||||
|
fn decode_fragment(bytes: &'a [u8]) -> Result<Self, Error>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> Fragment<'a> for T
|
||||||
|
where
|
||||||
|
T: minicbor::Encode + minicbor::Decode<'a> + Sized,
|
||||||
|
{
|
||||||
|
fn encode_fragment(&self) -> Result<Vec<u8>, Error> {
|
||||||
|
minicbor::to_vec(self).map_err(|e| e.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decode_fragment(bytes: &'a [u8]) -> Result<Self, Error> {
|
||||||
|
minicbor::decode(bytes).map_err(|e| e.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
10
pallas-byron/src/lib.rs
Normal file
10
pallas-byron/src/lib.rs
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
//! Ledger primitives and cbor codec for the Byron era
|
||||||
|
|
||||||
|
mod framework;
|
||||||
|
mod model;
|
||||||
|
mod utils;
|
||||||
|
|
||||||
|
pub use framework::*;
|
||||||
|
pub use model::*;
|
||||||
|
|
||||||
|
// pub mod crypto;
|
||||||
954
pallas-byron/src/model.rs
Normal file
954
pallas-byron/src/model.rs
Normal file
|
|
@ -0,0 +1,954 @@
|
||||||
|
//! Ledger primitives and cbor codec for the Byron era
|
||||||
|
//!
|
||||||
|
//! Handcrafted, idiomatic rust artifacts based on based on the [Byron CDDL](https://github.com/input-output-hk/cardano-ledger/blob/master/eras/byron/cddl-spec/byron.cddl) file in IOHK repo.
|
||||||
|
|
||||||
|
use log::warn;
|
||||||
|
use minicbor::bytes::ByteVec;
|
||||||
|
use minicbor_derive::{Decode, Encode};
|
||||||
|
use pallas_crypto::hash::Hash;
|
||||||
|
|
||||||
|
use crate::utils::{
|
||||||
|
CborWrap, EmptyMap, KeyValuePairs, MaybeIndefArray, OrderPreservingProperties, TagWrap,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, PartialOrd, Eq, Ord)]
|
||||||
|
pub struct SkipCbor<const N: usize> {}
|
||||||
|
|
||||||
|
impl<'b, const N: usize> minicbor::Decode<'b> for SkipCbor<N> {
|
||||||
|
fn decode(d: &mut minicbor::Decoder<'b>) -> Result<Self, minicbor::decode::Error> {
|
||||||
|
{
|
||||||
|
let probe = d.probe();
|
||||||
|
warn!("skipped cbor value {}: {:?}", N, probe.datatype()?);
|
||||||
|
println!("skipped cbor value {}: {:?}", N, probe.datatype()?);
|
||||||
|
}
|
||||||
|
|
||||||
|
d.skip()?;
|
||||||
|
Ok(SkipCbor {})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const N: usize> minicbor::Encode for SkipCbor<N> {
|
||||||
|
fn encode<W: minicbor::encode::Write>(
|
||||||
|
&self,
|
||||||
|
_e: &mut minicbor::Encoder<W>,
|
||||||
|
) -> Result<(), minicbor::encode::Error<W::Error>> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Basic Cardano Types
|
||||||
|
|
||||||
|
pub type Blake2b256 = Hash<32>;
|
||||||
|
|
||||||
|
pub type TxId = Blake2b256;
|
||||||
|
pub type BlockId = Blake2b256;
|
||||||
|
pub type UpdId = Blake2b256;
|
||||||
|
pub type ByronHash = Blake2b256;
|
||||||
|
|
||||||
|
pub type Blake2b224 = Hash<28>;
|
||||||
|
|
||||||
|
pub type AddressId = Blake2b224;
|
||||||
|
pub type StakeholderId = Blake2b224;
|
||||||
|
|
||||||
|
pub type EpochId = u64;
|
||||||
|
|
||||||
|
#[derive(Encode, Decode, Debug)]
|
||||||
|
pub struct SlotId {
|
||||||
|
#[n(0)]
|
||||||
|
epoch: EpochId,
|
||||||
|
|
||||||
|
#[n(1)]
|
||||||
|
slot: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type PubKey = ByteVec;
|
||||||
|
pub type Signature = ByteVec;
|
||||||
|
|
||||||
|
// Attributes
|
||||||
|
|
||||||
|
// quote from the CDDL file: at the moment we do not bother deserialising these,
|
||||||
|
// since they don't contain anything
|
||||||
|
|
||||||
|
// attributes = {* any => any}
|
||||||
|
pub type Attributes = EmptyMap;
|
||||||
|
|
||||||
|
// Addresses
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum AddrDistr {
|
||||||
|
Variant0(StakeholderId),
|
||||||
|
Variant1,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'b> minicbor::Decode<'b> for AddrDistr {
|
||||||
|
fn decode(d: &mut minicbor::Decoder<'b>) -> Result<Self, minicbor::decode::Error> {
|
||||||
|
d.array()?;
|
||||||
|
let variant = d.u32()?;
|
||||||
|
|
||||||
|
match variant {
|
||||||
|
0 => Ok(AddrDistr::Variant0(d.decode()?)),
|
||||||
|
1 => Ok(AddrDistr::Variant1),
|
||||||
|
_ => Err(minicbor::decode::Error::Message(
|
||||||
|
"invalid variant for addrdstr",
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl minicbor::Encode for AddrDistr {
|
||||||
|
fn encode<W: minicbor::encode::Write>(
|
||||||
|
&self,
|
||||||
|
e: &mut minicbor::Encoder<W>,
|
||||||
|
) -> Result<(), minicbor::encode::Error<W::Error>> {
|
||||||
|
match self {
|
||||||
|
AddrDistr::Variant0(x) => {
|
||||||
|
e.array(2)?;
|
||||||
|
e.u32(0)?;
|
||||||
|
e.encode(x)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
AddrDistr::Variant1 => {
|
||||||
|
e.array(1)?;
|
||||||
|
e.u32(1)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum AddrType {
|
||||||
|
PubKey,
|
||||||
|
Script,
|
||||||
|
Redeem,
|
||||||
|
Other(u64),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'b> minicbor::Decode<'b> for AddrType {
|
||||||
|
fn decode(d: &mut minicbor::Decoder<'b>) -> Result<Self, minicbor::decode::Error> {
|
||||||
|
let variant = d.u64()?;
|
||||||
|
|
||||||
|
match variant {
|
||||||
|
0 => Ok(AddrType::PubKey),
|
||||||
|
1 => Ok(AddrType::Script),
|
||||||
|
2 => Ok(AddrType::Redeem),
|
||||||
|
x => Ok(AddrType::Other(x)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl minicbor::Encode for AddrType {
|
||||||
|
fn encode<W: minicbor::encode::Write>(
|
||||||
|
&self,
|
||||||
|
e: &mut minicbor::Encoder<W>,
|
||||||
|
) -> Result<(), minicbor::encode::Error<W::Error>> {
|
||||||
|
match self {
|
||||||
|
AddrType::PubKey => e.u64(0)?,
|
||||||
|
AddrType::Script => e.u64(1)?,
|
||||||
|
AddrType::Redeem => e.u64(2)?,
|
||||||
|
AddrType::Other(x) => e.u64(*x)?,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum AddrAttrProperty {
|
||||||
|
AddrDistr(AddrDistr),
|
||||||
|
Bytes(ByteVec),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'b> minicbor::Decode<'b> for AddrAttrProperty {
|
||||||
|
fn decode(d: &mut minicbor::Decoder<'b>) -> Result<Self, minicbor::decode::Error> {
|
||||||
|
let key = d.u8()?;
|
||||||
|
|
||||||
|
match key {
|
||||||
|
0 => Ok(AddrAttrProperty::AddrDistr(d.decode()?)),
|
||||||
|
1 => Ok(AddrAttrProperty::Bytes(d.decode()?)),
|
||||||
|
_ => Err(minicbor::decode::Error::Message(
|
||||||
|
"unknown variant for addrattr property",
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl minicbor::Encode for AddrAttrProperty {
|
||||||
|
fn encode<W: minicbor::encode::Write>(
|
||||||
|
&self,
|
||||||
|
e: &mut minicbor::Encoder<W>,
|
||||||
|
) -> Result<(), minicbor::encode::Error<W::Error>> {
|
||||||
|
match self {
|
||||||
|
AddrAttrProperty::AddrDistr(x) => {
|
||||||
|
e.u32(0)?;
|
||||||
|
e.encode(x)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
AddrAttrProperty::Bytes(x) => {
|
||||||
|
e.u32(1)?;
|
||||||
|
e.encode(x)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type AddrAttr = OrderPreservingProperties<AddrAttrProperty>;
|
||||||
|
|
||||||
|
// address = [ #6.24(bytes .cbor ([addressid, addrattr, addrtype])), u64 ]
|
||||||
|
pub type Address = (CborWrap<(AddressId, AddrAttr, AddrType)>, u64);
|
||||||
|
|
||||||
|
// Transactions
|
||||||
|
|
||||||
|
// txout = [address, u64]
|
||||||
|
pub type TxOut = (Address, u64);
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum TxIn {
|
||||||
|
// [0, #6.24(bytes .cbor ([txid, u32]))]
|
||||||
|
Variant0(CborWrap<(TxId, u32)>),
|
||||||
|
|
||||||
|
// [u8 .ne 0, encoded-cbor]
|
||||||
|
Other(u8, ByteVec),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'b> minicbor::Decode<'b> for TxIn {
|
||||||
|
fn decode(d: &mut minicbor::Decoder<'b>) -> Result<Self, minicbor::decode::Error> {
|
||||||
|
d.array()?;
|
||||||
|
|
||||||
|
let variant = d.u8()?;
|
||||||
|
|
||||||
|
match variant {
|
||||||
|
0 => Ok(TxIn::Variant0(d.decode()?)),
|
||||||
|
x => Ok(TxIn::Other(x, d.decode()?)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl minicbor::Encode for TxIn {
|
||||||
|
fn encode<W: minicbor::encode::Write>(
|
||||||
|
&self,
|
||||||
|
e: &mut minicbor::Encoder<W>,
|
||||||
|
) -> Result<(), minicbor::encode::Error<W::Error>> {
|
||||||
|
match self {
|
||||||
|
TxIn::Variant0(x) => {
|
||||||
|
e.array(2)?;
|
||||||
|
e.u8(0)?;
|
||||||
|
e.encode(x)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
TxIn::Other(a, b) => {
|
||||||
|
e.array(2)?;
|
||||||
|
e.u8(*a)?;
|
||||||
|
e.encode(b)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// tx = [[+ txin], [+ txout], attributes]
|
||||||
|
pub type Tx = (Vec<TxIn>, Vec<TxOut>, Attributes);
|
||||||
|
|
||||||
|
// txproof = [u32, hash, hash]
|
||||||
|
pub type TxProof = (u32, ByronHash, ByronHash);
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Twit {
|
||||||
|
// [0, #6.24(bytes .cbor ([pubkey, signature]))]
|
||||||
|
Variant0(CborWrap<(PubKey, Signature)>),
|
||||||
|
|
||||||
|
// [1, #6.24(bytes .cbor ([[u16, bytes], [u16, bytes]]))]
|
||||||
|
Variant1(CborWrap<((u16, ByteVec), (u16, ByteVec))>),
|
||||||
|
|
||||||
|
// [2, #6.24(bytes .cbor ([pubkey, signature]))]
|
||||||
|
Variant2(CborWrap<(PubKey, Signature)>),
|
||||||
|
|
||||||
|
// [u8 .gt 2, encoded-cbor]
|
||||||
|
Other(u8, ByteVec),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'b> minicbor::Decode<'b> for Twit {
|
||||||
|
fn decode(d: &mut minicbor::Decoder<'b>) -> Result<Self, minicbor::decode::Error> {
|
||||||
|
d.array()?;
|
||||||
|
|
||||||
|
let variant = d.u8()?;
|
||||||
|
|
||||||
|
match variant {
|
||||||
|
0 => Ok(Twit::Variant0(d.decode()?)),
|
||||||
|
1 => Ok(Twit::Variant1(d.decode()?)),
|
||||||
|
2 => Ok(Twit::Variant2(d.decode()?)),
|
||||||
|
x => Ok(Twit::Other(x, d.decode()?)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl minicbor::Encode for Twit {
|
||||||
|
fn encode<W: minicbor::encode::Write>(
|
||||||
|
&self,
|
||||||
|
e: &mut minicbor::Encoder<W>,
|
||||||
|
) -> Result<(), minicbor::encode::Error<W::Error>> {
|
||||||
|
match self {
|
||||||
|
Twit::Variant0(x) => {
|
||||||
|
e.array(2)?;
|
||||||
|
e.u8(0)?;
|
||||||
|
e.encode(x)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Twit::Variant1(x) => {
|
||||||
|
e.array(2)?;
|
||||||
|
e.u8(1)?;
|
||||||
|
e.encode(x)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Twit::Variant2(x) => {
|
||||||
|
e.array(2)?;
|
||||||
|
e.u8(2)?;
|
||||||
|
e.encode(x)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Twit::Other(a, b) => {
|
||||||
|
e.array(2)?;
|
||||||
|
e.u8(*a)?;
|
||||||
|
e.encode(b)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shared Seed Computation
|
||||||
|
|
||||||
|
// cddl note:
|
||||||
|
// This is encoded using the 'Binary' instance
|
||||||
|
// for Scrape.PublicKey
|
||||||
|
pub type VssPubKey = ByteVec;
|
||||||
|
|
||||||
|
// cddl note:
|
||||||
|
// This is encoded using the 'Binary' instance
|
||||||
|
// for Scrape.Secret.
|
||||||
|
pub type VssSec = ByteVec;
|
||||||
|
|
||||||
|
// cddl note:
|
||||||
|
// This is encoded using the 'Binary' instance
|
||||||
|
// for Scrape.EncryptedSi.
|
||||||
|
// TODO work out why this seems to be in a length 1 array
|
||||||
|
pub type VssEnc = MaybeIndefArray<ByteVec>;
|
||||||
|
|
||||||
|
// cddl note:
|
||||||
|
// This is encoded using the 'Binary' instance
|
||||||
|
// for Scrape.DecryptedShare
|
||||||
|
pub type VssDec = ByteVec;
|
||||||
|
|
||||||
|
// cddl note:
|
||||||
|
// This is encoded using the
|
||||||
|
// 'Binary' instance for Scrape.Proof
|
||||||
|
pub type VssProof = (ByteVec, ByteVec, ByteVec, Vec<ByteVec>);
|
||||||
|
|
||||||
|
//ssccomm = [pubkey, [{vsspubkey => vssenc},vssproof], signature]
|
||||||
|
pub type SscComm = (
|
||||||
|
PubKey,
|
||||||
|
(KeyValuePairs<VssPubKey, VssEnc>, VssProof),
|
||||||
|
Signature,
|
||||||
|
);
|
||||||
|
|
||||||
|
//ssccomms = #6.258([* ssccomm])
|
||||||
|
pub type SscComms = TagWrap<MaybeIndefArray<SscComm>, 258>;
|
||||||
|
|
||||||
|
// sscopens = {stakeholderid => vsssec}
|
||||||
|
pub type SscOpens = KeyValuePairs<StakeholderId, VssSec>;
|
||||||
|
|
||||||
|
// sscshares = {addressid => [addressid, [* vssdec]]}
|
||||||
|
pub type SscShares = KeyValuePairs<AddressId, (AddressId, MaybeIndefArray<VssDec>)>;
|
||||||
|
|
||||||
|
// CDDL says: ssccert = [vsspubkey, pubkey, epochid, signature]
|
||||||
|
// this is what seems to work: ssccert = [vsspubkey, epochid, pubkey, signature]
|
||||||
|
pub type SscCert = (VssPubKey, EpochId, PubKey, Signature);
|
||||||
|
|
||||||
|
// ssccerts = #6.258([* ssccert])
|
||||||
|
pub type SscCerts = TagWrap<MaybeIndefArray<SscCert>, 258>;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Ssc {
|
||||||
|
Variant0(SscComms, SscCerts),
|
||||||
|
Variant1(SscOpens, SscCerts),
|
||||||
|
Variant2(SscShares, SscCerts),
|
||||||
|
Variant3(SscCerts),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'b> minicbor::Decode<'b> for Ssc {
|
||||||
|
fn decode(d: &mut minicbor::Decoder<'b>) -> Result<Self, minicbor::decode::Error> {
|
||||||
|
d.array()?;
|
||||||
|
|
||||||
|
let variant = d.u8()?;
|
||||||
|
|
||||||
|
match variant {
|
||||||
|
0 => Ok(Ssc::Variant0(d.decode()?, d.decode()?)),
|
||||||
|
1 => Ok(Ssc::Variant1(d.decode()?, d.decode()?)),
|
||||||
|
2 => Ok(Ssc::Variant2(d.decode()?, d.decode()?)),
|
||||||
|
3 => Ok(Ssc::Variant3(d.decode()?)),
|
||||||
|
_ => Err(minicbor::decode::Error::Message("invalid variant for ssc")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl minicbor::Encode for Ssc {
|
||||||
|
fn encode<W: minicbor::encode::Write>(
|
||||||
|
&self,
|
||||||
|
e: &mut minicbor::Encoder<W>,
|
||||||
|
) -> Result<(), minicbor::encode::Error<W::Error>> {
|
||||||
|
match self {
|
||||||
|
Ssc::Variant0(a, b) => {
|
||||||
|
e.array(3)?;
|
||||||
|
e.u8(0)?;
|
||||||
|
e.encode(a)?;
|
||||||
|
e.encode(b)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Ssc::Variant1(a, b) => {
|
||||||
|
e.array(3)?;
|
||||||
|
e.u8(1)?;
|
||||||
|
e.encode(a)?;
|
||||||
|
e.encode(b)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Ssc::Variant2(a, b) => {
|
||||||
|
e.array(3)?;
|
||||||
|
e.u8(2)?;
|
||||||
|
e.encode(a)?;
|
||||||
|
e.encode(b)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Ssc::Variant3(x) => {
|
||||||
|
e.array(2)?;
|
||||||
|
e.u8(3)?;
|
||||||
|
e.encode(x)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum SscProof {
|
||||||
|
Variant0(ByronHash, ByronHash),
|
||||||
|
Variant1(ByronHash, ByronHash),
|
||||||
|
Variant2(ByronHash, ByronHash),
|
||||||
|
Variant3(ByronHash),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'b> minicbor::Decode<'b> for SscProof {
|
||||||
|
fn decode(d: &mut minicbor::Decoder<'b>) -> Result<Self, minicbor::decode::Error> {
|
||||||
|
d.array()?;
|
||||||
|
|
||||||
|
let variant = d.u8()?;
|
||||||
|
|
||||||
|
match variant {
|
||||||
|
0 => Ok(SscProof::Variant0(d.decode()?, d.decode()?)),
|
||||||
|
1 => Ok(SscProof::Variant1(d.decode()?, d.decode()?)),
|
||||||
|
2 => Ok(SscProof::Variant2(d.decode()?, d.decode()?)),
|
||||||
|
3 => Ok(SscProof::Variant3(d.decode()?)),
|
||||||
|
_ => Err(minicbor::decode::Error::Message(
|
||||||
|
"invalid variant for sscproof",
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl minicbor::Encode for SscProof {
|
||||||
|
fn encode<W: minicbor::encode::Write>(
|
||||||
|
&self,
|
||||||
|
e: &mut minicbor::Encoder<W>,
|
||||||
|
) -> Result<(), minicbor::encode::Error<W::Error>> {
|
||||||
|
match self {
|
||||||
|
SscProof::Variant0(a, b) => {
|
||||||
|
e.array(3)?;
|
||||||
|
e.u8(0)?;
|
||||||
|
e.encode(a)?;
|
||||||
|
e.encode(b)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
SscProof::Variant1(a, b) => {
|
||||||
|
e.array(3)?;
|
||||||
|
e.u8(1)?;
|
||||||
|
e.encode(a)?;
|
||||||
|
e.encode(b)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
SscProof::Variant2(a, b) => {
|
||||||
|
e.array(3)?;
|
||||||
|
e.u8(2)?;
|
||||||
|
e.encode(a)?;
|
||||||
|
e.encode(b)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
SscProof::Variant3(x) => {
|
||||||
|
e.array(2)?;
|
||||||
|
e.u8(3)?;
|
||||||
|
e.encode(x)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delegation
|
||||||
|
|
||||||
|
#[derive(Debug, Encode, Decode)]
|
||||||
|
pub struct Dlg {
|
||||||
|
#[n(0)]
|
||||||
|
epoch: EpochId,
|
||||||
|
|
||||||
|
#[n(1)]
|
||||||
|
issuer: PubKey,
|
||||||
|
|
||||||
|
#[n(2)]
|
||||||
|
delegate: PubKey,
|
||||||
|
|
||||||
|
#[n(3)]
|
||||||
|
certificate: Signature,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type DlgSig = (Dlg, Signature);
|
||||||
|
|
||||||
|
#[derive(Debug, Encode, Decode)]
|
||||||
|
pub struct Lwdlg {
|
||||||
|
#[n(0)]
|
||||||
|
epoch_range: (EpochId, EpochId),
|
||||||
|
|
||||||
|
#[n(1)]
|
||||||
|
issuer: PubKey,
|
||||||
|
|
||||||
|
#[n(2)]
|
||||||
|
delegate: PubKey,
|
||||||
|
|
||||||
|
#[n(3)]
|
||||||
|
certificate: Signature,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type LwdlgSig = (Lwdlg, Signature);
|
||||||
|
|
||||||
|
// Updates
|
||||||
|
|
||||||
|
pub type BVer = (u16, u16, u8);
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum TxFeePol {
|
||||||
|
//[0, #6.24(bytes .cbor ([bigint, bigint]))]
|
||||||
|
Variant0(CborWrap<(i64, i64)>),
|
||||||
|
|
||||||
|
// [u8 .gt 0, encoded-cbor]
|
||||||
|
Other(u8, ByteVec),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'b> minicbor::Decode<'b> for TxFeePol {
|
||||||
|
fn decode(d: &mut minicbor::Decoder<'b>) -> Result<Self, minicbor::decode::Error> {
|
||||||
|
d.array()?;
|
||||||
|
|
||||||
|
let variant = d.u8()?;
|
||||||
|
|
||||||
|
match variant {
|
||||||
|
0 => Ok(TxFeePol::Variant0(d.decode()?)),
|
||||||
|
x => Ok(TxFeePol::Other(x, d.decode()?)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl minicbor::Encode for TxFeePol {
|
||||||
|
fn encode<W: minicbor::encode::Write>(
|
||||||
|
&self,
|
||||||
|
e: &mut minicbor::Encoder<W>,
|
||||||
|
) -> Result<(), minicbor::encode::Error<W::Error>> {
|
||||||
|
match self {
|
||||||
|
TxFeePol::Variant0(x) => {
|
||||||
|
e.array(2)?;
|
||||||
|
e.u8(0)?;
|
||||||
|
e.encode(x)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
TxFeePol::Other(a, b) => {
|
||||||
|
e.array(2)?;
|
||||||
|
e.u8(*a)?;
|
||||||
|
e.encode(b)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Encode, Decode)]
|
||||||
|
pub struct BVerMod {
|
||||||
|
#[n(0)]
|
||||||
|
script_version: (Option<u16>,),
|
||||||
|
|
||||||
|
#[n(1)]
|
||||||
|
slot_duration: (Option<u64>,),
|
||||||
|
|
||||||
|
#[n(2)]
|
||||||
|
max_block_size: (Option<u64>,),
|
||||||
|
|
||||||
|
#[n(3)]
|
||||||
|
max_header_size: (Option<u64>,),
|
||||||
|
|
||||||
|
#[n(4)]
|
||||||
|
max_tx_size: (Option<u64>,),
|
||||||
|
|
||||||
|
#[n(5)]
|
||||||
|
max_proposal_size: (Option<u64>,),
|
||||||
|
|
||||||
|
#[n(6)]
|
||||||
|
mpc_thd: (Option<u64>,),
|
||||||
|
|
||||||
|
#[n(7)]
|
||||||
|
heavy_del_thd: (Option<u64>,),
|
||||||
|
|
||||||
|
#[n(8)]
|
||||||
|
update_vote_thd: (Option<u64>,),
|
||||||
|
|
||||||
|
#[n(9)]
|
||||||
|
update_proposal_thd: (Option<u64>,),
|
||||||
|
|
||||||
|
#[n(10)]
|
||||||
|
update_implicit: (Option<u64>,),
|
||||||
|
|
||||||
|
#[n(11)]
|
||||||
|
soft_fork_rule: (Option<(u64, u64, u64)>,),
|
||||||
|
|
||||||
|
#[n(12)]
|
||||||
|
tx_fee_policy: (Option<TxFeePol>,),
|
||||||
|
|
||||||
|
#[n(13)]
|
||||||
|
unlock_stake_epoch: (Option<EpochId>,),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type UpData = (ByronHash, ByronHash, ByronHash, ByronHash);
|
||||||
|
|
||||||
|
#[derive(Debug, Encode, Decode)]
|
||||||
|
pub struct UpProp {
|
||||||
|
#[n(0)]
|
||||||
|
block_version: Option<BVer>,
|
||||||
|
|
||||||
|
#[n(1)]
|
||||||
|
block_version_mod: Option<BVerMod>,
|
||||||
|
|
||||||
|
#[n(2)]
|
||||||
|
software_version: Option<(String, u32)>,
|
||||||
|
|
||||||
|
#[n(3)]
|
||||||
|
data: Option<TagWrap<(String, UpData), 258>>,
|
||||||
|
|
||||||
|
#[n(4)]
|
||||||
|
attributes: Option<Attributes>,
|
||||||
|
|
||||||
|
#[n(5)]
|
||||||
|
from: Option<PubKey>,
|
||||||
|
|
||||||
|
#[n(6)]
|
||||||
|
signature: Option<Signature>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Encode, Decode)]
|
||||||
|
pub struct UpVote {
|
||||||
|
#[n(0)]
|
||||||
|
voter: PubKey,
|
||||||
|
|
||||||
|
#[n(1)]
|
||||||
|
proposal_id: UpdId,
|
||||||
|
|
||||||
|
#[n(2)]
|
||||||
|
vote: bool,
|
||||||
|
|
||||||
|
#[n(3)]
|
||||||
|
signature: Signature,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Encode, Decode)]
|
||||||
|
pub struct Up {
|
||||||
|
#[n(0)]
|
||||||
|
proposal: Option<UpProp>,
|
||||||
|
|
||||||
|
#[n(1)]
|
||||||
|
votes: MaybeIndefArray<UpVote>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Blocks
|
||||||
|
|
||||||
|
pub type Difficulty = MaybeIndefArray<u64>;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum BlockSig {
|
||||||
|
Signature(Signature),
|
||||||
|
LwdlgSig(LwdlgSig),
|
||||||
|
DlgSig(DlgSig),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'b> minicbor::Decode<'b> for BlockSig {
|
||||||
|
fn decode(d: &mut minicbor::Decoder<'b>) -> Result<Self, minicbor::decode::Error> {
|
||||||
|
d.array()?;
|
||||||
|
|
||||||
|
let variant = d.u8()?;
|
||||||
|
|
||||||
|
match variant {
|
||||||
|
0 => Ok(BlockSig::Signature(d.decode()?)),
|
||||||
|
1 => Ok(BlockSig::LwdlgSig(d.decode()?)),
|
||||||
|
2 => Ok(BlockSig::DlgSig(d.decode()?)),
|
||||||
|
_ => Err(minicbor::decode::Error::Message(
|
||||||
|
"unknown variant for blocksig",
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl minicbor::Encode for BlockSig {
|
||||||
|
fn encode<W: minicbor::encode::Write>(
|
||||||
|
&self,
|
||||||
|
e: &mut minicbor::Encoder<W>,
|
||||||
|
) -> Result<(), minicbor::encode::Error<W::Error>> {
|
||||||
|
match self {
|
||||||
|
BlockSig::Signature(x) => {
|
||||||
|
e.array(2)?;
|
||||||
|
e.u8(0)?;
|
||||||
|
e.encode(x)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
BlockSig::LwdlgSig(x) => {
|
||||||
|
e.array(2)?;
|
||||||
|
e.u8(1)?;
|
||||||
|
e.encode(x)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
BlockSig::DlgSig(x) => {
|
||||||
|
e.array(2)?;
|
||||||
|
e.u8(2)?;
|
||||||
|
e.encode(x)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Encode, Decode, Debug)]
|
||||||
|
pub struct BlockCons(
|
||||||
|
#[n(0)] SlotId,
|
||||||
|
#[n(1)] PubKey,
|
||||||
|
#[n(2)] Difficulty,
|
||||||
|
#[n(3)] BlockSig,
|
||||||
|
);
|
||||||
|
|
||||||
|
#[derive(Encode, Decode, Debug)]
|
||||||
|
pub struct BlockHeadEx {
|
||||||
|
#[n(0)]
|
||||||
|
block_version: BVer,
|
||||||
|
|
||||||
|
#[n(1)]
|
||||||
|
software_version: (String, u32),
|
||||||
|
|
||||||
|
#[n(2)]
|
||||||
|
attributes: Option<Attributes>,
|
||||||
|
|
||||||
|
#[n(3)]
|
||||||
|
extra_proof: ByronHash,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Encode, Decode, Debug)]
|
||||||
|
pub struct BlockProof {
|
||||||
|
#[n(0)]
|
||||||
|
tx_proof: TxProof,
|
||||||
|
|
||||||
|
#[n(1)]
|
||||||
|
ssc_proof: SscProof,
|
||||||
|
|
||||||
|
#[n(2)]
|
||||||
|
dlg_proof: ByronHash,
|
||||||
|
|
||||||
|
#[n(3)]
|
||||||
|
upd_proof: ByronHash,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Encode, Decode, Debug)]
|
||||||
|
pub struct BlockHead {
|
||||||
|
#[n(0)]
|
||||||
|
protocol_magic: u32,
|
||||||
|
|
||||||
|
#[n(1)]
|
||||||
|
prev_block: BlockId,
|
||||||
|
|
||||||
|
#[n(2)]
|
||||||
|
body_proof: BlockProof,
|
||||||
|
|
||||||
|
#[n(3)]
|
||||||
|
consensus_data: BlockCons,
|
||||||
|
|
||||||
|
#[n(4)]
|
||||||
|
extra_data: BlockHeadEx,
|
||||||
|
}
|
||||||
|
|
||||||
|
// [tx, [* twit]]
|
||||||
|
pub type TxPayload = (Tx, Vec<Twit>);
|
||||||
|
|
||||||
|
#[derive(Encode, Decode, Debug)]
|
||||||
|
pub struct BlockBody {
|
||||||
|
#[n(0)]
|
||||||
|
tx_payload: MaybeIndefArray<TxPayload>,
|
||||||
|
|
||||||
|
#[n(1)]
|
||||||
|
ssc_payload: Ssc,
|
||||||
|
|
||||||
|
#[n(2)]
|
||||||
|
dlg_payload: MaybeIndefArray<Dlg>,
|
||||||
|
|
||||||
|
#[n(3)]
|
||||||
|
upd_payload: Up,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Epoch Boundary Blocks
|
||||||
|
|
||||||
|
#[derive(Encode, Decode, Debug)]
|
||||||
|
pub struct EbbCons {
|
||||||
|
#[n(0)]
|
||||||
|
epoch_id: EpochId,
|
||||||
|
|
||||||
|
#[n(1)]
|
||||||
|
difficulty: Difficulty,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Encode, Decode, Debug)]
|
||||||
|
pub struct EbbHead {
|
||||||
|
#[n(0)]
|
||||||
|
protocol_magic: u32,
|
||||||
|
|
||||||
|
#[n(1)]
|
||||||
|
prev_block: BlockId,
|
||||||
|
|
||||||
|
#[n(2)]
|
||||||
|
body_proof: ByronHash,
|
||||||
|
|
||||||
|
#[n(3)]
|
||||||
|
consensus_data: EbbCons,
|
||||||
|
|
||||||
|
#[n(4)]
|
||||||
|
extra_data: (Attributes,),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Encode, Decode, Debug)]
|
||||||
|
pub struct MainBlock {
|
||||||
|
#[n(0)]
|
||||||
|
header: BlockHead,
|
||||||
|
|
||||||
|
#[n(1)]
|
||||||
|
body: BlockBody,
|
||||||
|
|
||||||
|
#[n(2)]
|
||||||
|
extra: MaybeIndefArray<Attributes>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Encode, Decode, Debug)]
|
||||||
|
pub struct EbBlock {
|
||||||
|
#[n(0)]
|
||||||
|
header: EbbHead,
|
||||||
|
|
||||||
|
#[n(1)]
|
||||||
|
body: MaybeIndefArray<StakeholderId>,
|
||||||
|
|
||||||
|
#[n(2)]
|
||||||
|
extra: Option<Attributes>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Block {
|
||||||
|
MainBlock(MainBlock),
|
||||||
|
EbBlock(EbBlock),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'b> minicbor::Decode<'b> for Block {
|
||||||
|
fn decode(d: &mut minicbor::Decoder<'b>) -> Result<Self, minicbor::decode::Error> {
|
||||||
|
d.array()?;
|
||||||
|
|
||||||
|
let variant = d.u32()?;
|
||||||
|
|
||||||
|
match variant {
|
||||||
|
0 => Ok(Block::EbBlock(d.decode()?)),
|
||||||
|
1 => Ok(Block::MainBlock(d.decode()?)),
|
||||||
|
_ => Err(minicbor::decode::Error::Message(
|
||||||
|
"unknown variant for block",
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl minicbor::Encode for Block {
|
||||||
|
fn encode<W: minicbor::encode::Write>(
|
||||||
|
&self,
|
||||||
|
e: &mut minicbor::Encoder<W>,
|
||||||
|
) -> Result<(), minicbor::encode::Error<W::Error>> {
|
||||||
|
match self {
|
||||||
|
Block::EbBlock(x) => {
|
||||||
|
e.array(2)?;
|
||||||
|
e.encode(0)?;
|
||||||
|
e.encode(x)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Block::MainBlock(x) => {
|
||||||
|
e.array(2)?;
|
||||||
|
e.encode(1)?;
|
||||||
|
e.encode(x)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::{Block, Fragment};
|
||||||
|
use minicbor::{self, to_vec};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn block_isomorphic_decoding_encoding() {
|
||||||
|
let test_blocks = vec![
|
||||||
|
include_str!("test_data/test1.block"),
|
||||||
|
include_str!("test_data/test2.block"),
|
||||||
|
include_str!("test_data/test3.block"),
|
||||||
|
];
|
||||||
|
|
||||||
|
for (idx, block_str) in test_blocks.iter().enumerate() {
|
||||||
|
println!("decoding test block {}", idx + 1);
|
||||||
|
let bytes = hex::decode(block_str).expect(&format!("bad block file {}", idx));
|
||||||
|
|
||||||
|
let block = Block::decode_fragment(&bytes[..])
|
||||||
|
.expect(&format!("error decoding cbor for file {}", idx));
|
||||||
|
|
||||||
|
println!("{:?}", block);
|
||||||
|
|
||||||
|
let bytes2 =
|
||||||
|
to_vec(block).expect(&format!("error encoding block cbor for file {}", idx));
|
||||||
|
|
||||||
|
assert_eq!(bytes, bytes2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1
pallas-byron/src/test_data/test1.block
Normal file
1
pallas-byron/src/test_data/test1.block
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
820183851a2d964a095820a5a5c235200bbe91f16cd3e5dcb67369c25dcfb1279c83d22021f5d960c485e684830058200e5751c026e543b2e8ab2eb06099daa1d1e5df47778f7787faab45cdf12fe3a85820afc0da64183bf2664f3d4eec7238d524ba607faeeab24fc100eb861dba69971b82035820d36a2619a672494604e11bb447cbcf5231e9f2ba25c2169177edc941bd50ad6c5820afc0da64183bf2664f3d4eec7238d524ba607faeeab24fc100eb861dba69971b58204e66280cd94d591072349bec0a3090a53aa945562efb6d08d56e53654b0e4098848218cf19545a584026566e86fc6b9b177c8480e275b2b112b573f6d073f9deea53b8d99c4ed976b335b2b3842f0e380001f090bc923caa9691ed9115e286da9421e2745c7acc87f1811a004485098202828400584026566e86fc6b9b177c8480e275b2b112b573f6d073f9deea53b8d99c4ed976b335b2b3842f0e380001f090bc923caa9691ed9115e286da9421e2745c7acc87f15840f14f712dc600d793052d4842d50cefa4e65884ea6cf83707079eb8ce302efc85dae922d5eb3838d2b91784f04824d26767bfb65bd36a36e74fec46d09d98858d58408ab43e904b06e799c1817c5ced4f3a7bbe15cdbf422dea9d2d5dc2c6105ce2f4d4c71e5d4779f6c44b770a133636109949e1f7786acb5a732bcdea0470fea4065840c15d273e3e0735777e2b38359224803aa4a0fcd1cde37ed1f2f399d7e095b18bdc698a2aff59b2118cbbe45498c7bdc6ccf3a88a806cbd3e73bcf2fc6d7364028483020000826a63617264616e6f2d736c01a058204ba92aa320c60acc9ad7b9a64f2eda55c4d2ec28e604faf186708b4f0c4e8edf849fff8203d90102809fff82809fff81a0
|
||||||
1
pallas-byron/src/test_data/test2.block
Normal file
1
pallas-byron/src/test_data/test2.block
Normal file
File diff suppressed because one or more lines are too long
1
pallas-byron/src/test_data/test3.block
Normal file
1
pallas-byron/src/test_data/test3.block
Normal file
File diff suppressed because one or more lines are too long
285
pallas-byron/src/utils.rs
Normal file
285
pallas-byron/src/utils.rs
Normal file
|
|
@ -0,0 +1,285 @@
|
||||||
|
use std::ops::Deref;
|
||||||
|
|
||||||
|
use minicbor::{data::Tag, Decode, Encode};
|
||||||
|
|
||||||
|
/// Custom collection to ensure ordered pairs of values
|
||||||
|
///
|
||||||
|
/// Since the ordering of the entries requires a particular order to maintain
|
||||||
|
/// canonicalization for isomorphic decoding / encoding operators, we use a Vec
|
||||||
|
/// as the underlaying struct for storage of the items (as opposed to a BTreeMap
|
||||||
|
/// or HashMap).
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
pub enum KeyValuePairs<K, V> {
|
||||||
|
Def(Vec<(K, V)>),
|
||||||
|
Indef(Vec<(K, V)>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K, V> Deref for KeyValuePairs<K, V> {
|
||||||
|
type Target = Vec<(K, V)>;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
match self {
|
||||||
|
KeyValuePairs::Def(x) => x,
|
||||||
|
KeyValuePairs::Indef(x) => x,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'b, K, V> minicbor::decode::Decode<'b> for KeyValuePairs<K, V>
|
||||||
|
where
|
||||||
|
K: Encode + Decode<'b>,
|
||||||
|
V: Encode + Decode<'b>,
|
||||||
|
{
|
||||||
|
fn decode(d: &mut minicbor::Decoder<'b>) -> Result<Self, minicbor::decode::Error> {
|
||||||
|
let datatype = d.datatype()?;
|
||||||
|
|
||||||
|
let items: Result<Vec<_>, _> = d.map_iter::<K, V>()?.collect();
|
||||||
|
let items = items?;
|
||||||
|
|
||||||
|
match datatype {
|
||||||
|
minicbor::data::Type::Map => Ok(KeyValuePairs::Def(items)),
|
||||||
|
minicbor::data::Type::MapIndef => Ok(KeyValuePairs::Indef(items)),
|
||||||
|
_ => Err(minicbor::decode::Error::Message(
|
||||||
|
"invalid data type for keyvaluepairs",
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K, V> minicbor::encode::Encode for KeyValuePairs<K, V>
|
||||||
|
where
|
||||||
|
K: Encode,
|
||||||
|
V: Encode,
|
||||||
|
{
|
||||||
|
fn encode<W: minicbor::encode::Write>(
|
||||||
|
&self,
|
||||||
|
e: &mut minicbor::Encoder<W>,
|
||||||
|
) -> Result<(), minicbor::encode::Error<W::Error>> {
|
||||||
|
match self {
|
||||||
|
KeyValuePairs::Def(x) => {
|
||||||
|
e.map(x.len() as u64)?;
|
||||||
|
|
||||||
|
for (k, v) in x.iter() {
|
||||||
|
k.encode(e)?;
|
||||||
|
v.encode(e)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
KeyValuePairs::Indef(x) => {
|
||||||
|
e.begin_map()?;
|
||||||
|
|
||||||
|
for (k, v) in x.iter() {
|
||||||
|
k.encode(e)?;
|
||||||
|
v.encode(e)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.end()?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A struct that maintains a reference to whether a cbor array was indef or not
|
||||||
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
pub enum MaybeIndefArray<A> {
|
||||||
|
Def(Vec<A>),
|
||||||
|
Indef(Vec<A>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A> Deref for MaybeIndefArray<A> {
|
||||||
|
type Target = Vec<A>;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
match self {
|
||||||
|
MaybeIndefArray::Def(x) => x,
|
||||||
|
MaybeIndefArray::Indef(x) => x,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'b, A> minicbor::decode::Decode<'b> for MaybeIndefArray<A>
|
||||||
|
where
|
||||||
|
A: minicbor::decode::Decode<'b>,
|
||||||
|
{
|
||||||
|
fn decode(d: &mut minicbor::Decoder<'b>) -> Result<Self, minicbor::decode::Error> {
|
||||||
|
let datatype = d.datatype()?;
|
||||||
|
|
||||||
|
match datatype {
|
||||||
|
minicbor::data::Type::Array => Ok(Self::Def(d.decode()?)),
|
||||||
|
minicbor::data::Type::ArrayIndef => Ok(Self::Indef(d.decode()?)),
|
||||||
|
_ => Err(minicbor::decode::Error::Message(
|
||||||
|
"unknown data type of maybe indef array",
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A> minicbor::encode::Encode for MaybeIndefArray<A>
|
||||||
|
where
|
||||||
|
A: minicbor::encode::Encode,
|
||||||
|
{
|
||||||
|
fn encode<W: minicbor::encode::Write>(
|
||||||
|
&self,
|
||||||
|
e: &mut minicbor::Encoder<W>,
|
||||||
|
) -> Result<(), minicbor::encode::Error<W::Error>> {
|
||||||
|
match self {
|
||||||
|
MaybeIndefArray::Def(x) => {
|
||||||
|
e.encode(x)?;
|
||||||
|
}
|
||||||
|
MaybeIndefArray::Indef(x) if x.is_empty() => {
|
||||||
|
e.encode(x)?;
|
||||||
|
}
|
||||||
|
MaybeIndefArray::Indef(x) => {
|
||||||
|
e.begin_array()?;
|
||||||
|
|
||||||
|
for v in x.iter() {
|
||||||
|
e.encode(v)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.end()?;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Order-preserving set of attributes
|
||||||
|
///
|
||||||
|
/// There's no guarantee that the entries on a Cardano cbor entity that uses
|
||||||
|
/// maps for its representation will follow the canonical order specified by the
|
||||||
|
/// standard. To implement an isomorphic codec, we need a way of preserving the
|
||||||
|
/// original order in which the entries were encoded. To acomplish this, we
|
||||||
|
/// transform key-value structures into an orderer vec of `properties`, where
|
||||||
|
/// each entry represents a a cbor-encodable variant of an attribute of the
|
||||||
|
/// struct.
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub struct OrderPreservingProperties<P>(Vec<P>);
|
||||||
|
|
||||||
|
impl<P> Deref for OrderPreservingProperties<P> {
|
||||||
|
type Target = Vec<P>;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'b, P> minicbor::decode::Decode<'b> for OrderPreservingProperties<P>
|
||||||
|
where
|
||||||
|
P: Decode<'b>,
|
||||||
|
{
|
||||||
|
fn decode(d: &mut minicbor::Decoder<'b>) -> Result<Self, minicbor::decode::Error> {
|
||||||
|
let len = d.map()?.unwrap_or_default();
|
||||||
|
|
||||||
|
let components: Result<_, _> = (0..len).map(|_| d.decode()).collect();
|
||||||
|
|
||||||
|
Ok(Self(components?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P> minicbor::encode::Encode for OrderPreservingProperties<P>
|
||||||
|
where
|
||||||
|
P: Encode,
|
||||||
|
{
|
||||||
|
fn encode<W: minicbor::encode::Write>(
|
||||||
|
&self,
|
||||||
|
e: &mut minicbor::Encoder<W>,
|
||||||
|
) -> Result<(), minicbor::encode::Error<W::Error>> {
|
||||||
|
e.map(self.0.len() as u64)?;
|
||||||
|
for component in &self.0 {
|
||||||
|
e.encode(component)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wraps a struct so that it is encoded/decoded as a cbor bytes
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct CborWrap<T>(T);
|
||||||
|
|
||||||
|
impl<'b, T> minicbor::Decode<'b> for CborWrap<T>
|
||||||
|
where
|
||||||
|
T: minicbor::Decode<'b>,
|
||||||
|
{
|
||||||
|
fn decode(d: &mut minicbor::Decoder<'b>) -> Result<Self, minicbor::decode::Error> {
|
||||||
|
d.tag()?;
|
||||||
|
let cbor = d.bytes()?;
|
||||||
|
let wrapped = minicbor::decode(cbor)?;
|
||||||
|
|
||||||
|
Ok(CborWrap(wrapped))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> minicbor::Encode for CborWrap<T>
|
||||||
|
where
|
||||||
|
T: minicbor::Encode,
|
||||||
|
{
|
||||||
|
fn encode<W: minicbor::encode::Write>(
|
||||||
|
&self,
|
||||||
|
e: &mut minicbor::Encoder<W>,
|
||||||
|
) -> Result<(), minicbor::encode::Error<W::Error>> {
|
||||||
|
let buf = minicbor::to_vec(&self.0).map_err(|_| {
|
||||||
|
minicbor::encode::Error::Message("error encoding cbor-wrapped structure")
|
||||||
|
})?;
|
||||||
|
|
||||||
|
e.tag(Tag::Cbor)?;
|
||||||
|
e.bytes(&buf)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct TagWrap<I, const T: u64>(I);
|
||||||
|
|
||||||
|
impl<'b, I, const T: u64> minicbor::Decode<'b> for TagWrap<I, T>
|
||||||
|
where
|
||||||
|
I: minicbor::Decode<'b>,
|
||||||
|
{
|
||||||
|
fn decode(d: &mut minicbor::Decoder<'b>) -> Result<Self, minicbor::decode::Error> {
|
||||||
|
d.tag()?;
|
||||||
|
|
||||||
|
Ok(TagWrap(d.decode()?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I, const T: u64> minicbor::Encode for TagWrap<I, T>
|
||||||
|
where
|
||||||
|
I: minicbor::Encode,
|
||||||
|
{
|
||||||
|
fn encode<W: minicbor::encode::Write>(
|
||||||
|
&self,
|
||||||
|
e: &mut minicbor::Encoder<W>,
|
||||||
|
) -> Result<(), minicbor::encode::Error<W::Error>> {
|
||||||
|
e.tag(Tag::Unassigned(T))?;
|
||||||
|
e.encode(&self.0)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An empty map
|
||||||
|
///
|
||||||
|
/// don't ask me why, that's what the CDDL asks for.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct EmptyMap;
|
||||||
|
|
||||||
|
impl<'b> minicbor::decode::Decode<'b> for EmptyMap {
|
||||||
|
fn decode(d: &mut minicbor::Decoder<'b>) -> Result<Self, minicbor::decode::Error> {
|
||||||
|
d.skip()?;
|
||||||
|
Ok(EmptyMap)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl minicbor::encode::Encode for EmptyMap {
|
||||||
|
fn encode<W: minicbor::encode::Write>(
|
||||||
|
&self,
|
||||||
|
e: &mut minicbor::Encoder<W>,
|
||||||
|
) -> Result<(), minicbor::encode::Error<W::Error>> {
|
||||||
|
e.map(0)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -20,5 +20,6 @@ pallas-chainsync = { version = "0.4.0", path = "../pallas-chainsync/" }
|
||||||
pallas-blockfetch = { version = "0.4.0", path = "../pallas-blockfetch/" }
|
pallas-blockfetch = { version = "0.4.0", path = "../pallas-blockfetch/" }
|
||||||
pallas-localstate = { version = "0.4.0", path = "../pallas-localstate/" }
|
pallas-localstate = { version = "0.4.0", path = "../pallas-localstate/" }
|
||||||
pallas-txsubmission = { version = "0.4.0", path = "../pallas-txsubmission/" }
|
pallas-txsubmission = { version = "0.4.0", path = "../pallas-txsubmission/" }
|
||||||
|
pallas-byron = { version = "0.4.0", path = "../pallas-byron/" }
|
||||||
pallas-alonzo = { version = "0.4.0", path = "../pallas-alonzo/" }
|
pallas-alonzo = { version = "0.4.0", path = "../pallas-alonzo/" }
|
||||||
pallas-crypto = { version = "0.4.0", path = "../pallas-crypto/" }
|
pallas-crypto = { version = "0.4.0", path = "../pallas-crypto/" }
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||
//! Ledger primitives and cbor codecs for different Cardano eras
|
//! Ledger primitives and cbor codecs for different Cardano eras
|
||||||
|
|
||||||
|
#[doc(inline)]
|
||||||
|
pub use pallas_byron as byron;
|
||||||
|
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use pallas_alonzo as alonzo;
|
pub use pallas_alonzo as alonzo;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue