pallas_primitives/byron/
model.rs

1//! Ledger primitives and cbor codec for the Byron era
2//!
3//! 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.
4
5use pallas_codec::minicbor::{bytes::ByteVec, Decode, Encode};
6use pallas_crypto::hash::Hash;
7
8use pallas_codec::utils::{
9    CborWrap, EmptyMap, KeepRaw, KeyValuePairs, MaybeIndefArray, TagWrap, ZeroOrOneArray,
10};
11
12// required for derive attrs to work
13use pallas_codec::minicbor;
14
15use std::hash::Hash as StdHash;
16
17// Basic Cardano Types
18
19pub type Blake2b256 = Hash<32>;
20
21pub type TxId = Blake2b256;
22pub type BlockId = Blake2b256;
23pub type UpdId = Blake2b256;
24pub type ByronHash = Blake2b256;
25
26pub type Blake2b224 = Hash<28>;
27
28pub type AddressId = Blake2b224;
29pub type StakeholderId = Blake2b224;
30
31pub type EpochId = u64;
32
33#[derive(Encode, Decode, Debug, Clone)]
34pub struct SlotId {
35    #[n(0)]
36    pub epoch: EpochId,
37
38    #[n(1)]
39    pub slot: u64,
40}
41
42pub type PubKey = ByteVec;
43pub type Signature = ByteVec;
44
45// Attributes
46
47// quote from the CDDL file: at the moment we do not bother deserialising these,
48// since they don't contain anything
49
50// attributes = {* any => any}
51pub type Attributes = EmptyMap;
52
53// The cbor struct of the address payload is now defined in pallas-addresses.
54// The primitives crate will treat addresses as a black-box vec of bytes.
55
56// address = [ #6.24(bytes .cbor ([addressid, addrattr, addrtype])), u64 ]
57#[derive(Debug, Encode, Decode, Clone, PartialEq, Eq, PartialOrd, Ord)]
58pub struct Address {
59    #[n(0)]
60    pub payload: TagWrap<ByteVec, 24>,
61
62    #[n(1)]
63    pub crc: u32,
64}
65
66// Transactions
67
68// txout = [address, u64]
69#[derive(Debug, Encode, Decode, Clone, PartialEq, Eq)]
70pub struct TxOut {
71    #[n(0)]
72    pub address: Address,
73
74    #[n(1)]
75    pub amount: u64,
76}
77
78#[derive(Debug, Clone, PartialEq, Eq, StdHash)]
79pub enum TxIn {
80    // [0, #6.24(bytes .cbor ([txid, u32]))]
81    Variant0(CborWrap<(TxId, u32)>),
82
83    // [u8 .ne 0, encoded-cbor]
84    Other(u8, ByteVec),
85}
86
87impl<'b, C> minicbor::Decode<'b, C> for TxIn {
88    fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result<Self, minicbor::decode::Error> {
89        d.array()?;
90
91        let variant = d.u8()?;
92
93        match variant {
94            0 => Ok(TxIn::Variant0(d.decode_with(ctx)?)),
95            x => Ok(TxIn::Other(x, d.decode_with(ctx)?)),
96        }
97    }
98}
99
100impl<C> minicbor::Encode<C> for TxIn {
101    fn encode<W: minicbor::encode::Write>(
102        &self,
103        e: &mut minicbor::Encoder<W>,
104        ctx: &mut C,
105    ) -> Result<(), minicbor::encode::Error<W::Error>> {
106        match self {
107            TxIn::Variant0(x) => {
108                e.array(2)?;
109                e.u8(0)?;
110                e.encode_with(x, ctx)?;
111
112                Ok(())
113            }
114            TxIn::Other(a, b) => {
115                e.array(2)?;
116                e.u8(*a)?;
117                e.encode_with(b, ctx)?;
118
119                Ok(())
120            }
121        }
122    }
123}
124
125// tx = [[+ txin], [+ txout], attributes]
126#[derive(Debug, Encode, Decode, Clone, PartialEq, Eq)]
127pub struct Tx {
128    #[n(0)]
129    pub inputs: MaybeIndefArray<TxIn>,
130
131    #[n(1)]
132    pub outputs: MaybeIndefArray<TxOut>,
133
134    #[n(2)]
135    pub attributes: Attributes,
136}
137
138// txproof = [u32, hash, hash]
139pub type TxProof = (u32, ByronHash, ByronHash);
140
141pub type ValidatorScript = (u16, ByteVec);
142pub type RedeemerScript = (u16, ByteVec);
143
144#[derive(Debug, Clone)]
145pub enum Twit {
146    // [0, #6.24(bytes .cbor ([pubkey, signature]))]
147    PkWitness(CborWrap<(PubKey, Signature)>),
148
149    // [1, #6.24(bytes .cbor ([[u16, bytes], [u16, bytes]]))]
150    ScriptWitness(CborWrap<(ValidatorScript, RedeemerScript)>),
151
152    // [2, #6.24(bytes .cbor ([pubkey, signature]))]
153    RedeemWitness(CborWrap<(PubKey, Signature)>),
154
155    // [u8 .gt 2, encoded-cbor]
156    Other(u8, ByteVec),
157}
158
159impl<'b, C> minicbor::Decode<'b, C> for Twit {
160    fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result<Self, minicbor::decode::Error> {
161        d.array()?;
162
163        let variant = d.u8()?;
164
165        match variant {
166            0 => Ok(Twit::PkWitness(d.decode_with(ctx)?)),
167            1 => Ok(Twit::ScriptWitness(d.decode_with(ctx)?)),
168            2 => Ok(Twit::RedeemWitness(d.decode_with(ctx)?)),
169            x => Ok(Twit::Other(x, d.decode_with(ctx)?)),
170        }
171    }
172}
173
174impl<C> minicbor::Encode<C> for Twit {
175    fn encode<W: minicbor::encode::Write>(
176        &self,
177        e: &mut minicbor::Encoder<W>,
178        ctx: &mut C,
179    ) -> Result<(), minicbor::encode::Error<W::Error>> {
180        match self {
181            Twit::PkWitness(x) => {
182                e.array(2)?;
183                e.u8(0)?;
184                e.encode_with(x, ctx)?;
185
186                Ok(())
187            }
188            Twit::ScriptWitness(x) => {
189                e.array(2)?;
190                e.u8(1)?;
191                e.encode_with(x, ctx)?;
192
193                Ok(())
194            }
195            Twit::RedeemWitness(x) => {
196                e.array(2)?;
197                e.u8(2)?;
198                e.encode(x)?;
199
200                Ok(())
201            }
202            Twit::Other(a, b) => {
203                e.array(2)?;
204                e.u8(*a)?;
205                e.encode(b)?;
206
207                Ok(())
208            }
209        }
210    }
211}
212
213// Shared Seed Computation
214
215// cddl note:
216// This is encoded using the 'Binary' instance
217// for Scrape.PublicKey
218pub type VssPubKey = ByteVec;
219
220// cddl note:
221// This is encoded using the 'Binary' instance
222// for Scrape.Secret.
223pub type VssSec = ByteVec;
224
225// cddl note:
226// This is encoded using the 'Binary' instance
227// for Scrape.EncryptedSi.
228// TODO work out why this seems to be in a length 1 array
229pub type VssEnc = MaybeIndefArray<ByteVec>;
230
231// cddl note:
232// This is encoded using the 'Binary' instance
233// for Scrape.DecryptedShare
234pub type VssDec = ByteVec;
235
236// cddl note:
237// This is encoded using the
238// 'Binary' instance for Scrape.Proof
239pub type VssProof = (ByteVec, ByteVec, ByteVec, MaybeIndefArray<ByteVec>);
240
241//ssccomm = [pubkey, [{vsspubkey => vssenc},vssproof], signature]
242pub type SscComm = (
243    PubKey,
244    (KeyValuePairs<VssPubKey, VssEnc>, VssProof),
245    Signature,
246);
247
248//ssccomms = #6.258([* ssccomm])
249pub type SscComms = TagWrap<MaybeIndefArray<SscComm>, 258>;
250
251// sscopens = {stakeholderid => vsssec}
252pub type SscOpens = KeyValuePairs<StakeholderId, VssSec>;
253
254// sscshares = {addressid => [addressid, [* vssdec]]}
255pub type SscShares = KeyValuePairs<AddressId, KeyValuePairs<AddressId, MaybeIndefArray<VssDec>>>;
256
257// CDDL says: ssccert = [vsspubkey, pubkey, epochid, signature]
258// this is what seems to work: ssccert = [vsspubkey, epochid, pubkey, signature]
259pub type SscCert = (VssPubKey, EpochId, PubKey, Signature);
260
261// ssccerts = #6.258([* ssccert])
262pub type SscCerts = TagWrap<MaybeIndefArray<SscCert>, 258>;
263
264#[derive(Debug, Clone)]
265pub enum Ssc {
266    Variant0(SscComms, SscCerts),
267    Variant1(SscOpens, SscCerts),
268    Variant2(SscShares, SscCerts),
269    Variant3(SscCerts),
270}
271
272impl<'b, C> minicbor::Decode<'b, C> for Ssc {
273    fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result<Self, minicbor::decode::Error> {
274        d.array()?;
275
276        let variant = d.u8()?;
277
278        match variant {
279            0 => Ok(Ssc::Variant0(d.decode_with(ctx)?, d.decode_with(ctx)?)),
280            1 => Ok(Ssc::Variant1(d.decode_with(ctx)?, d.decode_with(ctx)?)),
281            2 => Ok(Ssc::Variant2(d.decode_with(ctx)?, d.decode_with(ctx)?)),
282            3 => Ok(Ssc::Variant3(d.decode_with(ctx)?)),
283            _ => Err(minicbor::decode::Error::message("invalid variant for ssc")),
284        }
285    }
286}
287
288impl<C> minicbor::Encode<C> for Ssc {
289    fn encode<W: minicbor::encode::Write>(
290        &self,
291        e: &mut minicbor::Encoder<W>,
292        ctx: &mut C,
293    ) -> Result<(), minicbor::encode::Error<W::Error>> {
294        match self {
295            Ssc::Variant0(a, b) => {
296                e.array(3)?;
297                e.u8(0)?;
298                e.encode_with(a, ctx)?;
299                e.encode_with(b, ctx)?;
300
301                Ok(())
302            }
303            Ssc::Variant1(a, b) => {
304                e.array(3)?;
305                e.u8(1)?;
306                e.encode_with(a, ctx)?;
307                e.encode_with(b, ctx)?;
308
309                Ok(())
310            }
311            Ssc::Variant2(a, b) => {
312                e.array(3)?;
313                e.u8(2)?;
314                e.encode_with(a, ctx)?;
315                e.encode_with(b, ctx)?;
316
317                Ok(())
318            }
319            Ssc::Variant3(x) => {
320                e.array(2)?;
321                e.u8(3)?;
322                e.encode_with(x, ctx)?;
323
324                Ok(())
325            }
326        }
327    }
328}
329
330#[derive(Debug, Clone)]
331pub enum SscProof {
332    Variant0(ByronHash, ByronHash),
333    Variant1(ByronHash, ByronHash),
334    Variant2(ByronHash, ByronHash),
335    Variant3(ByronHash),
336}
337
338impl<'b, C> minicbor::Decode<'b, C> for SscProof {
339    fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result<Self, minicbor::decode::Error> {
340        d.array()?;
341
342        let variant = d.u8()?;
343
344        match variant {
345            0 => Ok(SscProof::Variant0(d.decode_with(ctx)?, d.decode_with(ctx)?)),
346            1 => Ok(SscProof::Variant1(d.decode_with(ctx)?, d.decode_with(ctx)?)),
347            2 => Ok(SscProof::Variant2(d.decode_with(ctx)?, d.decode_with(ctx)?)),
348            3 => Ok(SscProof::Variant3(d.decode_with(ctx)?)),
349            _ => Err(minicbor::decode::Error::message(
350                "invalid variant for sscproof",
351            )),
352        }
353    }
354}
355
356impl<C> minicbor::Encode<C> for SscProof {
357    fn encode<W: minicbor::encode::Write>(
358        &self,
359        e: &mut minicbor::Encoder<W>,
360        ctx: &mut C,
361    ) -> Result<(), minicbor::encode::Error<W::Error>> {
362        match self {
363            SscProof::Variant0(a, b) => {
364                e.array(3)?;
365                e.u8(0)?;
366                e.encode_with(a, ctx)?;
367                e.encode_with(b, ctx)?;
368
369                Ok(())
370            }
371            SscProof::Variant1(a, b) => {
372                e.array(3)?;
373                e.u8(1)?;
374                e.encode_with(a, ctx)?;
375                e.encode_with(b, ctx)?;
376
377                Ok(())
378            }
379            SscProof::Variant2(a, b) => {
380                e.array(3)?;
381                e.u8(2)?;
382                e.encode_with(a, ctx)?;
383                e.encode_with(b, ctx)?;
384
385                Ok(())
386            }
387            SscProof::Variant3(x) => {
388                e.array(2)?;
389                e.u8(3)?;
390                e.encode_with(x, ctx)?;
391
392                Ok(())
393            }
394        }
395    }
396}
397
398// Delegation
399
400#[derive(Debug, Encode, Decode, Clone)]
401pub struct Dlg {
402    #[n(0)]
403    pub epoch: EpochId,
404
405    #[n(1)]
406    pub issuer: PubKey,
407
408    #[n(2)]
409    pub delegate: PubKey,
410
411    #[n(3)]
412    pub certificate: Signature,
413}
414
415pub type DlgSig = (Dlg, Signature);
416
417#[derive(Debug, Encode, Decode, Clone)]
418pub struct Lwdlg {
419    #[n(0)]
420    pub epoch_range: (EpochId, EpochId),
421
422    #[n(1)]
423    pub issuer: PubKey,
424
425    #[n(2)]
426    pub delegate: PubKey,
427
428    #[n(3)]
429    pub certificate: Signature,
430}
431
432pub type LwdlgSig = (Lwdlg, Signature);
433
434// Updates
435
436pub type BVer = (u16, u16, u8);
437
438#[derive(Debug, Clone)]
439pub enum TxFeePol {
440    //[0, #6.24(bytes .cbor ([bigint, bigint]))]
441    Variant0(CborWrap<(i64, i64)>),
442
443    // [u8 .gt 0, encoded-cbor]
444    Other(u8, ByteVec),
445}
446
447impl<'b, C> minicbor::Decode<'b, C> for TxFeePol {
448    fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result<Self, minicbor::decode::Error> {
449        d.array()?;
450
451        let variant = d.u8()?;
452
453        match variant {
454            0 => Ok(TxFeePol::Variant0(d.decode_with(ctx)?)),
455            x => Ok(TxFeePol::Other(x, d.decode_with(ctx)?)),
456        }
457    }
458}
459
460impl<C> minicbor::Encode<C> for TxFeePol {
461    fn encode<W: minicbor::encode::Write>(
462        &self,
463        e: &mut minicbor::Encoder<W>,
464        ctx: &mut C,
465    ) -> Result<(), minicbor::encode::Error<W::Error>> {
466        match self {
467            TxFeePol::Variant0(x) => {
468                e.array(2)?;
469                e.u8(0)?;
470                e.encode_with(x, ctx)?;
471
472                Ok(())
473            }
474            TxFeePol::Other(a, b) => {
475                e.array(2)?;
476                e.u8(*a)?;
477                e.encode_with(b, ctx)?;
478
479                Ok(())
480            }
481        }
482    }
483}
484
485#[derive(Debug, Encode, Decode, Clone)]
486pub struct BVerMod {
487    #[n(0)]
488    pub script_version: ZeroOrOneArray<u16>,
489
490    #[n(1)]
491    pub slot_duration: ZeroOrOneArray<u64>,
492
493    #[n(2)]
494    pub max_block_size: ZeroOrOneArray<u64>,
495
496    #[n(3)]
497    pub max_header_size: ZeroOrOneArray<u64>,
498
499    #[n(4)]
500    pub max_tx_size: ZeroOrOneArray<u64>,
501
502    #[n(5)]
503    pub max_proposal_size: ZeroOrOneArray<u64>,
504
505    #[n(6)]
506    pub mpc_thd: ZeroOrOneArray<u64>,
507
508    #[n(7)]
509    pub heavy_del_thd: ZeroOrOneArray<u64>,
510
511    #[n(8)]
512    pub update_vote_thd: ZeroOrOneArray<u64>,
513
514    #[n(9)]
515    pub update_proposal_thd: ZeroOrOneArray<u64>,
516
517    #[n(10)]
518    pub update_implicit: ZeroOrOneArray<u64>,
519
520    #[n(11)]
521    pub soft_fork_rule: ZeroOrOneArray<(u64, u64, u64)>,
522
523    #[n(12)]
524    pub tx_fee_policy: ZeroOrOneArray<TxFeePol>,
525
526    #[n(13)]
527    pub unlock_stake_epoch: ZeroOrOneArray<EpochId>,
528}
529
530pub type UpData = (ByronHash, ByronHash, ByronHash, ByronHash);
531
532#[derive(Debug, Encode, Decode, Clone)]
533pub struct UpProp {
534    #[n(0)]
535    pub block_version: Option<BVer>,
536
537    #[n(1)]
538    pub block_version_mod: Option<BVerMod>,
539
540    #[n(2)]
541    pub software_version: Option<(String, u32)>,
542
543    #[n(3)]
544    // HACK: CDDL show a tag wrap 258, but chain data doesn't present the tag
545    //pub data: TagWrap<(String, UpData), 258>,
546    pub data: KeyValuePairs<String, UpData>,
547
548    #[n(4)]
549    pub attributes: Option<Attributes>,
550
551    #[n(5)]
552    pub from: Option<PubKey>,
553
554    #[n(6)]
555    pub signature: Option<Signature>,
556}
557
558#[derive(Debug, Encode, Decode, Clone)]
559pub struct UpVote {
560    #[n(0)]
561    pub voter: PubKey,
562
563    #[n(1)]
564    pub proposal_id: UpdId,
565
566    #[n(2)]
567    pub vote: bool,
568
569    #[n(3)]
570    pub signature: Signature,
571}
572
573#[derive(Debug, Encode, Decode, Clone)]
574pub struct Up {
575    #[n(0)]
576    pub proposal: ZeroOrOneArray<UpProp>,
577
578    #[n(1)]
579    pub votes: MaybeIndefArray<UpVote>,
580}
581
582// Blocks
583
584pub type Difficulty = MaybeIndefArray<u64>;
585
586#[derive(Debug, Clone)]
587pub enum BlockSig {
588    Signature(Signature),
589    LwdlgSig(LwdlgSig),
590    DlgSig(DlgSig),
591}
592
593impl<'b, C> minicbor::Decode<'b, C> for BlockSig {
594    fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result<Self, minicbor::decode::Error> {
595        d.array()?;
596
597        let variant = d.u8()?;
598
599        match variant {
600            0 => Ok(BlockSig::Signature(d.decode_with(ctx)?)),
601            1 => Ok(BlockSig::LwdlgSig(d.decode_with(ctx)?)),
602            2 => Ok(BlockSig::DlgSig(d.decode_with(ctx)?)),
603            _ => Err(minicbor::decode::Error::message(
604                "unknown variant for blocksig",
605            )),
606        }
607    }
608}
609
610impl<C> minicbor::Encode<C> for BlockSig {
611    fn encode<W: minicbor::encode::Write>(
612        &self,
613        e: &mut minicbor::Encoder<W>,
614        _ctx: &mut C,
615    ) -> Result<(), minicbor::encode::Error<W::Error>> {
616        match self {
617            BlockSig::Signature(x) => {
618                e.array(2)?;
619                e.u8(0)?;
620                e.encode(x)?;
621
622                Ok(())
623            }
624            BlockSig::LwdlgSig(x) => {
625                e.array(2)?;
626                e.u8(1)?;
627                e.encode(x)?;
628
629                Ok(())
630            }
631            BlockSig::DlgSig(x) => {
632                e.array(2)?;
633                e.u8(2)?;
634                e.encode(x)?;
635
636                Ok(())
637            }
638        }
639    }
640}
641
642#[derive(Encode, Decode, Debug, Clone)]
643pub struct BlockCons(
644    #[n(0)] pub SlotId,
645    #[n(1)] pub PubKey,
646    #[n(2)] pub Difficulty,
647    #[n(3)] pub BlockSig,
648);
649
650#[derive(Encode, Decode, Debug, Clone)]
651pub struct BlockHeadEx {
652    #[n(0)]
653    pub block_version: BVer,
654
655    #[n(1)]
656    pub software_version: (String, u32),
657
658    #[n(2)]
659    pub attributes: Option<Attributes>,
660
661    #[n(3)]
662    pub extra_proof: ByronHash,
663}
664
665#[derive(Encode, Decode, Debug, Clone)]
666pub struct BlockProof {
667    #[n(0)]
668    pub tx_proof: TxProof,
669
670    #[n(1)]
671    pub ssc_proof: SscProof,
672
673    #[n(2)]
674    pub dlg_proof: ByronHash,
675
676    #[n(3)]
677    pub upd_proof: ByronHash,
678}
679
680#[derive(Encode, Decode, Debug, Clone)]
681pub struct BlockHead {
682    #[n(0)]
683    pub protocol_magic: u32,
684
685    #[n(1)]
686    pub prev_block: BlockId,
687
688    #[n(2)]
689    pub body_proof: BlockProof,
690
691    #[n(3)]
692    pub consensus_data: BlockCons,
693
694    #[n(4)]
695    pub extra_data: BlockHeadEx,
696}
697
698pub type Witnesses = MaybeIndefArray<Twit>;
699
700#[derive(Debug, Encode, Decode)]
701pub struct TxPayload {
702    #[n(0)]
703    pub transaction: Tx,
704
705    #[n(1)]
706    pub witness: Witnesses,
707}
708
709#[derive(Debug, Encode, Decode, Clone)]
710pub struct MintedTxPayload<'b> {
711    #[b(0)]
712    pub transaction: KeepRaw<'b, Tx>,
713
714    #[n(1)]
715    pub witness: KeepRaw<'b, Witnesses>,
716}
717
718#[derive(Encode, Decode, Debug)]
719pub struct BlockBody {
720    #[n(0)]
721    pub tx_payload: MaybeIndefArray<TxPayload>,
722
723    #[n(1)]
724    pub ssc_payload: Ssc,
725
726    #[n(2)]
727    pub dlg_payload: MaybeIndefArray<Dlg>,
728
729    #[n(3)]
730    pub upd_payload: Up,
731}
732
733#[derive(Encode, Decode, Debug, Clone)]
734pub struct MintedBlockBody<'b> {
735    #[b(0)]
736    pub tx_payload: MaybeIndefArray<MintedTxPayload<'b>>,
737
738    #[b(1)]
739    pub ssc_payload: Ssc,
740
741    #[b(2)]
742    pub dlg_payload: MaybeIndefArray<Dlg>,
743
744    #[b(3)]
745    pub upd_payload: Up,
746}
747
748// Epoch Boundary Blocks
749
750#[derive(Encode, Decode, Debug, Clone)]
751pub struct EbbCons {
752    #[n(0)]
753    pub epoch_id: EpochId,
754
755    #[n(1)]
756    pub difficulty: Difficulty,
757}
758
759#[derive(Encode, Decode, Debug, Clone)]
760pub struct EbbHead {
761    #[n(0)]
762    pub protocol_magic: u32,
763
764    #[n(1)]
765    pub prev_block: BlockId,
766
767    #[n(2)]
768    pub body_proof: ByronHash,
769
770    #[n(3)]
771    pub consensus_data: EbbCons,
772
773    #[n(4)]
774    pub extra_data: (Attributes,),
775}
776
777#[derive(Encode, Decode, Debug)]
778pub struct Block {
779    #[n(0)]
780    pub header: BlockHead,
781
782    #[n(1)]
783    pub body: BlockBody,
784
785    #[n(2)]
786    pub extra: MaybeIndefArray<Attributes>,
787}
788
789#[derive(Encode, Decode, Debug, Clone)]
790pub struct MintedBlock<'b> {
791    #[b(0)]
792    pub header: KeepRaw<'b, BlockHead>,
793
794    #[b(1)]
795    pub body: MintedBlockBody<'b>,
796
797    #[n(2)]
798    pub extra: MaybeIndefArray<Attributes>,
799}
800
801#[derive(Encode, Decode, Debug, Clone)]
802pub struct EbBlock {
803    #[n(0)]
804    pub header: EbbHead,
805
806    #[n(1)]
807    pub body: MaybeIndefArray<StakeholderId>,
808
809    #[n(2)]
810    pub extra: MaybeIndefArray<Attributes>,
811}
812
813#[derive(Encode, Decode, Debug, Clone)]
814pub struct MintedEbBlock<'b> {
815    #[b(0)]
816    pub header: KeepRaw<'b, EbbHead>,
817
818    #[n(1)]
819    pub body: MaybeIndefArray<StakeholderId>,
820
821    #[n(2)]
822    pub extra: MaybeIndefArray<Attributes>,
823}
824
825#[cfg(test)]
826mod tests {
827    use super::{BlockHead, EbBlock, MintedBlock};
828    use pallas_codec::minicbor::{self, to_vec};
829
830    #[test]
831    fn boundary_block_isomorphic_decoding_encoding() {
832        type BlockWrapper = (u16, EbBlock);
833
834        let test_blocks = [include_str!("../../../test_data/genesis.block")];
835
836        for (idx, block_str) in test_blocks.iter().enumerate() {
837            println!("decoding test block {}", idx + 1);
838            let bytes = hex::decode(block_str).unwrap_or_else(|_| panic!("bad block file {idx}"));
839
840            let block: BlockWrapper = minicbor::decode(&bytes[..])
841                .unwrap_or_else(|_| panic!("error decoding cbor for file {idx}"));
842
843            let bytes2 = to_vec(block)
844                .unwrap_or_else(|_| panic!("error encoding block cbor for file {idx}"));
845
846            assert_eq!(hex::encode(bytes), hex::encode(bytes2));
847        }
848    }
849
850    #[test]
851    fn main_block_isomorphic_decoding_encoding() {
852        type BlockWrapper<'b> = (u16, MintedBlock<'b>);
853
854        let test_blocks = [
855            //include_str!("../../../test_data/genesis.block"),
856            include_str!("../../../test_data/byron1.block"),
857            include_str!("../../../test_data/byron2.block"),
858            include_str!("../../../test_data/byron3.block"),
859            include_str!("../../../test_data/byron4.block"),
860            include_str!("../../../test_data/byron5.block"),
861            include_str!("../../../test_data/byron6.block"),
862            include_str!("../../../test_data/byron7.block"),
863            include_str!("../../../test_data/byron8.block"),
864        ];
865
866        for (idx, block_str) in test_blocks.iter().enumerate() {
867            println!("decoding test block {}", idx + 1);
868            let bytes = hex::decode(block_str).unwrap_or_else(|_| panic!("bad block file {idx}"));
869
870            let block: BlockWrapper = minicbor::decode(&bytes[..])
871                .unwrap_or_else(|_| panic!("error decoding cbor for file {idx}"));
872
873            let bytes2 = to_vec(block)
874                .unwrap_or_else(|_| panic!("error encoding block cbor for file {idx}"));
875
876            assert_eq!(hex::encode(bytes), hex::encode(bytes2));
877        }
878    }
879
880    #[test]
881    fn header_isomorphic_decoding_encoding() {
882        let subjects = [include_str!("../../../test_data/byron1.header")];
883
884        for (idx, str) in subjects.iter().enumerate() {
885            println!("decoding test header {}", idx + 1);
886            let bytes = hex::decode(str).unwrap_or_else(|_| panic!("bad header file {idx}"));
887
888            let block: BlockHead = minicbor::decode(&bytes[..])
889                .unwrap_or_else(|_| panic!("error decoding cbor for file {idx}"));
890
891            let bytes2 = to_vec(block)
892                .unwrap_or_else(|_| panic!("error encoding header cbor for file {idx}"));
893
894            assert_eq!(bytes, bytes2);
895        }
896    }
897}