chore: Merge Byron / Alonzo into single crate (#43)

This commit is contained in:
Santiago Carmuega 2022-02-09 07:19:17 -03:00 committed by GitHub
parent e41a99883c
commit fec96ffd99
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
61 changed files with 120 additions and 335 deletions

View file

@ -0,0 +1,21 @@
[package]
name = "pallas-primitives"
description = "Ledger primitives and cbor codec for the different Cardano eras"
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" }

View file

@ -0,0 +1,2 @@
# Pallas Primitives

View file

@ -0,0 +1,51 @@
use super::{AuxiliaryData, Header, PlutusData, TransactionBody};
use pallas_crypto::hash::{Hash, Hasher};
pub fn hash_block_header(data: &Header) -> Hash<32> {
Hasher::<256>::hash_cbor(data)
}
pub fn hash_auxiliary_data(data: &AuxiliaryData) -> Hash<32> {
Hasher::<256>::hash_cbor(data)
}
pub fn hash_transaction(data: &TransactionBody) -> Hash<32> {
Hasher::<256>::hash_cbor(data)
}
pub fn hash_plutus_data(data: &PlutusData) -> Hash<32> {
Hasher::<256>::hash_cbor(data)
}
#[cfg(test)]
mod tests {
use crate::alonzo::BlockWrapper;
use crate::Fragment;
use super::hash_transaction;
#[test]
fn transaction_hash_works() {
// TODO: expand this test to include more test blocks
let block_idx = 1;
let block_str = include_str!("test_data/test1.block");
let block_bytes = hex::decode(block_str).expect(&format!("bad block file {}", block_idx));
let block_model = BlockWrapper::decode_fragment(&block_bytes[..])
.expect(&format!("error decoding cbor for file {}", block_idx));
let valid_hashes = vec![
"8ae0cd531635579a9b52b954a840782d12235251fb1451e5c699e864c677514a",
"bb5bb4e1c09c02aa199c60e9f330102912e3ef977bb73ecfd8f790945c6091d4",
"8cdd88042ddb6c800714fb1469fb1a1a93152aae3c87a81f2a3016f2ee5c664a",
"10add6bdaa7ade06466bdd768456e756709090846b58bf473f240c484db517fa",
"8838f5ab27894a6543255aeaec086f7b3405a6db6e7457a541409cdbbf0cd474",
];
for (tx_idx, tx) in block_model.1.transaction_bodies.iter().enumerate() {
let computed_hash = hash_transaction(tx);
let known_hash = valid_hashes[tx_idx];
assert_eq!(hex::encode(computed_hash), known_hash)
}
}
}

View file

@ -0,0 +1,5 @@
mod model;
pub mod crypto;
pub use model::*;

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
820284828f1a0044abcb1a0047967c58202398f79031da6f550bae3f1b632dd4bb368c27c12e32e6bd61f52edfc6eaae7d5820f14f712dc600d793052d4842d50cefa4e65884ea6cf83707079eb8ce302efc85582022f9cecbecf3986953c01ea54260da2fe95b4293141c0712754def9c69ab6c9182584055c3eff59c04e744ae3c16aec6c3f5a551fd8e4f779971decbb6c7d2a3714aec1976264d4ee202ca369f29be932711c8bde63b34b64c06ed2f4e9ab5a1329e57585098c451df3d4a6e9159661fe29a8be2921adc0f103095bbc3d4035222017fcfa6ed04dc79b3fdc9427466a2466669f9fe4ae77fcd4aa8caa848d64ebc4d74586ff3c48a141b5b95e552ec3474f234f50a825840013c07946856242e4f93b3c422082d98982d9e231897d9ee8b59037cd29f6079bf91303b6da9564419ef8fd31a13b3ea6723ec45ec731b434069b375a99cb34f5850c49b9427372dca9828d6d77dbfa2f66e7b68601c4e63fb9ecb298615aa15d6d936069b6213818752819c9a9ea09a28eab4a6df8a7ba87fec95470a0853504b6816c13deb9ef25264db3a244b590306060358201033376be025cb705fd8dd02eda11cc73975a062b5d14ffd74d6ff69e69a2ff75820b6524ab310081164b67a9183be3759f11b018b802f06bb8a7c5d02ee6a7789e800005840868b538f654bde3c98cbc29fbb6fa5d2a9f89bb5f1804a91f0edd301cc1fdf03e1538e1babaa5358c788d81bfd06ad191d2300ef0a0a503ea39f68140ebfa00402005901c07ee89d8efe52849ab043d82ba20aef40c75a78d44ec02643f33ce19177e74bd400027829ec0238a0562babcaf530fb6fd3935438a3a08e1ffcc9094fcf3bd90f6612fe8771a42f65f08f51501180cd881f41e201514737568a83f895444d2541ef4d35a0646b292a1d1863f11939975cd7004407b0f0be050c1d01371e8e0d63e9a21d4a871208780002ac69ec5460b94f5ece69d8a35fa70559764004ac2ac07adceea64f61cc6142d8b46bed3ef7e207d0a558a594f8756aec1c4c23e312641f3a3019c0fa78df9d21cd1596e440b7d928c99964edde0eff1cf1da45352b11e3cb73bc6be058b80329f8d8e870d85dbba84f0e5b52c86384617561a542b3cdc4b312522bb029fd798fcef53ef381b9bb7482930fafcaff501416fc83c73f1a353b7356605996f5e5308f4b8905926de5854617603b0fab1db252de195d6ebc3d2b2f5d0d2396ba8a35513b3e1d8c8607717606122ad05ca50c93fc4437889ea4a4d2c3a273a0466970f8cc86edeac65aaf6092b6b6f581f455bd0bc4ad80d3cbd8f37a07f076439e0e9385795d4185603419eee6018bbb237cccf827aab2214c2dac5ef86714648ca654ab93b34e7478c6814419970eae26d5a50dade111b88080a0

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
820585828f1a002f4a4c1a029629ad58205ad2f2deceaccd8146b93759d0fa67991651ca839144e64003be26286d1d378e58209b30232b87e5568f4dd9848a0ea9d91fef54ba11bcd39121cef5e7e6e750f1575820fae4b8f31c676f58a039005d59ea1d2179a83ed2e1f0707b46c2f6c4401d7206825840cf0f48ee58294f1e576a94158d2874d1502116e0cc6a645968c0338e453d774fae0759e2f20d77d413e00c9aa9aaeac090dcbc71a02eb5a15dcb8390bec5e67a585033f146522cf11b4df9382b37b1ea4630bf270317cab1d7c957273426777ae0e4e7d6d700cfec44380a1958dbbee09055b84fcf4b40d506c0ec4c620c005737a250297b877431405eb77c36beee74fa058258400068ee9ea93d139ecca4a7a4ecd9e18c0e233c08149e75080bbbe7b5aac6e3280236d703a9afd93513e972dbaa063c05356512e74c81612d5c9e0436038567fb58500b1bf104008ff1ed4cbb8aeaba933e0a06a0f117dedd8a6f13f6bf62cb00c2225461a88c4e92d9d4b5ab109d58416a76e23d28f36c7d3878e7b16fffa61fb66dea0fbabbc42677f557c3f38384f0d4071904285820d392fb9117513610ab841a17327bc28572cc1fbf47eeaf494917e664d3d014b15820b4590f50ac87d2b4349ba2166b0127c0c78243907e908e6fedb40aedd4b93d7c061901485840b8f3a384c3c4fc4ba055fe96fd152955c04657f84bb5486699222dd2f165f47ce28d8c16cee5df37a6157eb03feadf8318726708af24aa7a4e8115e8cce3790e06005901c0c889981b5e3e242be0d9bc74d7e3cdbb9f1ffd59a11fe2256ee6f66b3c7bf575a847fcdf6899fa14e94bf80da25544c33a21b4fe75166dcef427c97c5386b00b97abfc1a062248aab0ac49054ff3c7de07978850417da22248c31d1c500c92de762ded2c4bf896ff46b16a1cf4f67a4c9e805b25f1286a411e4f29ab1142d988d75a68cc52261d255e7a639917df4dcf04b0b6266e99470f184aa9284e2339138b0bfcf460d558db50c0cd213347db35a13d47dadcffad568e944a70a0a9f2ea34e6cf313d355acf01838f5a0e39afd5ac832a376d03bcb8fbd9f51b75dcfda1a70194842f9793606ba2fefc63fd35fc7032c64887be82b257645b200e0cce00cff671e5444910b85a119970affd8a6121fd07dfdf7482255092025233aba620973f083ffb6b3e1310a8f96573bc117d38827deeea18dd62b44e660fea3dd94cae33bed669d40bd4af7d6cf0e64043a09f3a300932814749610f8e5c66438a7aa6ae5bf662dc81b1fa2b586b2048b0ed8d714c667f5ffd8579919942c64032bb0221b5fcb7625aca20ec2b1c0d189a37db5c03e613234739506d595980a06543e4746a7e82f6ab2e816f13d6d02aa26ab1bba65585fa700dc42b08609075f79f81a600838258204cf7df47e1aa8303380aa4dde4b83545c48e6094fea6735a9885e9e784e6d80d01825820ca60ad59ae9df6b3188d9c6b8545723a973695e58dc5aab6c5edf3b6611a10b501825820cea4b3f0dd6d815cc028c0f6e790bf719f49c334108ca1014e4794fc59344093010d818258202bf219d87408a81b110567b01c8d3cc3fc7e17d4d3585a21587e6a4b454426f3000184825839008cc30a5608abf06060864e214441d9be2362692bc25fda12ee549fbdab0359580d253ffdfd5b7e57692fba68db312d184a23231c24f27c9b1a0098968082583900d34fecdda880807048625cbf1f09af024ab4694c9e45888d2a0de6045c76aa2fefc4b0c3886d2a2adef634ba9040ab91c64d16a224f5737d821a00155cc0a1581cd9a1156d008866951090923bb1d39587aaebb342c50e5fb848f5d84fa1445245563218c883581d7067f33146617a5e61936081db3b2117cbf59bd2123748f58ac9678656821a032d3579a1581cd9a1156d008866951090923bb1d39587aaebb342c50e5fb848f5d84fa247504f4f4c4e465401445245563219021c5820aef3b61d6806116a70ada02870f7717249252b70f117d7d2bf1d5e7d4487de25825839008cc30a5608abf06060864e214441d9be2362692bc25fda12ee549fbdab0359580d253ffdfd5b7e57692fba68db312d184a23231c24f27c9b821a00d59f80a1581cd9a1156d008866951090923bb1d39587aaebb342c50e5fb848f5d84fa14953776170546f6b656e1a00989748021a000322e70e800b58200d6e2523d69edd04bdf699a0d369fbc6d39076df73e4d15b2e2f1e20d290355581a4008182582054f1a5800650ab29f920cc05e5cf73bb64a0359c6952e78a8386a6ac4e320e8258403d1a117682859510ae27ee98bb89d24eac0a9dac605c2008a65e85df75de6c5682d0ba3944bd17a1ecfe1f8cf38160d1831a5e7889141e1b2871dfb6843af10703814e4d0100003322222005120012001104839f583f616464725f746573743177706e6c78763278763961397563766e767a71616b7765707a6c396c7478376a7a676d353361763265396e637634737973656d6d3840ff9f5840616464725f7465737431717a7876787a6a6b707a346c716372717365387a7a337a706d786c7a78636e66393070396c6b736a616532666c306474716476347372582c6639386c376c366b6d373261356a6c776e676d76636a36787a32797633336366386a306a64736574666c656bff9f5840616464725f7465737431717266356c6d7861347a716771757a6776667774373863663475707934647266666a3079747a79643967783776707a757736347a6c6d582c37796b727063736d663239743030766439366a7071326879777866357432796638347764377364776c727474ff05838400001864821906a41a0007453484000101821906a41a000745348400021864821906a41a00074534a080

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,7 @@
//! Ledger primitives and cbor codec for the Byron era
mod model;
pub use model::*;
// pub mod crypto;

View file

@ -0,0 +1,931 @@
//! 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 minicbor::bytes::ByteVec;
use minicbor_derive::{Decode, Encode};
use pallas_crypto::hash::Hash;
use crate::utils::{
CborWrap, EmptyMap, KeyValuePairs, MaybeIndefArray, OrderPreservingProperties, TagWrap,
};
// 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>,
}
#[allow(clippy::large_enum_variant)]
#[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::byron::Block;
use crate::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));
let _bytes2 =
to_vec(block).expect(&format!("error encoding block cbor for file {}", idx));
// HACK: we ommit the ismorphic requirement until we find the
// offending difference
// assert_eq!(bytes, bytes2);
}
}
}

View file

@ -0,0 +1 @@
820183851a2d964a095820a5a5c235200bbe91f16cd3e5dcb67369c25dcfb1279c83d22021f5d960c485e684830058200e5751c026e543b2e8ab2eb06099daa1d1e5df47778f7787faab45cdf12fe3a85820afc0da64183bf2664f3d4eec7238d524ba607faeeab24fc100eb861dba69971b82035820d36a2619a672494604e11bb447cbcf5231e9f2ba25c2169177edc941bd50ad6c5820afc0da64183bf2664f3d4eec7238d524ba607faeeab24fc100eb861dba69971b58204e66280cd94d591072349bec0a3090a53aa945562efb6d08d56e53654b0e4098848218cf19545a584026566e86fc6b9b177c8480e275b2b112b573f6d073f9deea53b8d99c4ed976b335b2b3842f0e380001f090bc923caa9691ed9115e286da9421e2745c7acc87f1811a004485098202828400584026566e86fc6b9b177c8480e275b2b112b573f6d073f9deea53b8d99c4ed976b335b2b3842f0e380001f090bc923caa9691ed9115e286da9421e2745c7acc87f15840f14f712dc600d793052d4842d50cefa4e65884ea6cf83707079eb8ce302efc85dae922d5eb3838d2b91784f04824d26767bfb65bd36a36e74fec46d09d98858d58408ab43e904b06e799c1817c5ced4f3a7bbe15cdbf422dea9d2d5dc2c6105ce2f4d4c71e5d4779f6c44b770a133636109949e1f7786acb5a732bcdea0470fea4065840c15d273e3e0735777e2b38359224803aa4a0fcd1cde37ed1f2f399d7e095b18bdc698a2aff59b2118cbbe45498c7bdc6ccf3a88a806cbd3e73bcf2fc6d7364028483020000826a63617264616e6f2d736c01a058204ba92aa320c60acc9ad7b9a64f2eda55c4d2ec28e604faf186708b4f0c4e8edf849fff8203d90102809fff82809fff81a0

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View 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())
}
}

View file

@ -0,0 +1,9 @@
//! Ledger primitives and cbor codec for the Cardano eras
mod framework;
pub mod alonzo;
pub mod byron;
pub mod utils;
pub use framework::*;

View file

@ -0,0 +1,311 @@
use std::ops::Deref;
use minicbor::{data::Tag, Decode, Encode};
/// Utility for skipping parts of the CBOR payload, use only for debugging
#[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();
log::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!()
}
}
/// 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(())
}
}