cml_chain/plutus/
utils.rs

1use super::{CostModels, Language, LegacyRedeemer, RedeemerKey, RedeemerVal, Redeemers};
2use super::{ExUnits, PlutusData, PlutusV1Script, PlutusV2Script, PlutusV3Script};
3use crate::crypto::hash::{hash_script, ScriptHashNamespace};
4use crate::json::plutus_datums::{
5    decode_plutus_datum_to_json_value, encode_json_value_to_plutus_datum,
6    CardanoNodePlutusDatumSchema,
7};
8use crate::utils::BigInteger;
9use cbor_event::de::Deserializer;
10use cbor_event::se::Serializer;
11use cml_core::error::*;
12use cml_core::ordered_hash_map::OrderedHashMap;
13use cml_core::serialization::*;
14use cml_crypto::ScriptHash;
15use itertools::Itertools;
16use std::convert::{TryFrom, TryInto};
17use std::io::{BufRead, Seek, Write};
18
19impl serde::Serialize for PlutusData {
20    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
21    where
22        S: serde::Serializer,
23    {
24        let json_value =
25            decode_plutus_datum_to_json_value(self, CardanoNodePlutusDatumSchema::DetailedSchema)
26                .expect("DetailedSchema can represent everything");
27        serde_json::Value::from(json_value).serialize(serializer)
28    }
29}
30
31impl<'de> serde::de::Deserialize<'de> for PlutusData {
32    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
33    where
34        D: serde::de::Deserializer<'de>,
35    {
36        let serde_json_value =
37            <serde_json::Value as serde::de::Deserialize>::deserialize(deserializer)?;
38        let json_value = crate::json::json_serialize::Value::from(serde_json_value);
39        encode_json_value_to_plutus_datum(
40            json_value.clone(),
41            CardanoNodePlutusDatumSchema::DetailedSchema,
42        )
43        .map_err(|_e| {
44            serde::de::Error::invalid_value(
45                (&json_value).into(),
46                &"invalid plutus datum (cardano-node JSON format)",
47            )
48        })
49    }
50}
51
52impl schemars::JsonSchema for PlutusData {
53    fn schema_name() -> String {
54        String::from("PlutusData")
55    }
56
57    fn json_schema(_gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
58        schemars::schema::Schema::from(schemars::schema::SchemaObject::new_ref(
59            "PlutusData".to_owned(),
60        ))
61    }
62
63    fn is_referenceable() -> bool {
64        true
65    }
66}
67
68impl PlutusData {
69    /**
70     *  Convert to a Datum that will serialize equivalent to cardano-node's format
71     *
72     *  Please VERY STRONGLY consider using PlutusData::from_cbor_bytes() instead wherever possible.
73     * You should try to never rely on a tool encoding CBOR a certain way as there are many possible,
74     * and just because it matches with a specific datum, doesn't mean that a different datum won't differ.
75     * This is critical as that means the datum hash won't match.
76     * After creation a datum (or other hashable CBOR object) should only be treated as raw CBOR bytes,
77     * or through a type that respects its specific CBOR format e.g. CML's PlutusData::from_cbor_bytes()
78     *
79     *  This function is just here in case there's no possible way at all to create from CBOR bytes and
80     * thus cold only be constructed manually and then had this function called on it.
81     *
82     *  This is also the format that CSL and Lucid use
83     */
84    pub fn to_cardano_node_format(&self) -> Self {
85        match self {
86            Self::ConstrPlutusData(c) => Self::ConstrPlutusData(ConstrPlutusData {
87                alternative: c.alternative,
88                fields: c
89                    .fields
90                    .iter()
91                    .map(|datum| datum.to_cardano_node_format())
92                    .collect(),
93                encodings: Some(ConstrPlutusDataEncoding {
94                    len_encoding: LenEncoding::Indefinite,
95                    tag_encoding: None,
96                    alternative_encoding: None,
97                    fields_encoding: if c.fields.is_empty() {
98                        LenEncoding::Canonical
99                    } else {
100                        LenEncoding::Indefinite
101                    },
102                    prefer_compact: true,
103                }),
104            }),
105            Self::Bytes { bytes, .. } => Self::Bytes {
106                bytes: bytes.clone(),
107                bytes_encoding: StringEncoding::Canonical,
108            },
109            // canonical
110            Self::Integer(bigint) => Self::Integer(BigInteger::from(bigint.num.clone())),
111            Self::List { list, .. } => Self::List {
112                list: list
113                    .iter()
114                    .map(|datum| datum.to_cardano_node_format())
115                    .collect(),
116                list_encoding: if list.is_empty() {
117                    LenEncoding::Canonical
118                } else {
119                    LenEncoding::Indefinite
120                },
121            },
122            Self::Map(map) => Self::Map(PlutusMap {
123                entries: {
124                    let mut sorted_entries: Vec<_> = map
125                        .entries
126                        .iter()
127                        .map(|(k, v)| (k.to_cardano_node_format(), v.to_cardano_node_format()))
128                        .collect();
129                    sorted_entries.sort_by(|(a, _), (b, _)| a.cmp(b));
130                    sorted_entries
131                },
132                encoding: if map.entries.is_empty() {
133                    LenEncoding::Canonical
134                } else {
135                    LenEncoding::Indefinite
136                },
137            }),
138        }
139    }
140}
141
142#[derive(
143    Clone, Debug, serde::Deserialize, serde::Serialize, schemars::JsonSchema, derivative::Derivative,
144)]
145#[derivative(Eq, PartialEq, Ord, PartialOrd, Hash)]
146pub struct ConstrPlutusData {
147    pub alternative: u64,
148    pub fields: Vec<PlutusData>,
149    #[derivative(
150        PartialEq = "ignore",
151        Ord = "ignore",
152        PartialOrd = "ignore",
153        Hash = "ignore"
154    )]
155    #[serde(skip)]
156    pub encodings: Option<ConstrPlutusDataEncoding>,
157}
158
159impl ConstrPlutusData {
160    // see: https://github.com/input-output-hk/plutus/blob/1f31e640e8a258185db01fa899da63f9018c0e85/plutus-core/plutus-core/src/PlutusCore/Data.hs#L61
161    // We don't directly serialize the alternative in the tag, instead the scheme is:
162    // - Alternatives 0-6 -> tags 121-127, followed by the arguments in a list
163    // - Alternatives 7-127 -> tags 1280-1400, followed by the arguments in a list
164    // - Any alternatives, including those that don't fit in the above -> tag 102 followed by a list containing
165    //   an unsigned integer for the actual alternative, and then the arguments in a (nested!) list.
166    const GENERAL_FORM_TAG: u64 = 102;
167
168    // None -> needs general tag serialization, not compact
169    fn alternative_to_compact_cbor_tag(alt: u64) -> Option<u64> {
170        if alt <= 6 {
171            Some(121 + alt)
172        } else if (7..=127).contains(&alt) {
173            Some(1280 - 7 + alt)
174        } else {
175            None
176        }
177    }
178
179    // None -> General tag(=102) OR Invalid CBOR tag for this scheme
180    fn compact_cbor_tag_to_alternative(cbor_tag: u64) -> Option<u64> {
181        if (121..=127).contains(&cbor_tag) {
182            Some(cbor_tag - 121)
183        } else if (1280..=1400).contains(&cbor_tag) {
184            Some(cbor_tag - 1280 + 7)
185        } else {
186            None
187        }
188    }
189
190    pub fn new(alternative: u64, fields: Vec<PlutusData>) -> Self {
191        Self {
192            alternative,
193            fields,
194            encodings: None,
195        }
196    }
197}
198
199#[derive(Clone, Debug, Default)]
200pub struct ConstrPlutusDataEncoding {
201    pub len_encoding: LenEncoding,
202    pub tag_encoding: Option<cbor_event::Sz>,
203    pub alternative_encoding: Option<cbor_event::Sz>,
204    pub fields_encoding: LenEncoding,
205    pub prefer_compact: bool,
206}
207
208impl Serialize for ConstrPlutusData {
209    fn serialize<'se, W: Write>(
210        &self,
211        serializer: &'se mut Serializer<W>,
212        force_canonical: bool,
213    ) -> cbor_event::Result<&'se mut Serializer<W>> {
214        match Self::alternative_to_compact_cbor_tag(self.alternative) {
215            Some(compact_tag)
216                if self
217                    .encodings
218                    .as_ref()
219                    .map(|encs| encs.prefer_compact)
220                    .unwrap_or(true) =>
221            {
222                // compact form
223                serializer.write_tag_sz(
224                    compact_tag,
225                    fit_sz(
226                        compact_tag,
227                        self.encodings
228                            .as_ref()
229                            .map(|encs| encs.tag_encoding)
230                            .unwrap_or_default(),
231                        force_canonical,
232                    ),
233                )?;
234                serializer.write_array_sz(
235                    self.encodings
236                        .as_ref()
237                        .map(|encs| encs.fields_encoding)
238                        .unwrap_or_default()
239                        .to_len_sz(self.fields.len() as u64, force_canonical),
240                )?;
241                for element in self.fields.iter() {
242                    element.serialize(serializer, force_canonical)?;
243                }
244                self.encodings
245                    .as_ref()
246                    .map(|encs| encs.fields_encoding)
247                    .unwrap_or_default()
248                    .end(serializer, force_canonical)
249            }
250            _ => {
251                // general form
252                serializer.write_tag_sz(
253                    Self::GENERAL_FORM_TAG,
254                    fit_sz(
255                        Self::GENERAL_FORM_TAG,
256                        self.encodings
257                            .as_ref()
258                            .map(|encs| encs.tag_encoding)
259                            .unwrap_or_default(),
260                        force_canonical,
261                    ),
262                )?;
263                serializer.write_array_sz(
264                    self.encodings
265                        .as_ref()
266                        .map(|encs| encs.len_encoding)
267                        .unwrap_or_default()
268                        .to_len_sz(2, force_canonical),
269                )?;
270                serializer.write_unsigned_integer_sz(
271                    self.alternative,
272                    fit_sz(
273                        self.alternative,
274                        self.encodings
275                            .as_ref()
276                            .map(|encs| encs.alternative_encoding)
277                            .unwrap_or_default(),
278                        force_canonical,
279                    ),
280                )?;
281                serializer.write_array_sz(
282                    self.encodings
283                        .as_ref()
284                        .map(|encs| encs.fields_encoding)
285                        .unwrap_or_default()
286                        .to_len_sz(self.fields.len() as u64, force_canonical),
287                )?;
288                for element in self.fields.iter() {
289                    element.serialize(serializer, force_canonical)?;
290                }
291                self.encodings
292                    .as_ref()
293                    .map(|encs| encs.fields_encoding)
294                    .unwrap_or_default()
295                    .end(serializer, force_canonical)?;
296                self.encodings
297                    .as_ref()
298                    .map(|encs| encs.len_encoding)
299                    .unwrap_or_default()
300                    .end(serializer, force_canonical)
301            }
302        }
303    }
304}
305
306impl Deserialize for ConstrPlutusData {
307    fn deserialize<R: BufRead + Seek>(raw: &mut Deserializer<R>) -> Result<Self, DeserializeError> {
308        (|| -> Result<_, DeserializeError> {
309            let (tag, tag_encoding) = raw.tag_sz()?;
310            match tag {
311                // general form
312                Self::GENERAL_FORM_TAG => {
313                    let len = raw.array_sz()?;
314                    let len_encoding: LenEncoding = len.into();
315                    let mut read_len = CBORReadLen::new(len);
316                    read_len.read_elems(2)?;
317                    let (alternative, alternative_encoding) = raw
318                        .unsigned_integer_sz()
319                        .map(|(x, enc)| (x, Some(enc)))
320                        .map_err(Into::<DeserializeError>::into)
321                        .map_err(|e: DeserializeError| e.annotate("alternative"))?;
322                    let (fields, fields_encoding) = (|| -> Result<_, DeserializeError> {
323                        let mut fields_arr = Vec::new();
324                        let len = raw.array_sz()?;
325                        let fields_encoding = len.into();
326                        while match len {
327                            cbor_event::LenSz::Len(n, _) => (fields_arr.len() as u64) < n,
328                            cbor_event::LenSz::Indefinite => true,
329                        } {
330                            if raw.cbor_type()? == cbor_event::Type::Special {
331                                assert_eq!(raw.special()?, cbor_event::Special::Break);
332                                break;
333                            }
334                            fields_arr.push(PlutusData::deserialize(raw)?);
335                        }
336                        Ok((fields_arr, fields_encoding))
337                    })()
338                    .map_err(|e| e.annotate("fields"))?;
339                    match len {
340                        cbor_event::LenSz::Len(_, _) => (),
341                        cbor_event::LenSz::Indefinite => match raw.special()? {
342                            cbor_event::Special::Break => (),
343                            _ => return Err(DeserializeFailure::EndingBreakMissing.into()),
344                        },
345                    }
346                    Ok(ConstrPlutusData {
347                        alternative,
348                        fields,
349                        encodings: Some(ConstrPlutusDataEncoding {
350                            len_encoding,
351                            tag_encoding: Some(tag_encoding),
352                            alternative_encoding,
353                            fields_encoding,
354                            prefer_compact: false,
355                        }),
356                    })
357                }
358                // concise form
359                tag => {
360                    if let Some(alternative) = Self::compact_cbor_tag_to_alternative(tag) {
361                        let (fields, fields_encoding) = (|| -> Result<_, DeserializeError> {
362                            let mut fields_arr = Vec::new();
363                            let len = raw.array_sz()?;
364                            let fields_encoding = len.into();
365                            while match len {
366                                cbor_event::LenSz::Len(n, _) => (fields_arr.len() as u64) < n,
367                                cbor_event::LenSz::Indefinite => true,
368                            } {
369                                if raw.cbor_type()? == cbor_event::Type::Special {
370                                    assert_eq!(raw.special()?, cbor_event::Special::Break);
371                                    break;
372                                }
373                                fields_arr.push(PlutusData::deserialize(raw)?);
374                            }
375                            Ok((fields_arr, fields_encoding))
376                        })()
377                        .map_err(|e| e.annotate("fields"))?;
378                        Ok(ConstrPlutusData {
379                            alternative,
380                            fields,
381                            encodings: Some(ConstrPlutusDataEncoding {
382                                len_encoding: LenEncoding::default(),
383                                tag_encoding: Some(tag_encoding),
384                                alternative_encoding: None,
385                                fields_encoding,
386                                prefer_compact: true,
387                            }),
388                        })
389                    } else {
390                        Err(DeserializeFailure::TagMismatch {
391                            found: tag,
392                            expected: Self::GENERAL_FORM_TAG,
393                        }
394                        .into())
395                    }
396                }
397            }
398        })()
399        .map_err(|e| e.annotate("ConstrPlutusData"))
400    }
401}
402
403impl CostModels {
404    pub(crate) fn language_views_encoding(&self) -> Result<Vec<u8>, cbor_event::Error> {
405        // ; language views CDDL:
406        // ; { * language => script_integrity_data }
407        // ;
408        // ; This must be encoded canonically, using the same scheme as in
409        // ; RFC7049 section 3.9:
410        // ;  - Maps, strings, and bytestrings must use a definite-length encoding
411        // ;  - Integers must be as small as possible.
412        // ;  - The expressions for map length, string length, and bytestring length
413        // ;    must be as short as possible.
414        // ;  - The keys in the map must be sorted as follows:
415        // ;     -  If two keys have different lengths, the shorter one sorts earlier.
416        // ;     -  If two keys have the same length, the one with the lower value
417        // ;        in (byte-wise) lexical order sorts earlier.
418        let mut serializer = Serializer::new_vec();
419        // as canonical encodings are used, we odn't need to check the keys' bytes encodings
420        // and can order this statically.
421        // Due to PlutusV1 bug we can't re-use the generated serialization code
422        // as it requires it to be encoded as CBOR bytes in CBOR
423        serializer.write_map(cbor_event::Len::Len(self.inner.len() as u64))?;
424        for (language, costs) in self.inner.iter() {
425            match (*language).try_into() {
426                Ok(Language::PlutusV1) => {
427                    // For PlutusV1 (language id 0), the language view is the following:
428                    //   * the value of costmdls map at key 0 is encoded as an indefinite length
429                    //     list and the result is encoded as a bytestring. (our apologies)
430                    //   * the language ID tag is also encoded twice. first as a uint then as
431                    //     a bytestring. (our apologies)
432                    let v1_key_canonical_bytes = [0];
433                    serializer.write_bytes(v1_key_canonical_bytes)?;
434                    // Due to a bug in the cardano-node input-output-hk/cardano-ledger-specs/issues/2512
435                    // we must use indefinite length serialization in this inner bytestring to match it
436                    let mut cost_model_serializer = Serializer::new_vec();
437                    cost_model_serializer.write_array(cbor_event::Len::Indefinite)?;
438                    for cost in costs {
439                        if *cost >= 0 {
440                            cost_model_serializer.write_unsigned_integer(cost.unsigned_abs())?;
441                        } else {
442                            cost_model_serializer.write_negative_integer(*cost)?;
443                        }
444                    }
445                    cost_model_serializer.write_special(cbor_event::Special::Break)?;
446                    serializer.write_bytes(cost_model_serializer.finalize())?;
447                }
448                _ => {
449                    // For PlutusV2 (language id 1), the language view is the following:
450                    //    * the value of costmdls map at key 1 is encoded as an definite length list.
451                    // For PlutusV3 (language id 2), the language view is the following:
452                    //   * the value of costmdls map at key 2 is encoded as a definite length list.
453                    //
454                    // We will assume all other languages also follow this and that the non-canonical
455                    // encoding is just a bug pertaining to Plutus V1
456                    serializer.write_unsigned_integer(*language)?;
457                    serializer.write_array(cbor_event::Len::Len(costs.len() as u64))?;
458                    for cost in costs {
459                        if *cost >= 0 {
460                            serializer.write_unsigned_integer(cost.unsigned_abs())?;
461                        } else {
462                            serializer.write_negative_integer(*cost)?;
463                        }
464                    }
465                }
466            }
467        }
468        Ok(serializer.finalize())
469    }
470}
471
472impl AsRef<OrderedHashMap<u64, Vec<i64>>> for CostModels {
473    fn as_ref(&self) -> &OrderedHashMap<u64, Vec<i64>> {
474        &self.inner
475    }
476}
477
478impl AsMut<OrderedHashMap<u64, Vec<i64>>> for CostModels {
479    fn as_mut(&mut self) -> &mut OrderedHashMap<u64, Vec<i64>> {
480        &mut self.inner
481    }
482}
483
484/// Version-agnostic Plutus script
485#[derive(Clone, Debug)]
486pub enum PlutusScript {
487    PlutusV1(PlutusV1Script),
488    PlutusV2(PlutusV2Script),
489    PlutusV3(PlutusV3Script),
490}
491
492impl PlutusScript {
493    pub fn hash(&self) -> ScriptHash {
494        match &self {
495            Self::PlutusV1(script) => script.hash(),
496            Self::PlutusV2(script) => script.hash(),
497            Self::PlutusV3(script) => script.hash(),
498        }
499    }
500
501    pub fn version(&self) -> Language {
502        match self {
503            Self::PlutusV1(_) => Language::PlutusV1,
504            Self::PlutusV2(_) => Language::PlutusV2,
505            Self::PlutusV3(_) => Language::PlutusV3,
506        }
507    }
508}
509
510impl From<PlutusV1Script> for PlutusScript {
511    fn from(script: PlutusV1Script) -> Self {
512        Self::PlutusV1(script)
513    }
514}
515
516impl From<PlutusV2Script> for PlutusScript {
517    fn from(script: PlutusV2Script) -> Self {
518        Self::PlutusV2(script)
519    }
520}
521
522impl From<PlutusV3Script> for PlutusScript {
523    fn from(script: PlutusV3Script) -> Self {
524        Self::PlutusV3(script)
525    }
526}
527
528impl PlutusV1Script {
529    pub fn hash(&self) -> ScriptHash {
530        hash_script(ScriptHashNamespace::PlutusV1, self.to_raw_bytes())
531    }
532}
533
534impl PlutusV2Script {
535    pub fn hash(&self) -> ScriptHash {
536        hash_script(ScriptHashNamespace::PlutusV2, self.to_raw_bytes())
537    }
538}
539
540impl PlutusV3Script {
541    pub fn hash(&self) -> ScriptHash {
542        hash_script(ScriptHashNamespace::PlutusV3, self.to_raw_bytes())
543    }
544}
545
546impl RawBytesEncoding for PlutusV1Script {
547    fn to_raw_bytes(&self) -> &[u8] {
548        self.inner.as_ref()
549    }
550
551    fn from_raw_bytes(bytes: &[u8]) -> Result<Self, DeserializeError> {
552        Ok(Self::new(bytes.to_vec()))
553    }
554}
555
556impl RawBytesEncoding for PlutusV2Script {
557    fn to_raw_bytes(&self) -> &[u8] {
558        self.inner.as_ref()
559    }
560
561    fn from_raw_bytes(bytes: &[u8]) -> Result<Self, DeserializeError> {
562        Ok(Self::new(bytes.to_vec()))
563    }
564}
565
566impl RawBytesEncoding for PlutusV3Script {
567    fn to_raw_bytes(&self) -> &[u8] {
568        self.inner.as_ref()
569    }
570
571    fn from_raw_bytes(bytes: &[u8]) -> Result<Self, DeserializeError> {
572        Ok(Self::new(bytes.to_vec()))
573    }
574}
575
576impl ExUnits {
577    pub fn checked_add(&self, other: &ExUnits) -> Result<ExUnits, ArithmeticError> {
578        let mem = self
579            .mem
580            .checked_add(other.mem)
581            .ok_or(ArithmeticError::IntegerOverflow)?;
582        let step = self
583            .steps
584            .checked_add(other.steps)
585            .ok_or(ArithmeticError::IntegerOverflow)?;
586        Ok(ExUnits::new(mem, step))
587    }
588
589    /// used to create a dummy ExUnits that takes up the maximum size possible in cbor to provide an upper bound on tx size
590    pub fn dummy() -> ExUnits {
591        ExUnits::new(u64::MAX, u64::MAX)
592    }
593}
594
595pub fn compute_total_ex_units(redeemers: &[LegacyRedeemer]) -> Result<ExUnits, ArithmeticError> {
596    let mut sum = ExUnits::new(0, 0);
597    for redeemer in redeemers {
598        sum = sum.checked_add(&redeemer.ex_units)?;
599    }
600    Ok(sum)
601}
602
603impl TryFrom<u64> for Language {
604    type Error = DeserializeError;
605
606    fn try_from(language: u64) -> Result<Self, Self::Error> {
607        match language {
608            0 => Ok(Language::PlutusV1),
609            1 => Ok(Language::PlutusV2),
610            2 => Ok(Language::PlutusV3),
611            _ => Err(DeserializeFailure::OutOfRange {
612                found: language as usize,
613                min: 0,
614                max: 2,
615            }
616            .into()),
617        }
618    }
619}
620
621impl From<Language> for u64 {
622    fn from(language: Language) -> u64 {
623        match language {
624            Language::PlutusV1 => 0,
625            Language::PlutusV2 => 1,
626            Language::PlutusV3 => 2,
627        }
628    }
629}
630
631#[derive(Clone, Debug, Default, derivative::Derivative)]
632#[derivative(Eq, PartialEq, Ord, PartialOrd, Hash)]
633pub struct PlutusMap {
634    // possibly duplicates (very rare - only found on testnet)
635    pub entries: Vec<(PlutusData, PlutusData)>,
636    #[derivative(
637        PartialEq = "ignore",
638        Ord = "ignore",
639        PartialOrd = "ignore",
640        Hash = "ignore"
641    )]
642    pub encoding: LenEncoding,
643}
644
645impl PlutusMap {
646    pub fn new() -> Self {
647        Self::default()
648    }
649
650    pub fn len(&self) -> usize {
651        self.entries.len()
652    }
653
654    pub fn is_empty(&self) -> bool {
655        self.entries.is_empty()
656    }
657
658    /// Replaces all datums of a given key, if any exist.
659    pub fn set(&mut self, key: PlutusData, value: PlutusData) {
660        self.entries.retain(|(k, _)| *k != key);
661        self.entries.push((key, value));
662    }
663
664    /// Gets the plutus datum corresponding to a given key, if it exists.
665    /// Note: In the case of duplicate keys this only returns the first datum.
666    /// This is an extremely rare occurence on-chain but can happen.
667    pub fn get(&self, key: &PlutusData) -> Option<&PlutusData> {
668        self.entries
669            .iter()
670            .find(|(k, _)| *k == *key)
671            .map(|(_, value)| value)
672    }
673
674    /// In the extremely unlikely situation there are duplicate keys, this gets all of a single key
675    pub fn get_all(&self, key: &PlutusData) -> Option<Vec<&PlutusData>> {
676        let matches = self
677            .entries
678            .iter()
679            .filter_map(|(k, v)| if *k == *key { Some(v) } else { None })
680            .collect::<Vec<_>>();
681        if matches.is_empty() {
682            None
683        } else {
684            Some(matches)
685        }
686    }
687}
688
689impl Serialize for PlutusMap {
690    fn serialize<'se, W: Write>(
691        &self,
692        serializer: &'se mut Serializer<W>,
693        force_canonical: bool,
694    ) -> cbor_event::Result<&'se mut Serializer<W>> {
695        serializer.write_map_sz(
696            self.encoding
697                .to_len_sz(self.entries.len() as u64, force_canonical),
698        )?;
699        let mut key_order = self
700            .entries
701            .iter()
702            .map(|(k, v)| {
703                let mut buf = cbor_event::se::Serializer::new_vec();
704                k.serialize(&mut buf, force_canonical)?;
705                Ok((buf.finalize(), k, v))
706            })
707            .collect::<Result<Vec<(Vec<u8>, &_, &_)>, cbor_event::Error>>()?;
708        if force_canonical {
709            key_order.sort_by(|(lhs_bytes, _, _), (rhs_bytes, _, _)| {
710                match lhs_bytes.len().cmp(&rhs_bytes.len()) {
711                    std::cmp::Ordering::Equal => lhs_bytes.cmp(rhs_bytes),
712                    diff_ord => diff_ord,
713                }
714            });
715        }
716        for (key_bytes, _key, value) in key_order {
717            serializer.write_raw_bytes(&key_bytes)?;
718            value.serialize(serializer, force_canonical)?;
719        }
720        self.encoding.end(serializer, force_canonical)
721    }
722}
723
724impl Deserialize for PlutusMap {
725    fn deserialize<R: BufRead + Seek>(raw: &mut Deserializer<R>) -> Result<Self, DeserializeError> {
726        (|| -> Result<_, DeserializeError> {
727            let mut entries = Vec::new();
728            let map_len = raw.map_sz()?;
729            let encoding = map_len.into();
730            while match map_len {
731                cbor_event::LenSz::Len(n, _) => (entries.len() as u64) < n,
732                cbor_event::LenSz::Indefinite => true,
733            } {
734                if raw.cbor_type()? == cbor_event::Type::Special {
735                    assert_eq!(raw.special()?, cbor_event::Special::Break);
736                    break;
737                }
738                let map_key = PlutusData::deserialize(raw)?;
739                let map_value = PlutusData::deserialize(raw)?;
740                entries.push((map_key, map_value));
741            }
742            Ok(Self { entries, encoding })
743        })()
744        .map_err(|e| e.annotate("PlutusMap"))
745    }
746}
747
748impl Redeemers {
749    pub fn to_flat_format(self) -> Vec<LegacyRedeemer> {
750        match self {
751            Self::ArrLegacyRedeemer {
752                arr_legacy_redeemer,
753                ..
754            } => arr_legacy_redeemer,
755            Self::MapRedeemerKeyToRedeemerVal {
756                map_redeemer_key_to_redeemer_val,
757                ..
758            } => map_redeemer_key_to_redeemer_val
759                .iter()
760                .map(|(k, v)| {
761                    LegacyRedeemer::new(k.tag, k.index, v.data.clone(), v.ex_units.clone())
762                })
763                .collect_vec(),
764        }
765    }
766
767    pub fn to_map_format(self) -> OrderedHashMap<RedeemerKey, RedeemerVal> {
768        match self {
769            Self::ArrLegacyRedeemer {
770                arr_legacy_redeemer,
771                ..
772            } => arr_legacy_redeemer
773                .into_iter()
774                .map(|r| {
775                    (
776                        RedeemerKey::new(r.tag, r.index),
777                        RedeemerVal::new(r.data, r.ex_units),
778                    )
779                })
780                .collect(),
781            Self::MapRedeemerKeyToRedeemerVal {
782                map_redeemer_key_to_redeemer_val,
783                ..
784            } => map_redeemer_key_to_redeemer_val,
785        }
786    }
787
788    pub fn is_empty(&self) -> bool {
789        match self {
790            Self::ArrLegacyRedeemer {
791                arr_legacy_redeemer,
792                ..
793            } => arr_legacy_redeemer.is_empty(),
794            Self::MapRedeemerKeyToRedeemerVal {
795                map_redeemer_key_to_redeemer_val,
796                ..
797            } => map_redeemer_key_to_redeemer_val.is_empty(),
798        }
799    }
800
801    pub fn extend(&mut self, other: Self) {
802        match self {
803            Self::ArrLegacyRedeemer {
804                arr_legacy_redeemer,
805                ..
806            } => arr_legacy_redeemer.extend(other.to_flat_format()),
807            Self::MapRedeemerKeyToRedeemerVal {
808                map_redeemer_key_to_redeemer_val,
809                ..
810            } => {
811                for (k, v) in other.to_map_format().take() {
812                    map_redeemer_key_to_redeemer_val.insert(k, v);
813                }
814            }
815        }
816    }
817}
818
819#[cfg(test)]
820mod tests {
821    use crate::plutus::{CostModels, Language};
822
823    #[test]
824    pub fn test_cost_model() {
825        let v1_costs = vec![
826            197209, 0, 1, 1, 396231, 621, 0, 1, 150000, 1000, 0, 1, 150000, 32, 2477736, 29175, 4,
827            29773, 100, 29773, 100, 29773, 100, 29773, 100, 29773, 100, 29773, 100, 100, 100,
828            29773, 100, 150000, 32, 150000, 32, 150000, 32, 150000, 1000, 0, 1, 150000, 32, 150000,
829            1000, 0, 8, 148000, 425507, 118, 0, 1, 1, 150000, 1000, 0, 8, 150000, 112536, 247, 1,
830            150000, 10000, 1, 136542, 1326, 1, 1000, 150000, 1000, 1, 150000, 32, 150000, 32,
831            150000, 32, 1, 1, 150000, 1, 150000, 4, 103599, 248, 1, 103599, 248, 1, 145276, 1366,
832            1, 179690, 497, 1, 150000, 32, 150000, 32, 150000, 32, 150000, 32, 150000, 32, 150000,
833            32, 148000, 425507, 118, 0, 1, 1, 61516, 11218, 0, 1, 150000, 32, 148000, 425507, 118,
834            0, 1, 1, 148000, 425507, 118, 0, 1, 1, 2477736, 29175, 4, 0, 82363, 4, 150000, 5000, 0,
835            1, 150000, 32, 197209, 0, 1, 1, 150000, 32, 150000, 32, 150000, 32, 150000, 32, 150000,
836            32, 150000, 32, 150000, 32, 3345831, 1, 1,
837        ];
838        let mut cms = CostModels::default();
839        cms.inner.insert(Language::PlutusV1.into(), v1_costs);
840        assert_eq!(
841            hex::encode(cms.language_views_encoding().unwrap()),
842            "a141005901d59f1a000302590001011a00060bc719026d00011a000249f01903e800011a000249f018201a0025cea81971f70419744d186419744d186419744d186419744d186419744d186419744d18641864186419744d18641a000249f018201a000249f018201a000249f018201a000249f01903e800011a000249f018201a000249f01903e800081a000242201a00067e2318760001011a000249f01903e800081a000249f01a0001b79818f7011a000249f0192710011a0002155e19052e011903e81a000249f01903e8011a000249f018201a000249f018201a000249f0182001011a000249f0011a000249f0041a000194af18f8011a000194af18f8011a0002377c190556011a0002bdea1901f1011a000249f018201a000249f018201a000249f018201a000249f018201a000249f018201a000249f018201a000242201a00067e23187600010119f04c192bd200011a000249f018201a000242201a00067e2318760001011a000242201a00067e2318760001011a0025cea81971f704001a000141bb041a000249f019138800011a000249f018201a000302590001011a000249f018201a000249f018201a000249f018201a000249f018201a000249f018201a000249f018201a000249f018201a00330da70101ff"
843        );
844    }
845}