pallas_primitives/alonzo/
model.rs

1//! Ledger primitives and cbor codec for the Alonzo era
2//!
3//! Handcrafted, idiomatic rust artifacts based on based on the [Alonzo CDDL](https://github.com/input-output-hk/cardano-ledger/blob/master/eras/alonzo/test-suite/cddl-files/alonzo.cddl) file in IOHK repo.
4
5use serde::{Deserialize, Serialize};
6
7use pallas_codec::minicbor::{self, data::Tag, Decode, Encode};
8
9pub use crate::{
10    plutus_data::*, AddrKeyhash, AssetName, Bytes, Coin, CostModel, DatumHash, DnsName, Epoch,
11    ExUnitPrices, ExUnits, GenesisDelegateHash, Genesishash, Hash, IPv4, IPv6, Int, KeepRaw,
12    KeyValuePairs, MaybeIndefArray, Metadata, Metadatum, MetadatumLabel, NetworkId, Nonce,
13    NonceVariant, Nullable, PlutusScript, PolicyId, PoolKeyhash, PoolMetadata, PoolMetadataHash,
14    Port, PositiveInterval, ProtocolVersion, RationalNumber, Relay, RewardAccount, ScriptHash,
15    StakeCredential, TransactionIndex, TransactionInput, UnitInterval, VrfCert, VrfKeyhash,
16};
17
18#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
19pub struct HeaderBody {
20    #[n(0)]
21    pub block_number: u64,
22
23    #[n(1)]
24    pub slot: u64,
25
26    #[n(2)]
27    pub prev_hash: Option<Hash<32>>,
28
29    #[n(3)]
30    pub issuer_vkey: Bytes,
31
32    #[n(4)]
33    pub vrf_vkey: Bytes,
34
35    #[n(5)]
36    pub nonce_vrf: VrfCert,
37
38    #[n(6)]
39    pub leader_vrf: VrfCert,
40
41    #[n(7)]
42    pub block_body_size: u64,
43
44    #[n(8)]
45    pub block_body_hash: Hash<32>,
46
47    #[n(9)]
48    pub operational_cert_hot_vkey: Bytes,
49
50    #[n(10)]
51    pub operational_cert_sequence_number: u64,
52
53    #[n(11)]
54    pub operational_cert_kes_period: u64,
55
56    #[n(12)]
57    pub operational_cert_sigma: Bytes,
58
59    #[n(13)]
60    pub protocol_major: u64,
61
62    #[n(14)]
63    pub protocol_minor: u64,
64}
65
66pub type MintedHeaderBody<'a> = KeepRaw<'a, HeaderBody>;
67
68#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
69pub struct PseudoHeader<T1> {
70    #[n(0)]
71    pub header_body: T1,
72
73    #[n(1)]
74    pub body_signature: Bytes,
75}
76
77pub type Header = PseudoHeader<HeaderBody>;
78
79pub type MintedHeader<'a> = KeepRaw<'a, PseudoHeader<MintedHeaderBody<'a>>>;
80
81impl<'a> From<MintedHeader<'a>> for Header {
82    fn from(x: MintedHeader<'a>) -> Self {
83        let x = x.unwrap();
84        Self {
85            header_body: x.header_body.into(),
86            body_signature: x.body_signature,
87        }
88    }
89}
90
91impl<'a> From<MintedHeaderBody<'a>> for HeaderBody {
92    fn from(x: MintedHeaderBody<'a>) -> Self {
93        x.unwrap()
94    }
95}
96
97pub type Multiasset<A> = KeyValuePairs<PolicyId, KeyValuePairs<AssetName, A>>;
98
99pub type Mint = Multiasset<i64>;
100
101#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
102pub enum Value {
103    Coin(Coin),
104    Multiasset(Coin, Multiasset<Coin>),
105}
106
107impl<'b, C> minicbor::decode::Decode<'b, C> for Value {
108    fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result<Self, minicbor::decode::Error> {
109        match d.datatype()? {
110            minicbor::data::Type::U8 => Ok(Value::Coin(d.decode_with(ctx)?)),
111            minicbor::data::Type::U16 => Ok(Value::Coin(d.decode_with(ctx)?)),
112            minicbor::data::Type::U32 => Ok(Value::Coin(d.decode_with(ctx)?)),
113            minicbor::data::Type::U64 => Ok(Value::Coin(d.decode_with(ctx)?)),
114            minicbor::data::Type::Array => {
115                d.array()?;
116                let coin = d.decode_with(ctx)?;
117                let multiasset = d.decode_with(ctx)?;
118                Ok(Value::Multiasset(coin, multiasset))
119            }
120            _ => Err(minicbor::decode::Error::message(
121                "unknown cbor data type for Alonzo Value enum",
122            )),
123        }
124    }
125}
126
127impl<C> minicbor::encode::Encode<C> for Value {
128    fn encode<W: minicbor::encode::Write>(
129        &self,
130        e: &mut minicbor::Encoder<W>,
131        ctx: &mut C,
132    ) -> Result<(), minicbor::encode::Error<W::Error>> {
133        // TODO: check how to deal with uint variants (u32 vs u64)
134        match self {
135            Value::Coin(coin) => {
136                e.encode_with(coin, ctx)?;
137            }
138            Value::Multiasset(coin, other) => {
139                e.array(2)?;
140                e.encode_with(coin, ctx)?;
141                e.encode_with(other, ctx)?;
142            }
143        };
144
145        Ok(())
146    }
147}
148
149#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
150pub struct TransactionOutput {
151    #[n(0)]
152    pub address: Bytes,
153
154    #[n(1)]
155    pub amount: Value,
156
157    #[n(2)]
158    pub datum_hash: Option<DatumHash>,
159}
160
161/* move_instantaneous_reward = [ 0 / 1, { * stake_credential => delta_coin } / coin ]
162; The first field determines where the funds are drawn from.
163; 0 denotes the reserves, 1 denotes the treasury.
164; If the second field is a map, funds are moved to stake credentials,
165; otherwise the funds are given to the other accounting pot.
166 */
167
168#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
169pub enum InstantaneousRewardSource {
170    Reserves,
171    Treasury,
172}
173
174impl<'b, C> minicbor::decode::Decode<'b, C> for InstantaneousRewardSource {
175    fn decode(
176        d: &mut minicbor::Decoder<'b>,
177        _ctx: &mut C,
178    ) -> Result<Self, minicbor::decode::Error> {
179        let variant = d.u32()?;
180
181        match variant {
182            0 => Ok(Self::Reserves),
183            1 => Ok(Self::Treasury),
184            _ => Err(minicbor::decode::Error::message("invalid funds variant")),
185        }
186    }
187}
188
189impl<C> minicbor::encode::Encode<C> for InstantaneousRewardSource {
190    fn encode<W: minicbor::encode::Write>(
191        &self,
192        e: &mut minicbor::Encoder<W>,
193        _ctx: &mut C,
194    ) -> Result<(), minicbor::encode::Error<W::Error>> {
195        let variant = match self {
196            Self::Reserves => 0,
197            Self::Treasury => 1,
198        };
199
200        e.u32(variant)?;
201
202        Ok(())
203    }
204}
205
206#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
207pub enum InstantaneousRewardTarget {
208    StakeCredentials(KeyValuePairs<StakeCredential, i64>),
209    OtherAccountingPot(Coin),
210}
211
212impl<'b, C> minicbor::decode::Decode<'b, C> for InstantaneousRewardTarget {
213    fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result<Self, minicbor::decode::Error> {
214        let datatype = d.datatype()?;
215
216        match datatype {
217            minicbor::data::Type::Map | minicbor::data::Type::MapIndef => {
218                let a = d.decode_with(ctx)?;
219                Ok(Self::StakeCredentials(a))
220            }
221            _ => {
222                let a = d.decode_with(ctx)?;
223                Ok(Self::OtherAccountingPot(a))
224            }
225        }
226    }
227}
228
229impl<C> minicbor::encode::Encode<C> for InstantaneousRewardTarget {
230    fn encode<W: minicbor::encode::Write>(
231        &self,
232        e: &mut minicbor::Encoder<W>,
233        ctx: &mut C,
234    ) -> Result<(), minicbor::encode::Error<W::Error>> {
235        match self {
236            InstantaneousRewardTarget::StakeCredentials(a) => {
237                e.encode_with(a, ctx)?;
238                Ok(())
239            }
240            InstantaneousRewardTarget::OtherAccountingPot(a) => {
241                e.encode_with(a, ctx)?;
242                Ok(())
243            }
244        }
245    }
246}
247
248#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
249#[cbor()]
250pub struct MoveInstantaneousReward {
251    #[n(0)]
252    pub source: InstantaneousRewardSource,
253
254    #[n(1)]
255    pub target: InstantaneousRewardTarget,
256}
257
258pub type Withdrawals = KeyValuePairs<RewardAccount, Coin>;
259
260pub type RequiredSigners = Vec<AddrKeyhash>;
261
262#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
263pub enum Certificate {
264    StakeRegistration(StakeCredential),
265    StakeDeregistration(StakeCredential),
266    StakeDelegation(StakeCredential, PoolKeyhash),
267    PoolRegistration {
268        operator: PoolKeyhash,
269        vrf_keyhash: VrfKeyhash,
270        pledge: Coin,
271        cost: Coin,
272        margin: UnitInterval,
273        reward_account: RewardAccount,
274        pool_owners: Vec<AddrKeyhash>,
275        relays: Vec<Relay>,
276        pool_metadata: Nullable<PoolMetadata>,
277    },
278    PoolRetirement(PoolKeyhash, Epoch),
279    GenesisKeyDelegation(Genesishash, GenesisDelegateHash, VrfKeyhash),
280    MoveInstantaneousRewardsCert(MoveInstantaneousReward),
281}
282
283impl<'b, C> minicbor::decode::Decode<'b, C> for Certificate {
284    fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result<Self, minicbor::decode::Error> {
285        d.array()?;
286        let variant = d.u16()?;
287
288        match variant {
289            0 => {
290                let a = d.decode_with(ctx)?;
291                Ok(Certificate::StakeRegistration(a))
292            }
293            1 => {
294                let a = d.decode_with(ctx)?;
295                Ok(Certificate::StakeDeregistration(a))
296            }
297            2 => {
298                let a = d.decode_with(ctx)?;
299                let b = d.decode_with(ctx)?;
300                Ok(Certificate::StakeDelegation(a, b))
301            }
302            3 => {
303                let operator = d.decode_with(ctx)?;
304                let vrf_keyhash = d.decode_with(ctx)?;
305                let pledge = d.decode_with(ctx)?;
306                let cost = d.decode_with(ctx)?;
307                let margin = d.decode_with(ctx)?;
308                let reward_account = d.decode_with(ctx)?;
309                let pool_owners = d.decode_with(ctx)?;
310                let relays = d.decode_with(ctx)?;
311                let pool_metadata = d.decode_with(ctx)?;
312
313                Ok(Certificate::PoolRegistration {
314                    operator,
315                    vrf_keyhash,
316                    pledge,
317                    cost,
318                    margin,
319                    reward_account,
320                    pool_owners,
321                    relays,
322                    pool_metadata,
323                })
324            }
325            4 => {
326                let a = d.decode_with(ctx)?;
327                let b = d.decode_with(ctx)?;
328                Ok(Certificate::PoolRetirement(a, b))
329            }
330            5 => {
331                let a = d.decode_with(ctx)?;
332                let b = d.decode_with(ctx)?;
333                let c = d.decode_with(ctx)?;
334                Ok(Certificate::GenesisKeyDelegation(a, b, c))
335            }
336            6 => {
337                let a = d.decode_with(ctx)?;
338                Ok(Certificate::MoveInstantaneousRewardsCert(a))
339            }
340            _ => Err(minicbor::decode::Error::message(
341                "unknown variant id for certificate",
342            )),
343        }
344    }
345}
346
347impl<C> minicbor::encode::Encode<C> for Certificate {
348    fn encode<W: minicbor::encode::Write>(
349        &self,
350        e: &mut minicbor::Encoder<W>,
351        ctx: &mut C,
352    ) -> Result<(), minicbor::encode::Error<W::Error>> {
353        match self {
354            Certificate::StakeRegistration(a) => {
355                e.array(2)?;
356                e.u16(0)?;
357                e.encode_with(a, ctx)?;
358
359                Ok(())
360            }
361            Certificate::StakeDeregistration(a) => {
362                e.array(2)?;
363                e.u16(1)?;
364                e.encode_with(a, ctx)?;
365
366                Ok(())
367            }
368            Certificate::StakeDelegation(a, b) => {
369                e.array(3)?;
370                e.u16(2)?;
371                e.encode_with(a, ctx)?;
372                e.encode_with(b, ctx)?;
373
374                Ok(())
375            }
376            Certificate::PoolRegistration {
377                operator,
378                vrf_keyhash,
379                pledge,
380                cost,
381                margin,
382                reward_account,
383                pool_owners,
384                relays,
385                pool_metadata,
386            } => {
387                e.array(10)?;
388                e.u16(3)?;
389
390                e.encode_with(operator, ctx)?;
391                e.encode_with(vrf_keyhash, ctx)?;
392                e.encode_with(pledge, ctx)?;
393                e.encode_with(cost, ctx)?;
394                e.encode_with(margin, ctx)?;
395                e.encode_with(reward_account, ctx)?;
396                e.encode_with(pool_owners, ctx)?;
397                e.encode_with(relays, ctx)?;
398                e.encode_with(pool_metadata, ctx)?;
399
400                Ok(())
401            }
402            Certificate::PoolRetirement(a, b) => {
403                e.array(3)?;
404                e.u16(4)?;
405                e.encode_with(a, ctx)?;
406                e.encode_with(b, ctx)?;
407
408                Ok(())
409            }
410            Certificate::GenesisKeyDelegation(a, b, c) => {
411                e.array(4)?;
412                e.u16(5)?;
413                e.encode_with(a, ctx)?;
414                e.encode_with(b, ctx)?;
415                e.encode_with(c, ctx)?;
416
417                Ok(())
418            }
419            Certificate::MoveInstantaneousRewardsCert(a) => {
420                e.array(2)?;
421                e.u16(6)?;
422                e.encode_with(a, ctx)?;
423
424                Ok(())
425            }
426        }
427    }
428}
429
430#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
431#[cbor(index_only)]
432pub enum Language {
433    #[n(0)]
434    PlutusV1,
435}
436
437#[deprecated(since = "0.31.0", note = "use `CostModels` instead")]
438pub type CostMdls = CostModels;
439
440pub type CostModels = KeyValuePairs<Language, CostModel>;
441
442#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
443#[cbor(map)]
444pub struct ProtocolParamUpdate {
445    #[n(0)]
446    pub minfee_a: Option<u32>,
447    #[n(1)]
448    pub minfee_b: Option<u32>,
449    #[n(2)]
450    pub max_block_body_size: Option<u32>,
451    #[n(3)]
452    pub max_transaction_size: Option<u32>,
453    #[n(4)]
454    pub max_block_header_size: Option<u32>,
455    #[n(5)]
456    pub key_deposit: Option<Coin>,
457    #[n(6)]
458    pub pool_deposit: Option<Coin>,
459    #[n(7)]
460    pub maximum_epoch: Option<Epoch>,
461    #[n(8)]
462    pub desired_number_of_stake_pools: Option<u32>,
463    #[n(9)]
464    pub pool_pledge_influence: Option<RationalNumber>,
465    #[n(10)]
466    pub expansion_rate: Option<UnitInterval>,
467    #[n(11)]
468    pub treasury_growth_rate: Option<UnitInterval>,
469    #[n(12)]
470    pub decentralization_constant: Option<UnitInterval>,
471    #[n(13)]
472    pub extra_entropy: Option<Nonce>,
473    #[n(14)]
474    pub protocol_version: Option<ProtocolVersion>,
475    #[n(16)]
476    pub min_pool_cost: Option<Coin>,
477    #[n(17)]
478    pub ada_per_utxo_byte: Option<Coin>,
479    #[n(18)]
480    pub cost_models_for_script_languages: Option<CostModels>,
481    #[n(19)]
482    pub execution_costs: Option<ExUnitPrices>,
483    #[n(20)]
484    pub max_tx_ex_units: Option<ExUnits>,
485    #[n(21)]
486    pub max_block_ex_units: Option<ExUnits>,
487    #[n(22)]
488    pub max_value_size: Option<u32>,
489    #[n(23)]
490    pub collateral_percentage: Option<u32>,
491    #[n(24)]
492    pub max_collateral_inputs: Option<u32>,
493}
494
495#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
496pub struct Update {
497    #[n(0)]
498    pub proposed_protocol_parameter_updates: KeyValuePairs<Genesishash, ProtocolParamUpdate>,
499
500    #[n(1)]
501    pub epoch: Epoch,
502}
503
504// Can't derive encode for TransactionBody because it seems to require a very
505// particular order for each key in the map
506#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
507#[cbor(map)]
508pub struct TransactionBody {
509    #[n(0)]
510    pub inputs: Vec<TransactionInput>,
511
512    #[n(1)]
513    pub outputs: Vec<TransactionOutput>,
514
515    #[n(2)]
516    pub fee: u64,
517
518    #[n(3)]
519    pub ttl: Option<u64>,
520
521    #[n(4)]
522    pub certificates: Option<Vec<Certificate>>,
523
524    #[n(5)]
525    pub withdrawals: Option<Withdrawals>,
526
527    #[n(6)]
528    pub update: Option<Update>,
529
530    #[n(7)]
531    pub auxiliary_data_hash: Option<Bytes>,
532
533    #[n(8)]
534    pub validity_interval_start: Option<u64>,
535
536    #[n(9)]
537    pub mint: Option<Multiasset<i64>>,
538
539    #[n(11)]
540    pub script_data_hash: Option<Hash<32>>,
541
542    #[n(13)]
543    pub collateral: Option<Vec<TransactionInput>>,
544
545    #[n(14)]
546    pub required_signers: Option<RequiredSigners>,
547
548    #[n(15)]
549    pub network_id: Option<NetworkId>,
550}
551
552#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
553pub struct VKeyWitness {
554    #[n(0)]
555    pub vkey: Bytes,
556
557    #[n(1)]
558    pub signature: Bytes,
559}
560
561#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
562pub enum NativeScript {
563    ScriptPubkey(AddrKeyhash),
564    ScriptAll(Vec<NativeScript>),
565    ScriptAny(Vec<NativeScript>),
566    ScriptNOfK(u32, Vec<NativeScript>),
567    InvalidBefore(u64),
568    InvalidHereafter(u64),
569}
570
571impl<'b, C> minicbor::decode::Decode<'b, C> for NativeScript {
572    fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result<Self, minicbor::decode::Error> {
573        d.array()?;
574        let variant = d.u32()?;
575
576        match variant {
577            0 => Ok(NativeScript::ScriptPubkey(d.decode_with(ctx)?)),
578            1 => Ok(NativeScript::ScriptAll(d.decode_with(ctx)?)),
579            2 => Ok(NativeScript::ScriptAny(d.decode_with(ctx)?)),
580            3 => Ok(NativeScript::ScriptNOfK(
581                d.decode_with(ctx)?,
582                d.decode_with(ctx)?,
583            )),
584            4 => Ok(NativeScript::InvalidBefore(d.decode_with(ctx)?)),
585            5 => Ok(NativeScript::InvalidHereafter(d.decode_with(ctx)?)),
586            _ => Err(minicbor::decode::Error::message(
587                "unknown variant id for native script",
588            )),
589        }
590    }
591}
592
593impl<C> minicbor::encode::Encode<C> for NativeScript {
594    fn encode<W: minicbor::encode::Write>(
595        &self,
596        e: &mut minicbor::Encoder<W>,
597        ctx: &mut C,
598    ) -> Result<(), minicbor::encode::Error<W::Error>> {
599        e.array(2)?;
600
601        match self {
602            NativeScript::ScriptPubkey(v) => {
603                e.encode_with(0, ctx)?;
604                e.encode_with(v, ctx)?;
605            }
606            NativeScript::ScriptAll(v) => {
607                e.encode_with(1, ctx)?;
608                e.encode_with(v, ctx)?;
609            }
610            NativeScript::ScriptAny(v) => {
611                e.encode_with(2, ctx)?;
612                e.encode_with(v, ctx)?;
613            }
614            NativeScript::ScriptNOfK(a, b) => {
615                e.encode_with(3, ctx)?;
616                e.encode_with(a, ctx)?;
617                e.encode_with(b, ctx)?;
618            }
619            NativeScript::InvalidBefore(v) => {
620                e.encode_with(4, ctx)?;
621                e.encode_with(v, ctx)?;
622            }
623            NativeScript::InvalidHereafter(v) => {
624                e.encode_with(5, ctx)?;
625                e.encode_with(v, ctx)?;
626            }
627        }
628
629        Ok(())
630    }
631}
632
633#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone, Copy)]
634#[cbor(index_only)]
635pub enum RedeemerTag {
636    #[n(0)]
637    Spend,
638    #[n(1)]
639    Mint,
640    #[n(2)]
641    Cert,
642    #[n(3)]
643    Reward,
644}
645
646#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
647pub struct Redeemer {
648    #[n(0)]
649    pub tag: RedeemerTag,
650
651    #[n(1)]
652    pub index: u32,
653
654    #[n(2)]
655    pub data: PlutusData,
656
657    #[n(3)]
658    pub ex_units: ExUnits,
659}
660
661#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone, Copy)]
662pub struct RedeemerPointer {
663    #[n(0)]
664    pub tag: RedeemerTag,
665
666    #[n(1)]
667    pub index: u32,
668}
669
670/* bootstrap_witness =
671[ public_key : $vkey
672, signature  : $signature
673, chain_code : bytes .size 32
674, attributes : bytes
675] */
676
677#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
678pub struct BootstrapWitness {
679    #[n(0)]
680    pub public_key: Bytes,
681
682    #[n(1)]
683    pub signature: Bytes,
684
685    #[n(2)]
686    pub chain_code: Bytes,
687
688    #[n(3)]
689    pub attributes: Bytes,
690}
691
692#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Clone)]
693#[cbor(map)]
694pub struct WitnessSet {
695    #[n(0)]
696    pub vkeywitness: Option<Vec<VKeyWitness>>,
697
698    #[n(1)]
699    pub native_script: Option<Vec<NativeScript>>,
700
701    #[n(2)]
702    pub bootstrap_witness: Option<Vec<BootstrapWitness>>,
703
704    #[n(3)]
705    pub plutus_script: Option<Vec<PlutusScript<1>>>,
706
707    #[n(4)]
708    pub plutus_data: Option<Vec<PlutusData>>,
709
710    #[n(5)]
711    pub redeemer: Option<Vec<Redeemer>>,
712}
713
714#[derive(Encode, Decode, Debug, PartialEq, Clone)]
715#[cbor(map)]
716pub struct MintedWitnessSet<'b> {
717    #[n(0)]
718    pub vkeywitness: Option<Vec<VKeyWitness>>,
719
720    #[n(1)]
721    pub native_script: Option<Vec<KeepRaw<'b, NativeScript>>>,
722
723    #[n(2)]
724    pub bootstrap_witness: Option<Vec<BootstrapWitness>>,
725
726    #[n(3)]
727    pub plutus_script: Option<Vec<PlutusScript<1>>>,
728
729    #[b(4)]
730    pub plutus_data: Option<Vec<KeepRaw<'b, PlutusData>>>,
731
732    #[n(5)]
733    pub redeemer: Option<Vec<Redeemer>>,
734}
735
736impl<'b> From<MintedWitnessSet<'b>> for WitnessSet {
737    #[allow(deprecated)]
738    fn from(x: MintedWitnessSet<'b>) -> Self {
739        WitnessSet {
740            vkeywitness: x.vkeywitness,
741            native_script: x
742                .native_script
743                .map(|x| x.into_iter().map(|x| x.unwrap()).collect()),
744            bootstrap_witness: x.bootstrap_witness,
745            plutus_script: x.plutus_script,
746            plutus_data: x
747                .plutus_data
748                .map(|x| x.into_iter().map(|x| x.unwrap()).collect()),
749            redeemer: x.redeemer,
750        }
751    }
752}
753
754#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Clone)]
755#[cbor(map)]
756pub struct PostAlonzoAuxiliaryData {
757    #[n(0)]
758    pub metadata: Option<Metadata>,
759
760    #[n(1)]
761    pub native_scripts: Option<Vec<NativeScript>>,
762
763    #[n(2)]
764    pub plutus_scripts: Option<Vec<PlutusScript<1>>>,
765}
766
767#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Clone)]
768pub struct ShelleyMaAuxiliaryData {
769    #[n(0)]
770    pub transaction_metadata: Metadata,
771
772    #[n(1)]
773    pub auxiliary_scripts: Option<Vec<NativeScript>>,
774}
775
776#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
777pub enum AuxiliaryData {
778    Shelley(Metadata),
779    ShelleyMa(ShelleyMaAuxiliaryData),
780    PostAlonzo(PostAlonzoAuxiliaryData),
781}
782
783impl<'b, C> minicbor::Decode<'b, C> for AuxiliaryData {
784    fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result<Self, minicbor::decode::Error> {
785        match d.datatype()? {
786            minicbor::data::Type::Map | minicbor::data::Type::MapIndef => {
787                Ok(AuxiliaryData::Shelley(d.decode_with(ctx)?))
788            }
789            minicbor::data::Type::Array => Ok(AuxiliaryData::ShelleyMa(d.decode_with(ctx)?)),
790            minicbor::data::Type::Tag => {
791                d.tag()?;
792                Ok(AuxiliaryData::PostAlonzo(d.decode_with(ctx)?))
793            }
794            _ => Err(minicbor::decode::Error::message(
795                "Can't infer variant from data type for AuxiliaryData",
796            )),
797        }
798    }
799}
800
801impl<C> minicbor::Encode<C> for AuxiliaryData {
802    fn encode<W: minicbor::encode::Write>(
803        &self,
804        e: &mut minicbor::Encoder<W>,
805        ctx: &mut C,
806    ) -> Result<(), minicbor::encode::Error<W::Error>> {
807        match self {
808            AuxiliaryData::Shelley(m) => {
809                e.encode_with(m, ctx)?;
810            }
811            AuxiliaryData::ShelleyMa(m) => {
812                e.encode_with(m, ctx)?;
813            }
814            AuxiliaryData::PostAlonzo(v) => {
815                // TODO: check if this is the correct tag
816                e.tag(Tag::new(259))?;
817                e.encode_with(v, ctx)?;
818            }
819        };
820
821        Ok(())
822    }
823}
824
825#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Clone)]
826pub struct Block {
827    #[n(0)]
828    pub header: Header,
829
830    #[b(1)]
831    pub transaction_bodies: Vec<TransactionBody>,
832
833    #[n(2)]
834    pub transaction_witness_sets: Vec<WitnessSet>,
835
836    #[n(3)]
837    pub auxiliary_data_set: KeyValuePairs<TransactionIndex, AuxiliaryData>,
838
839    #[n(4)]
840    pub invalid_transactions: Option<Vec<TransactionIndex>>,
841}
842
843/// A memory representation of an already minted block
844///
845/// This structure is analogous to [Block], but it allows to retrieve the
846/// original CBOR bytes for each structure that might require hashing. In this
847/// way, we make sure that the resulting hash matches what exists on-chain.
848#[derive(Encode, Decode, Debug, PartialEq, Clone)]
849pub struct MintedBlock<'b> {
850    #[n(0)]
851    pub header: KeepRaw<'b, MintedHeader<'b>>,
852
853    #[b(1)]
854    pub transaction_bodies: MaybeIndefArray<KeepRaw<'b, TransactionBody>>,
855
856    #[n(2)]
857    pub transaction_witness_sets: MaybeIndefArray<KeepRaw<'b, MintedWitnessSet<'b>>>,
858
859    #[n(3)]
860    pub auxiliary_data_set: KeyValuePairs<TransactionIndex, KeepRaw<'b, AuxiliaryData>>,
861
862    #[n(4)]
863    pub invalid_transactions: Option<MaybeIndefArray<TransactionIndex>>,
864}
865
866impl<'b> From<MintedBlock<'b>> for Block {
867    fn from(x: MintedBlock<'b>) -> Self {
868        Block {
869            header: x.header.unwrap().into(),
870            transaction_bodies: x
871                .transaction_bodies
872                .to_vec()
873                .into_iter()
874                .map(|x| x.unwrap())
875                .collect(),
876            transaction_witness_sets: x
877                .transaction_witness_sets
878                .to_vec()
879                .into_iter()
880                .map(|x| x.unwrap())
881                .map(WitnessSet::from)
882                .collect(),
883            auxiliary_data_set: x
884                .auxiliary_data_set
885                .to_vec()
886                .into_iter()
887                .map(|(k, v)| (k, v.unwrap()))
888                .collect::<Vec<_>>()
889                .into(),
890            invalid_transactions: x.invalid_transactions.map(|x| x.into()),
891        }
892    }
893}
894
895#[derive(Serialize, Deserialize, Encode, Decode, Debug)]
896pub struct Tx {
897    #[n(0)]
898    pub transaction_body: TransactionBody,
899
900    #[n(1)]
901    pub transaction_witness_set: WitnessSet,
902
903    #[n(2)]
904    pub success: bool,
905
906    #[n(3)]
907    pub auxiliary_data: Nullable<AuxiliaryData>,
908}
909
910#[derive(Encode, Decode, Debug, Clone)]
911pub struct MintedTx<'b> {
912    #[b(0)]
913    pub transaction_body: KeepRaw<'b, TransactionBody>,
914
915    #[n(1)]
916    pub transaction_witness_set: KeepRaw<'b, MintedWitnessSet<'b>>,
917
918    #[n(2)]
919    pub success: bool,
920
921    #[n(3)]
922    pub auxiliary_data: Nullable<KeepRaw<'b, AuxiliaryData>>,
923}
924
925#[cfg(test)]
926mod tests {
927    use pallas_codec::minicbor::{self, to_vec};
928
929    use crate::{alonzo::PlutusData, Fragment};
930
931    use super::{Header, MintedBlock};
932
933    type BlockWrapper<'b> = (u16, MintedBlock<'b>);
934
935    #[test]
936    fn block_isomorphic_decoding_encoding() {
937        let test_blocks = vec![
938            include_str!("../../../test_data/alonzo1.block"),
939            include_str!("../../../test_data/alonzo2.block"),
940            include_str!("../../../test_data/alonzo3.block"),
941            include_str!("../../../test_data/alonzo4.block"),
942            include_str!("../../../test_data/alonzo5.block"),
943            include_str!("../../../test_data/alonzo6.block"),
944            include_str!("../../../test_data/alonzo7.block"),
945            include_str!("../../../test_data/alonzo8.block"),
946            include_str!("../../../test_data/alonzo9.block"),
947            // old block without invalid_transactions fields
948            include_str!("../../../test_data/alonzo10.block"),
949            // peculiar block with protocol update params
950            include_str!("../../../test_data/alonzo11.block"),
951            // peculiar block with decoding issue
952            // https://github.com/txpipe/oura/issues/37
953            include_str!("../../../test_data/alonzo12.block"),
954            // peculiar block with protocol update params, including nonce
955            include_str!("../../../test_data/alonzo13.block"),
956            // peculiar block with overflow crash
957            // https://github.com/txpipe/oura/issues/113
958            include_str!("../../../test_data/alonzo14.block"),
959            // peculiar block with many move-instantaneous-rewards certs
960            include_str!("../../../test_data/alonzo15.block"),
961            // peculiar block with protocol update values
962            include_str!("../../../test_data/alonzo16.block"),
963            // peculiar block with missing nonce hash
964            include_str!("../../../test_data/alonzo17.block"),
965            // peculiar block with strange AuxiliaryData variant
966            include_str!("../../../test_data/alonzo18.block"),
967            // peculiar block with strange AuxiliaryData variant
968            include_str!("../../../test_data/alonzo18.block"),
969            // peculiar block with nevative i64 overflow
970            include_str!("../../../test_data/alonzo19.block"),
971            // peculiar block with very BigInt in plutus code
972            include_str!("../../../test_data/alonzo20.block"),
973            // peculiar block with bad tx hash
974            include_str!("../../../test_data/alonzo21.block"),
975            // peculiar block with bad tx hash
976            include_str!("../../../test_data/alonzo22.block"),
977            // peculiar block with indef byte array in plutus data
978            include_str!("../../../test_data/alonzo23.block"),
979            // peculiar block with invalid address (pointer overflow)
980            include_str!("../../../test_data/alonzo27.block"),
981        ];
982
983        for (idx, block_str) in test_blocks.iter().enumerate() {
984            println!("decoding test block {}", idx + 1);
985            let bytes = hex::decode(block_str).unwrap_or_else(|_| panic!("bad block file {idx}"));
986
987            let block: BlockWrapper = minicbor::decode(&bytes[..])
988                .unwrap_or_else(|_| panic!("error decoding cbor for file {idx}"));
989
990            let bytes2 = to_vec(block)
991                .unwrap_or_else(|_| panic!("error encoding block cbor for file {idx}"));
992
993            assert!(bytes.eq(&bytes2), "re-encoded bytes didn't match original");
994        }
995    }
996
997    #[test]
998    fn header_isomorphic_decoding_encoding() {
999        let test_headers = [
1000            // peculiar alonzo header used as origin for a vasil devnet
1001            include_str!("../../../test_data/alonzo26.header"),
1002        ];
1003
1004        for (idx, header_str) in test_headers.iter().enumerate() {
1005            println!("decoding test header {}", idx + 1);
1006            let bytes = hex::decode(header_str).unwrap_or_else(|_| panic!("bad header file {idx}"));
1007
1008            let header: Header = minicbor::decode(&bytes[..])
1009                .unwrap_or_else(|_| panic!("error decoding cbor for file {idx}"));
1010
1011            let bytes2 = to_vec(header)
1012                .unwrap_or_else(|_| panic!("error encoding header cbor for file {idx}"));
1013
1014            assert!(bytes.eq(&bytes2), "re-encoded bytes didn't match original");
1015        }
1016    }
1017
1018    #[test]
1019    fn plutus_data_isomorphic_decoding_encoding() {
1020        let datas = [
1021            // unit = Constr 0 []
1022            "d87980",
1023            // pltmap = Map [(I 1, unit), (I 2, pltlist)]
1024            "a201d87980029f000102ff",
1025            // pltlist = List [I 0, I 1, I 2]
1026            "9f000102ff",
1027            // Constr 5 [pltmap, Constr 5 [Map [(pltmap, toData True), (pltlist, pltmap), (List [], List [I 1])], unit, toData (0, 1)]]
1028            "d87e9fa201d87980029f000102ffd87e9fa3a201d87980029f000102ffd87a809f000102ffa201d87980029f000102ff809f01ffd87980d8799f0001ffffff",
1029            // Constr 5 [List [], List [I 1], Map [], Map [(I 1, unit), (I 2, Constr 2 [I 2])]]
1030            "d87e9f809f01ffa0a201d8798002d87b9f02ffff",
1031            // B (B.replicate 32 105)
1032            "58206969696969696969696969696969696969696969696969696969696969696969",
1033            // B (B.replicate 67 105)
1034            "5f58406969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696943696969ff",
1035            // B B.empty
1036            "40"
1037        ];
1038        for data_hex in datas {
1039            let data_bytes = hex::decode(data_hex).unwrap();
1040            let data = PlutusData::decode_fragment(&data_bytes).unwrap();
1041            assert_eq!(data.encode_fragment().unwrap(), data_bytes);
1042        }
1043    }
1044}