chore: Merge Byron / Alonzo into single crate (#43)
This commit is contained in:
parent
e41a99883c
commit
fec96ffd99
61 changed files with 120 additions and 335 deletions
21
pallas-primitives/Cargo.toml
Normal file
21
pallas-primitives/Cargo.toml
Normal 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" }
|
||||
2
pallas-primitives/README.md
Normal file
2
pallas-primitives/README.md
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
# Pallas Primitives
|
||||
|
||||
51
pallas-primitives/src/alonzo/crypto.rs
Normal file
51
pallas-primitives/src/alonzo/crypto.rs
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
5
pallas-primitives/src/alonzo/mod.rs
Normal file
5
pallas-primitives/src/alonzo/mod.rs
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
mod model;
|
||||
|
||||
pub mod crypto;
|
||||
|
||||
pub use model::*;
|
||||
1438
pallas-primitives/src/alonzo/model.rs
Normal file
1438
pallas-primitives/src/alonzo/model.rs
Normal file
File diff suppressed because it is too large
Load diff
1
pallas-primitives/src/alonzo/test_data/test1.block
Normal file
1
pallas-primitives/src/alonzo/test_data/test1.block
Normal file
File diff suppressed because one or more lines are too long
1
pallas-primitives/src/alonzo/test_data/test10.block
Normal file
1
pallas-primitives/src/alonzo/test_data/test10.block
Normal file
|
|
@ -0,0 +1 @@
|
|||
820284828f1a0044abcb1a0047967c58202398f79031da6f550bae3f1b632dd4bb368c27c12e32e6bd61f52edfc6eaae7d5820f14f712dc600d793052d4842d50cefa4e65884ea6cf83707079eb8ce302efc85582022f9cecbecf3986953c01ea54260da2fe95b4293141c0712754def9c69ab6c9182584055c3eff59c04e744ae3c16aec6c3f5a551fd8e4f779971decbb6c7d2a3714aec1976264d4ee202ca369f29be932711c8bde63b34b64c06ed2f4e9ab5a1329e57585098c451df3d4a6e9159661fe29a8be2921adc0f103095bbc3d4035222017fcfa6ed04dc79b3fdc9427466a2466669f9fe4ae77fcd4aa8caa848d64ebc4d74586ff3c48a141b5b95e552ec3474f234f50a825840013c07946856242e4f93b3c422082d98982d9e231897d9ee8b59037cd29f6079bf91303b6da9564419ef8fd31a13b3ea6723ec45ec731b434069b375a99cb34f5850c49b9427372dca9828d6d77dbfa2f66e7b68601c4e63fb9ecb298615aa15d6d936069b6213818752819c9a9ea09a28eab4a6df8a7ba87fec95470a0853504b6816c13deb9ef25264db3a244b590306060358201033376be025cb705fd8dd02eda11cc73975a062b5d14ffd74d6ff69e69a2ff75820b6524ab310081164b67a9183be3759f11b018b802f06bb8a7c5d02ee6a7789e800005840868b538f654bde3c98cbc29fbb6fa5d2a9f89bb5f1804a91f0edd301cc1fdf03e1538e1babaa5358c788d81bfd06ad191d2300ef0a0a503ea39f68140ebfa00402005901c07ee89d8efe52849ab043d82ba20aef40c75a78d44ec02643f33ce19177e74bd400027829ec0238a0562babcaf530fb6fd3935438a3a08e1ffcc9094fcf3bd90f6612fe8771a42f65f08f51501180cd881f41e201514737568a83f895444d2541ef4d35a0646b292a1d1863f11939975cd7004407b0f0be050c1d01371e8e0d63e9a21d4a871208780002ac69ec5460b94f5ece69d8a35fa70559764004ac2ac07adceea64f61cc6142d8b46bed3ef7e207d0a558a594f8756aec1c4c23e312641f3a3019c0fa78df9d21cd1596e440b7d928c99964edde0eff1cf1da45352b11e3cb73bc6be058b80329f8d8e870d85dbba84f0e5b52c86384617561a542b3cdc4b312522bb029fd798fcef53ef381b9bb7482930fafcaff501416fc83c73f1a353b7356605996f5e5308f4b8905926de5854617603b0fab1db252de195d6ebc3d2b2f5d0d2396ba8a35513b3e1d8c8607717606122ad05ca50c93fc4437889ea4a4d2c3a273a0466970f8cc86edeac65aaf6092b6b6f581f455bd0bc4ad80d3cbd8f37a07f076439e0e9385795d4185603419eee6018bbb237cccf827aab2214c2dac5ef86714648ca654ab93b34e7478c6814419970eae26d5a50dade111b88080a0
|
||||
1
pallas-primitives/src/alonzo/test_data/test11.block
Normal file
1
pallas-primitives/src/alonzo/test_data/test11.block
Normal file
File diff suppressed because one or more lines are too long
1
pallas-primitives/src/alonzo/test_data/test12.block
Normal file
1
pallas-primitives/src/alonzo/test_data/test12.block
Normal file
File diff suppressed because one or more lines are too long
1
pallas-primitives/src/alonzo/test_data/test13.block
Normal file
1
pallas-primitives/src/alonzo/test_data/test13.block
Normal file
File diff suppressed because one or more lines are too long
1
pallas-primitives/src/alonzo/test_data/test14.block
Normal file
1
pallas-primitives/src/alonzo/test_data/test14.block
Normal file
File diff suppressed because one or more lines are too long
1
pallas-primitives/src/alonzo/test_data/test2.block
Normal file
1
pallas-primitives/src/alonzo/test_data/test2.block
Normal file
File diff suppressed because one or more lines are too long
1
pallas-primitives/src/alonzo/test_data/test3.block
Normal file
1
pallas-primitives/src/alonzo/test_data/test3.block
Normal file
File diff suppressed because one or more lines are too long
1
pallas-primitives/src/alonzo/test_data/test4.block
Normal file
1
pallas-primitives/src/alonzo/test_data/test4.block
Normal file
File diff suppressed because one or more lines are too long
1
pallas-primitives/src/alonzo/test_data/test5.block
Normal file
1
pallas-primitives/src/alonzo/test_data/test5.block
Normal file
File diff suppressed because one or more lines are too long
1
pallas-primitives/src/alonzo/test_data/test6.block
Normal file
1
pallas-primitives/src/alonzo/test_data/test6.block
Normal file
File diff suppressed because one or more lines are too long
1
pallas-primitives/src/alonzo/test_data/test7.block
Normal file
1
pallas-primitives/src/alonzo/test_data/test7.block
Normal file
|
|
@ -0,0 +1 @@
|
|||
820585828f1a002f4a4c1a029629ad58205ad2f2deceaccd8146b93759d0fa67991651ca839144e64003be26286d1d378e58209b30232b87e5568f4dd9848a0ea9d91fef54ba11bcd39121cef5e7e6e750f1575820fae4b8f31c676f58a039005d59ea1d2179a83ed2e1f0707b46c2f6c4401d7206825840cf0f48ee58294f1e576a94158d2874d1502116e0cc6a645968c0338e453d774fae0759e2f20d77d413e00c9aa9aaeac090dcbc71a02eb5a15dcb8390bec5e67a585033f146522cf11b4df9382b37b1ea4630bf270317cab1d7c957273426777ae0e4e7d6d700cfec44380a1958dbbee09055b84fcf4b40d506c0ec4c620c005737a250297b877431405eb77c36beee74fa058258400068ee9ea93d139ecca4a7a4ecd9e18c0e233c08149e75080bbbe7b5aac6e3280236d703a9afd93513e972dbaa063c05356512e74c81612d5c9e0436038567fb58500b1bf104008ff1ed4cbb8aeaba933e0a06a0f117dedd8a6f13f6bf62cb00c2225461a88c4e92d9d4b5ab109d58416a76e23d28f36c7d3878e7b16fffa61fb66dea0fbabbc42677f557c3f38384f0d4071904285820d392fb9117513610ab841a17327bc28572cc1fbf47eeaf494917e664d3d014b15820b4590f50ac87d2b4349ba2166b0127c0c78243907e908e6fedb40aedd4b93d7c061901485840b8f3a384c3c4fc4ba055fe96fd152955c04657f84bb5486699222dd2f165f47ce28d8c16cee5df37a6157eb03feadf8318726708af24aa7a4e8115e8cce3790e06005901c0c889981b5e3e242be0d9bc74d7e3cdbb9f1ffd59a11fe2256ee6f66b3c7bf575a847fcdf6899fa14e94bf80da25544c33a21b4fe75166dcef427c97c5386b00b97abfc1a062248aab0ac49054ff3c7de07978850417da22248c31d1c500c92de762ded2c4bf896ff46b16a1cf4f67a4c9e805b25f1286a411e4f29ab1142d988d75a68cc52261d255e7a639917df4dcf04b0b6266e99470f184aa9284e2339138b0bfcf460d558db50c0cd213347db35a13d47dadcffad568e944a70a0a9f2ea34e6cf313d355acf01838f5a0e39afd5ac832a376d03bcb8fbd9f51b75dcfda1a70194842f9793606ba2fefc63fd35fc7032c64887be82b257645b200e0cce00cff671e5444910b85a119970affd8a6121fd07dfdf7482255092025233aba620973f083ffb6b3e1310a8f96573bc117d38827deeea18dd62b44e660fea3dd94cae33bed669d40bd4af7d6cf0e64043a09f3a300932814749610f8e5c66438a7aa6ae5bf662dc81b1fa2b586b2048b0ed8d714c667f5ffd8579919942c64032bb0221b5fcb7625aca20ec2b1c0d189a37db5c03e613234739506d595980a06543e4746a7e82f6ab2e816f13d6d02aa26ab1bba65585fa700dc42b08609075f79f81a600838258204cf7df47e1aa8303380aa4dde4b83545c48e6094fea6735a9885e9e784e6d80d01825820ca60ad59ae9df6b3188d9c6b8545723a973695e58dc5aab6c5edf3b6611a10b501825820cea4b3f0dd6d815cc028c0f6e790bf719f49c334108ca1014e4794fc59344093010d818258202bf219d87408a81b110567b01c8d3cc3fc7e17d4d3585a21587e6a4b454426f3000184825839008cc30a5608abf06060864e214441d9be2362692bc25fda12ee549fbdab0359580d253ffdfd5b7e57692fba68db312d184a23231c24f27c9b1a0098968082583900d34fecdda880807048625cbf1f09af024ab4694c9e45888d2a0de6045c76aa2fefc4b0c3886d2a2adef634ba9040ab91c64d16a224f5737d821a00155cc0a1581cd9a1156d008866951090923bb1d39587aaebb342c50e5fb848f5d84fa1445245563218c883581d7067f33146617a5e61936081db3b2117cbf59bd2123748f58ac9678656821a032d3579a1581cd9a1156d008866951090923bb1d39587aaebb342c50e5fb848f5d84fa247504f4f4c4e465401445245563219021c5820aef3b61d6806116a70ada02870f7717249252b70f117d7d2bf1d5e7d4487de25825839008cc30a5608abf06060864e214441d9be2362692bc25fda12ee549fbdab0359580d253ffdfd5b7e57692fba68db312d184a23231c24f27c9b821a00d59f80a1581cd9a1156d008866951090923bb1d39587aaebb342c50e5fb848f5d84fa14953776170546f6b656e1a00989748021a000322e70e800b58200d6e2523d69edd04bdf699a0d369fbc6d39076df73e4d15b2e2f1e20d290355581a4008182582054f1a5800650ab29f920cc05e5cf73bb64a0359c6952e78a8386a6ac4e320e8258403d1a117682859510ae27ee98bb89d24eac0a9dac605c2008a65e85df75de6c5682d0ba3944bd17a1ecfe1f8cf38160d1831a5e7889141e1b2871dfb6843af10703814e4d0100003322222005120012001104839f583f616464725f746573743177706e6c78763278763961397563766e767a71616b7765707a6c396c7478376a7a676d353361763265396e637634737973656d6d3840ff9f5840616464725f7465737431717a7876787a6a6b707a346c716372717365387a7a337a706d786c7a78636e66393070396c6b736a616532666c306474716476347372582c6639386c376c366b6d373261356a6c776e676d76636a36787a32797633336366386a306a64736574666c656bff9f5840616464725f7465737431717266356c6d7861347a716771757a6776667774373863663475707934647266666a3079747a79643967783776707a757736347a6c6d582c37796b727063736d663239743030766439366a7071326879777866357432796638347764377364776c727474ff05838400001864821906a41a0007453484000101821906a41a000745348400021864821906a41a00074534a080
|
||||
1
pallas-primitives/src/alonzo/test_data/test8.block
Normal file
1
pallas-primitives/src/alonzo/test_data/test8.block
Normal file
File diff suppressed because one or more lines are too long
1
pallas-primitives/src/alonzo/test_data/test9.block
Normal file
1
pallas-primitives/src/alonzo/test_data/test9.block
Normal file
File diff suppressed because one or more lines are too long
7
pallas-primitives/src/byron/mod.rs
Normal file
7
pallas-primitives/src/byron/mod.rs
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
//! Ledger primitives and cbor codec for the Byron era
|
||||
|
||||
mod model;
|
||||
|
||||
pub use model::*;
|
||||
|
||||
// pub mod crypto;
|
||||
931
pallas-primitives/src/byron/model.rs
Normal file
931
pallas-primitives/src/byron/model.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
1
pallas-primitives/src/byron/test_data/test1.block
Normal file
1
pallas-primitives/src/byron/test_data/test1.block
Normal file
|
|
@ -0,0 +1 @@
|
|||
820183851a2d964a095820a5a5c235200bbe91f16cd3e5dcb67369c25dcfb1279c83d22021f5d960c485e684830058200e5751c026e543b2e8ab2eb06099daa1d1e5df47778f7787faab45cdf12fe3a85820afc0da64183bf2664f3d4eec7238d524ba607faeeab24fc100eb861dba69971b82035820d36a2619a672494604e11bb447cbcf5231e9f2ba25c2169177edc941bd50ad6c5820afc0da64183bf2664f3d4eec7238d524ba607faeeab24fc100eb861dba69971b58204e66280cd94d591072349bec0a3090a53aa945562efb6d08d56e53654b0e4098848218cf19545a584026566e86fc6b9b177c8480e275b2b112b573f6d073f9deea53b8d99c4ed976b335b2b3842f0e380001f090bc923caa9691ed9115e286da9421e2745c7acc87f1811a004485098202828400584026566e86fc6b9b177c8480e275b2b112b573f6d073f9deea53b8d99c4ed976b335b2b3842f0e380001f090bc923caa9691ed9115e286da9421e2745c7acc87f15840f14f712dc600d793052d4842d50cefa4e65884ea6cf83707079eb8ce302efc85dae922d5eb3838d2b91784f04824d26767bfb65bd36a36e74fec46d09d98858d58408ab43e904b06e799c1817c5ced4f3a7bbe15cdbf422dea9d2d5dc2c6105ce2f4d4c71e5d4779f6c44b770a133636109949e1f7786acb5a732bcdea0470fea4065840c15d273e3e0735777e2b38359224803aa4a0fcd1cde37ed1f2f399d7e095b18bdc698a2aff59b2118cbbe45498c7bdc6ccf3a88a806cbd3e73bcf2fc6d7364028483020000826a63617264616e6f2d736c01a058204ba92aa320c60acc9ad7b9a64f2eda55c4d2ec28e604faf186708b4f0c4e8edf849fff8203d90102809fff82809fff81a0
|
||||
1
pallas-primitives/src/byron/test_data/test2.block
Normal file
1
pallas-primitives/src/byron/test_data/test2.block
Normal file
File diff suppressed because one or more lines are too long
1
pallas-primitives/src/byron/test_data/test3.block
Normal file
1
pallas-primitives/src/byron/test_data/test3.block
Normal file
File diff suppressed because one or more lines are too long
22
pallas-primitives/src/framework.rs
Normal file
22
pallas-primitives/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())
|
||||
}
|
||||
}
|
||||
9
pallas-primitives/src/lib.rs
Normal file
9
pallas-primitives/src/lib.rs
Normal 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::*;
|
||||
311
pallas-primitives/src/utils.rs
Normal file
311
pallas-primitives/src/utils.rs
Normal 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(())
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue