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 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 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 const GENERAL_FORM_TAG: u64 = 102;
167
168 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 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 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 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 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 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 let mut serializer = Serializer::new_vec();
419 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 let v1_key_canonical_bytes = [0];
433 serializer.write_bytes(v1_key_canonical_bytes)?;
434 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 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#[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 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 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 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 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 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}