griffin_core/uplc/
ast.rs

1use crate::pallas_addresses::{Network, ShelleyAddress, ShelleyDelegationPart, ShelleyPaymentPart};
2use crate::pallas_primitives::{
3    alonzo::{self, Constr, PlutusData},
4    conway::{self, Language},
5};
6use crate::pallas_traverse::ComputeHash;
7use crate::uplc::{
8    builtins::DefaultFunction,
9    debruijn::{self, Converter},
10    flat::Binder,
11    machine::{
12        cost_model::{initialize_cost_model, CostModel, ExBudget},
13        eval_result::EvalResult,
14        Machine,
15    },
16    optimize::interner::CodeGenInterner,
17};
18use alloc::{
19    borrow::ToOwned,
20    boxed::Box,
21    rc::Rc,
22    string::{String, ToString},
23    vec::Vec,
24};
25use core::{
26    fmt::Display,
27    hash::{self, Hash},
28};
29use num_bigint::BigInt;
30use num_traits::ToPrimitive;
31use serde::{
32    self,
33    de::{self, Deserialize, Deserializer, MapAccess, Visitor},
34    ser::{Serialize, SerializeStruct, Serializer},
35};
36
37/// This represents a program in Untyped Plutus Core.
38/// A program contains a version tuple and a term.
39/// It is generic because Term requires a generic type.
40#[derive(Debug, Clone, PartialEq)]
41pub struct Program<T> {
42    pub version: (usize, usize, usize),
43    pub term: Term<T>,
44}
45
46impl<T> Program<T>
47where
48    T: Clone,
49{
50    /// We use this to apply the validator to Datum,
51    /// then redeemer, then ScriptContext. If datum is
52    /// even necessary (i.e. minting policy).
53    pub fn apply(&self, program: &Self) -> Self {
54        let applied_term = Term::Apply {
55            function: Rc::new(self.term.clone()),
56            argument: Rc::new(program.term.clone()),
57        };
58
59        Program {
60            version: self.version,
61            term: applied_term,
62        }
63    }
64
65    /// A convenient and faster version that `apply_term` since the program doesn't need to be
66    /// re-interned (constant Data do not introduce new bindings).
67    pub fn apply_data(&self, plutus_data: PlutusData) -> Self {
68        let applied_term = Term::Apply {
69            function: Rc::new(self.term.clone()),
70            argument: Rc::new(Term::Constant(Constant::Data(plutus_data).into())),
71        };
72
73        Program {
74            version: self.version,
75            term: applied_term,
76        }
77    }
78}
79
80impl Program<Name> {
81    /// We use this to apply the validator to Datum,
82    /// then redeemer, then ScriptContext. If datum is
83    /// even necessary (i.e. minting policy).
84    pub fn apply_term(&self, term: &Term<Name>) -> Self {
85        let applied_term = Term::Apply {
86            function: Rc::new(self.term.clone()),
87            argument: Rc::new(term.clone()),
88        };
89
90        let mut program = Program {
91            version: self.version,
92            term: applied_term,
93        };
94
95        CodeGenInterner::new().program(&mut program);
96
97        program
98    }
99
100    /// A convenient method to convery named programs to debruijn programs.
101    pub fn to_debruijn(self) -> Result<Program<DeBruijn>, debruijn::Error> {
102        self.try_into()
103    }
104
105    /// A convenient method to convery named programs to named debruijn programs.
106    pub fn to_named_debruijn(self) -> Result<Program<NamedDeBruijn>, debruijn::Error> {
107        self.try_into()
108    }
109}
110
111impl<'a, T> Display for Program<T>
112where
113    T: Binder<'a>,
114{
115    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
116        write!(f, "{}", self)
117    }
118}
119
120#[derive(Debug, Clone, PartialEq)]
121pub enum SerializableProgram {
122    PlutusV1Program(Program<DeBruijn>),
123    PlutusV2Program(Program<DeBruijn>),
124    PlutusV3Program(Program<DeBruijn>),
125}
126
127impl SerializableProgram {
128    pub fn inner(&self) -> &Program<DeBruijn> {
129        use SerializableProgram::*;
130
131        match self {
132            PlutusV1Program(program) => program,
133            PlutusV2Program(program) => program,
134            PlutusV3Program(program) => program,
135        }
136    }
137
138    pub fn map<F>(self, f: F) -> Self
139    where
140        F: FnOnce(Program<DeBruijn>) -> Program<DeBruijn>,
141    {
142        use SerializableProgram::*;
143
144        match self {
145            PlutusV1Program(program) => PlutusV1Program(f(program)),
146            PlutusV2Program(program) => PlutusV2Program(f(program)),
147            PlutusV3Program(program) => PlutusV3Program(f(program)),
148        }
149    }
150
151    pub fn compiled_code_and_hash(&self) -> (String, crate::pallas_crypto::hash::Hash<28>) {
152        use SerializableProgram::*;
153
154        match self {
155            PlutusV1Program(pgrm) => {
156                let cbor = pgrm.to_cbor().unwrap();
157                let compiled_code = hex::encode(&cbor);
158                let hash = conway::PlutusScript::<1>(cbor.into()).compute_hash();
159                (compiled_code, hash)
160            }
161
162            PlutusV2Program(pgrm) => {
163                let cbor = pgrm.to_cbor().unwrap();
164                let compiled_code = hex::encode(&cbor);
165                let hash = conway::PlutusScript::<2>(cbor.into()).compute_hash();
166                (compiled_code, hash)
167            }
168
169            PlutusV3Program(pgrm) => {
170                let cbor = pgrm.to_cbor().unwrap();
171                let compiled_code = hex::encode(&cbor);
172                let hash = conway::PlutusScript::<3>(cbor.into()).compute_hash();
173                (compiled_code, hash)
174            }
175        }
176    }
177}
178
179impl Serialize for SerializableProgram {
180    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
181        let (compiled_code, hash) = self.compiled_code_and_hash();
182        let mut s = serializer.serialize_struct("Program<DeBruijn>", 2)?;
183        s.serialize_field("compiledCode", &compiled_code)?;
184        s.serialize_field("hash", &hash)?;
185        s.end()
186    }
187}
188
189impl<'a> Deserialize<'a> for SerializableProgram {
190    fn deserialize<D: Deserializer<'a>>(deserializer: D) -> Result<Self, D::Error> {
191        #[derive(serde::Deserialize)]
192        #[serde(field_identifier, rename_all = "camelCase")]
193        enum Fields {
194            CompiledCode,
195            Hash,
196        }
197
198        struct ProgramVisitor;
199
200        impl<'a> Visitor<'a> for ProgramVisitor {
201            type Value = SerializableProgram;
202
203            fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
204                formatter.write_str("validator")
205            }
206
207            fn visit_map<V>(self, mut map: V) -> Result<SerializableProgram, V::Error>
208            where
209                V: MapAccess<'a>,
210            {
211                let mut compiled_code: Option<String> = None;
212                let mut hash: Option<String> = None;
213                while let Some(key) = map.next_key()? {
214                    match key {
215                        Fields::CompiledCode => {
216                            if compiled_code.is_some() {
217                                return Err(de::Error::duplicate_field("compiledCode"));
218                            }
219                            compiled_code = Some(map.next_value()?);
220                        }
221
222                        Fields::Hash => {
223                            if hash.is_some() {
224                                return Err(de::Error::duplicate_field("hash"));
225                            }
226                            hash = Some(map.next_value()?);
227                        }
228                    }
229                }
230                let compiled_code =
231                    compiled_code.ok_or_else(|| de::Error::missing_field("compiledCode"))?;
232
233                let hash = hash.ok_or_else(|| de::Error::missing_field("hash"))?;
234
235                let mut cbor_buffer = Vec::new();
236                let mut flat_buffer = Vec::new();
237
238                Program::<DeBruijn>::from_hex(&compiled_code, &mut cbor_buffer, &mut flat_buffer)
239                    .map_err(|e| {
240                        de::Error::invalid_value(
241                            de::Unexpected::Other(&format!("{e}")),
242                            &"a base16-encoded CBOR-serialized UPLC program",
243                        )
244                    })
245                    .and_then(|program| {
246                        let cbor = || program.to_cbor().unwrap().into();
247
248                        if conway::PlutusScript::<3>(cbor()).compute_hash().to_string() == hash {
249                            return Ok(SerializableProgram::PlutusV3Program(program));
250                        }
251
252                        if conway::PlutusScript::<2>(cbor()).compute_hash().to_string() == hash {
253                            return Ok(SerializableProgram::PlutusV2Program(program));
254                        }
255
256                        if conway::PlutusScript::<1>(cbor()).compute_hash().to_string() == hash {
257                            return Ok(SerializableProgram::PlutusV1Program(program));
258                        }
259
260                        Err(de::Error::custom(
261                            "hash doesn't match any recognisable Plutus version.",
262                        ))
263                    })
264            }
265        }
266
267        const FIELDS: &[&str] = &["compiledCode", "hash"];
268        deserializer.deserialize_struct("Program<DeBruijn>", FIELDS, ProgramVisitor)
269    }
270}
271
272impl Program<DeBruijn> {
273    pub fn address(
274        &self,
275        network: Network,
276        delegation: ShelleyDelegationPart,
277        plutus_version: &Language,
278    ) -> ShelleyAddress {
279        let cbor = self.to_cbor().unwrap();
280
281        let validator_hash = match plutus_version {
282            Language::PlutusV1 => conway::PlutusScript::<1>(cbor.into()).compute_hash(),
283            Language::PlutusV2 => conway::PlutusScript::<2>(cbor.into()).compute_hash(),
284            Language::PlutusV3 => conway::PlutusScript::<3>(cbor.into()).compute_hash(),
285        };
286
287        ShelleyAddress::new(
288            network,
289            ShelleyPaymentPart::Script(validator_hash),
290            delegation,
291        )
292    }
293}
294
295/// This represents a term in Untyped Plutus Core.
296/// We need a generic type for the different forms that a program may be in.
297/// Specifically, `Var` and `parameter_name` in `Lambda` can be a `Name`,
298/// `NamedDebruijn`, or `DeBruijn`. When encoded to flat for on chain usage
299/// we must encode using the `DeBruijn` form.
300#[derive(Debug, Clone, PartialEq)]
301pub enum Term<T> {
302    // tag: 0
303    Var(Rc<T>),
304    // tag: 1
305    Delay(Rc<Term<T>>),
306    // tag: 2
307    Lambda {
308        parameter_name: Rc<T>,
309        body: Rc<Term<T>>,
310    },
311    // tag: 3
312    Apply {
313        function: Rc<Term<T>>,
314        argument: Rc<Term<T>>,
315    },
316    // tag: 4
317    Constant(Rc<Constant>),
318    // tag: 5
319    Force(Rc<Term<T>>),
320    // tag: 6
321    Error,
322    // tag: 7
323    Builtin(DefaultFunction),
324    Constr {
325        tag: usize,
326        fields: Vec<Term<T>>,
327    },
328    Case {
329        constr: Rc<Term<T>>,
330        branches: Vec<Term<T>>,
331    },
332}
333
334impl<T> Term<T> {
335    pub fn is_unit(&self) -> bool {
336        matches!(self, Term::Constant(c) if c.as_ref() == &Constant::Unit)
337    }
338
339    pub fn is_int(&self) -> bool {
340        matches!(self, Term::Constant(c) if matches!(c.as_ref(), &Constant::Integer(_)))
341    }
342}
343
344impl<T> TryInto<PlutusData> for Term<T> {
345    type Error = String;
346
347    fn try_into(self) -> Result<PlutusData, String> {
348        match self {
349            Term::Constant(rc) => match &*rc {
350                Constant::Data(data) => Ok(data.to_owned()),
351                _ => Err("not a data".to_string()),
352            },
353            _ => Err("not a data".to_string()),
354        }
355    }
356}
357
358impl<'a, T> Display for Term<T>
359where
360    T: Binder<'a>,
361{
362    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
363        write!(f, "{}", self)
364    }
365}
366
367/// A container for the various constants that are available
368/// in Untyped Plutus Core. Used in the `Constant` variant of `Term`.
369#[derive(Debug, Clone, PartialEq)]
370pub enum Constant {
371    // tag: 0
372    Integer(BigInt),
373    // tag: 1
374    ByteString(Vec<u8>),
375    // tag: 2
376    String(String),
377    // tag: 3
378    Unit,
379    // tag: 4
380    Bool(bool),
381    // tag: 5
382    ProtoList(Type, Vec<Constant>),
383    // tag: 6
384    ProtoPair(Type, Type, Rc<Constant>, Rc<Constant>),
385    // tag: 7
386    // Apply(Box<Constant>, Type),
387    // tag: 8
388    Data(PlutusData),
389    Bls12_381G1Element(Box<blst::blst_p1>),
390    Bls12_381G2Element(Box<blst::blst_p2>),
391    Bls12_381MlResult(Box<blst::blst_fp12>),
392}
393
394pub struct Data;
395
396// TODO: See about moving these builders upstream to Pallas?
397impl Data {
398    pub fn to_hex(data: PlutusData) -> String {
399        let mut bytes = Vec::new();
400        crate::pallas_codec::minicbor::Encoder::new(&mut bytes)
401            .encode(data)
402            .expect("failed to encode Plutus Data as cbor?");
403        hex::encode(bytes)
404    }
405    pub fn integer(i: BigInt) -> PlutusData {
406        match i.to_i128().map(|n| n.try_into()) {
407            Some(Ok(i)) => PlutusData::BigInt(alonzo::BigInt::Int(i)),
408            _ => {
409                let (sign, bytes) = i.to_bytes_be();
410                match sign {
411                    num_bigint::Sign::Minus => {
412                        PlutusData::BigInt(alonzo::BigInt::BigNInt(bytes.into()))
413                    }
414                    _ => PlutusData::BigInt(alonzo::BigInt::BigUInt(bytes.into())),
415                }
416            }
417        }
418    }
419
420    pub fn bytestring(bytes: Vec<u8>) -> PlutusData {
421        PlutusData::BoundedBytes(bytes.into())
422    }
423
424    pub fn map(kvs: Vec<(PlutusData, PlutusData)>) -> PlutusData {
425        PlutusData::Map(kvs.into())
426    }
427
428    pub fn list(xs: Vec<PlutusData>) -> PlutusData {
429        PlutusData::Array(if xs.is_empty() {
430            conway::MaybeIndefArray::Def(xs)
431        } else {
432            conway::MaybeIndefArray::Indef(xs)
433        })
434    }
435
436    pub fn constr(ix: u64, fields: Vec<PlutusData>) -> PlutusData {
437        let fields = if fields.is_empty() {
438            conway::MaybeIndefArray::Def(fields)
439        } else {
440            conway::MaybeIndefArray::Indef(fields)
441        };
442
443        // NOTE: see https://github.com/input-output-hk/plutus/blob/9538fc9829426b2ecb0628d352e2d7af96ec8204/plutus-core/plutus-core/src/PlutusCore/Data.hs#L139-L155
444        if ix < 7 {
445            PlutusData::Constr(Constr {
446                tag: 121 + ix,
447                any_constructor: None,
448                fields,
449            })
450        } else if ix < 128 {
451            PlutusData::Constr(Constr {
452                tag: 1280 + ix - 7,
453                any_constructor: None,
454                fields,
455            })
456        } else {
457            PlutusData::Constr(Constr {
458                tag: 102,
459                any_constructor: Some(ix),
460                fields,
461            })
462        }
463    }
464}
465
466#[derive(Debug, Clone, PartialEq)]
467pub enum Type {
468    Bool,
469    Integer,
470    String,
471    ByteString,
472    Unit,
473    List(Rc<Type>),
474    Pair(Rc<Type>, Rc<Type>),
475    Data,
476    Bls12_381G1Element,
477    Bls12_381G2Element,
478    Bls12_381MlResult,
479}
480
481impl Display for Type {
482    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
483        match self {
484            Type::Bool => write!(f, "bool"),
485            Type::Integer => write!(f, "integer"),
486            Type::String => write!(f, "string"),
487            Type::ByteString => write!(f, "bytestring"),
488            Type::Unit => write!(f, "unit"),
489            Type::List(t) => write!(f, "list {t}"),
490            Type::Pair(t1, t2) => write!(f, "pair {t1} {t2}"),
491            Type::Data => write!(f, "data"),
492            Type::Bls12_381G1Element => write!(f, "bls12_381_G1_element"),
493            Type::Bls12_381G2Element => write!(f, "bls12_381_G2_element"),
494            Type::Bls12_381MlResult => write!(f, "bls12_381_mlresult"),
495        }
496    }
497}
498
499/// A Name containing it's parsed textual representation
500/// and a unique id from string interning. The Name's text is
501/// interned during parsing.
502#[derive(Debug, Clone, Eq)]
503pub struct Name {
504    pub text: String,
505    pub unique: Unique,
506}
507
508impl Name {
509    pub fn text(t: impl ToString) -> Name {
510        Name {
511            text: t.to_string(),
512            unique: 0.into(),
513        }
514    }
515}
516
517impl hash::Hash for Name {
518    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
519        self.text.hash(state);
520        self.unique.hash(state);
521    }
522}
523
524impl PartialEq for Name {
525    fn eq(&self, other: &Self) -> bool {
526        self.unique == other.unique && self.text == other.text
527    }
528}
529
530/// A unique id used for string interning.
531#[derive(Debug, Clone, PartialEq, Copy, Eq, Hash)]
532pub struct Unique(isize);
533
534impl Unique {
535    /// Create a new unique id.
536    pub fn new(unique: isize) -> Self {
537        Unique(unique)
538    }
539
540    /// Increment the available unique id. This is used during
541    /// string interning to get the next available unique id.
542    pub fn increment(&mut self) {
543        self.0 += 1;
544    }
545}
546
547impl From<isize> for Unique {
548    fn from(i: isize) -> Self {
549        Unique(i)
550    }
551}
552
553impl From<Unique> for isize {
554    fn from(d: Unique) -> Self {
555        d.0
556    }
557}
558
559impl Display for Unique {
560    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
561        write!(f, "{}", self.0)
562    }
563}
564
565/// Similar to `Name` but for Debruijn indices.
566/// `Name` is replaced by `NamedDebruijn` when converting
567/// program to it's debruijn form.
568#[derive(Debug, Clone, Eq)]
569pub struct NamedDeBruijn {
570    pub text: String,
571    pub index: DeBruijn,
572}
573
574impl PartialEq for NamedDeBruijn {
575    fn eq(&self, other: &Self) -> bool {
576        self.index == other.index
577    }
578}
579
580/// This is useful for decoding a on chain program into debruijn form.
581/// It allows for injecting fake textual names while also using Debruijn for decoding
582/// without having to loop through twice.
583#[derive(Debug, Clone)]
584pub struct FakeNamedDeBruijn(pub(crate) NamedDeBruijn);
585
586impl From<DeBruijn> for FakeNamedDeBruijn {
587    fn from(d: DeBruijn) -> Self {
588        FakeNamedDeBruijn(d.into())
589    }
590}
591
592impl From<FakeNamedDeBruijn> for DeBruijn {
593    fn from(d: FakeNamedDeBruijn) -> Self {
594        d.0.into()
595    }
596}
597
598impl From<FakeNamedDeBruijn> for NamedDeBruijn {
599    fn from(d: FakeNamedDeBruijn) -> Self {
600        d.0
601    }
602}
603
604impl From<NamedDeBruijn> for FakeNamedDeBruijn {
605    fn from(d: NamedDeBruijn) -> Self {
606        FakeNamedDeBruijn(d)
607    }
608}
609
610/// Represents a debruijn index.
611#[derive(Debug, Clone, PartialEq, Eq, Copy)]
612pub struct DeBruijn(usize);
613
614impl DeBruijn {
615    /// Create a new debruijn index.
616    pub fn new(index: usize) -> Self {
617        DeBruijn(index)
618    }
619
620    pub fn inner(&self) -> usize {
621        self.0
622    }
623}
624
625impl From<usize> for DeBruijn {
626    fn from(i: usize) -> Self {
627        DeBruijn(i)
628    }
629}
630
631impl From<DeBruijn> for usize {
632    fn from(d: DeBruijn) -> Self {
633        d.0
634    }
635}
636
637impl Display for DeBruijn {
638    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
639        write!(f, "{}", self.0)
640    }
641}
642
643impl From<NamedDeBruijn> for DeBruijn {
644    fn from(n: NamedDeBruijn) -> Self {
645        n.index
646    }
647}
648
649impl From<DeBruijn> for NamedDeBruijn {
650    fn from(index: DeBruijn) -> Self {
651        NamedDeBruijn {
652            // Inject fake name. We got `i` from the Plutus code base.
653            text: String::from("i"),
654            index,
655        }
656    }
657}
658
659/// Convert a Parsed `Program` to a `Program` in `NamedDebruijn` form.
660/// This checks for any Free Uniques in the `Program` and returns an error if found.
661impl TryFrom<Program<Name>> for Program<NamedDeBruijn> {
662    type Error = debruijn::Error;
663
664    fn try_from(value: Program<Name>) -> Result<Self, Self::Error> {
665        Ok(Program::<NamedDeBruijn> {
666            version: value.version,
667            term: value.term.try_into()?,
668        })
669    }
670}
671
672/// Convert a Parsed `Term` to a `Term` in `NamedDebruijn` form.
673/// This checks for any Free Uniques in the `Term` and returns an error if found.
674impl TryFrom<Term<Name>> for Term<NamedDeBruijn> {
675    type Error = debruijn::Error;
676
677    fn try_from(value: Term<Name>) -> Result<Self, debruijn::Error> {
678        let mut converter = Converter::new();
679
680        let term = converter.name_to_named_debruijn(&value)?;
681
682        Ok(term)
683    }
684}
685
686/// Convert a Parsed `Program` to a `Program` in `Debruijn` form.
687/// This checks for any Free Uniques in the `Program` and returns an error if found.
688impl TryFrom<Program<Name>> for Program<DeBruijn> {
689    type Error = debruijn::Error;
690
691    fn try_from(value: Program<Name>) -> Result<Self, Self::Error> {
692        Ok(Program::<DeBruijn> {
693            version: value.version,
694            term: value.term.try_into()?,
695        })
696    }
697}
698
699/// Convert a Parsed `Term` to a `Term` in `Debruijn` form.
700/// This checks for any Free Uniques in the `Program` and returns an error if found.
701impl TryFrom<Term<Name>> for Term<DeBruijn> {
702    type Error = debruijn::Error;
703
704    fn try_from(value: Term<Name>) -> Result<Self, debruijn::Error> {
705        let mut converter = Converter::new();
706
707        let term = converter.name_to_debruijn(&value)?;
708
709        Ok(term)
710    }
711}
712
713impl TryFrom<&Program<DeBruijn>> for Program<Name> {
714    type Error = debruijn::Error;
715
716    fn try_from(value: &Program<DeBruijn>) -> Result<Self, Self::Error> {
717        Ok(Program::<Name> {
718            version: value.version,
719            term: (&value.term).try_into()?,
720        })
721    }
722}
723
724impl TryFrom<&Term<DeBruijn>> for Term<Name> {
725    type Error = debruijn::Error;
726
727    fn try_from(value: &Term<DeBruijn>) -> Result<Self, debruijn::Error> {
728        let mut converter = Converter::new();
729
730        let term = converter.debruijn_to_name(value)?;
731
732        Ok(term)
733    }
734}
735
736impl TryFrom<Program<NamedDeBruijn>> for Program<Name> {
737    type Error = debruijn::Error;
738
739    fn try_from(value: Program<NamedDeBruijn>) -> Result<Self, Self::Error> {
740        Ok(Program::<Name> {
741            version: value.version,
742            term: value.term.try_into()?,
743        })
744    }
745}
746
747impl TryFrom<Term<NamedDeBruijn>> for Term<Name> {
748    type Error = debruijn::Error;
749
750    fn try_from(value: Term<NamedDeBruijn>) -> Result<Self, debruijn::Error> {
751        let mut converter = Converter::new();
752
753        let term = converter.named_debruijn_to_name(&value)?;
754
755        Ok(term)
756    }
757}
758
759impl From<Program<NamedDeBruijn>> for Program<DeBruijn> {
760    fn from(value: Program<NamedDeBruijn>) -> Self {
761        Program::<DeBruijn> {
762            version: value.version,
763            term: value.term.into(),
764        }
765    }
766}
767
768impl From<Term<NamedDeBruijn>> for Term<DeBruijn> {
769    fn from(value: Term<NamedDeBruijn>) -> Self {
770        let mut converter = Converter::new();
771
772        converter.named_debruijn_to_debruijn(&value)
773    }
774}
775
776impl From<Program<NamedDeBruijn>> for Program<FakeNamedDeBruijn> {
777    fn from(value: Program<NamedDeBruijn>) -> Self {
778        Program::<FakeNamedDeBruijn> {
779            version: value.version,
780            term: value.term.into(),
781        }
782    }
783}
784
785impl From<Term<NamedDeBruijn>> for Term<FakeNamedDeBruijn> {
786    fn from(value: Term<NamedDeBruijn>) -> Self {
787        let mut converter = Converter::new();
788
789        converter.named_debruijn_to_fake_named_debruijn(&value)
790    }
791}
792
793impl TryFrom<Program<DeBruijn>> for Program<Name> {
794    type Error = debruijn::Error;
795
796    fn try_from(value: Program<DeBruijn>) -> Result<Self, Self::Error> {
797        Ok(Program::<Name> {
798            version: value.version,
799            term: value.term.try_into()?,
800        })
801    }
802}
803
804impl TryFrom<Term<DeBruijn>> for Term<Name> {
805    type Error = debruijn::Error;
806
807    fn try_from(value: Term<DeBruijn>) -> Result<Self, debruijn::Error> {
808        let mut converter = Converter::new();
809
810        let term = converter.debruijn_to_name(&value)?;
811
812        Ok(term)
813    }
814}
815
816impl From<Program<DeBruijn>> for Program<NamedDeBruijn> {
817    fn from(value: Program<DeBruijn>) -> Self {
818        Program::<NamedDeBruijn> {
819            version: value.version,
820            term: value.term.into(),
821        }
822    }
823}
824
825impl From<Term<DeBruijn>> for Term<NamedDeBruijn> {
826    fn from(value: Term<DeBruijn>) -> Self {
827        let mut converter = Converter::new();
828
829        converter.debruijn_to_named_debruijn(&value)
830    }
831}
832
833impl From<Program<FakeNamedDeBruijn>> for Program<NamedDeBruijn> {
834    fn from(value: Program<FakeNamedDeBruijn>) -> Self {
835        Program::<NamedDeBruijn> {
836            version: value.version,
837            term: value.term.into(),
838        }
839    }
840}
841
842impl From<Term<FakeNamedDeBruijn>> for Term<NamedDeBruijn> {
843    fn from(value: Term<FakeNamedDeBruijn>) -> Self {
844        let mut converter = Converter::new();
845
846        converter.fake_named_debruijn_to_named_debruijn(&value)
847    }
848}
849
850impl Program<NamedDeBruijn> {
851    pub fn eval(self, initial_budget: ExBudget) -> EvalResult {
852        let mut machine = Machine::new(
853            Language::PlutusV2,
854            CostModel::default(),
855            initial_budget,
856            200,
857        );
858
859        let term = machine.run(self.term);
860
861        EvalResult::new(term, machine.ex_budget, initial_budget, machine.logs)
862    }
863
864    /// Evaluate a Program as a specific PlutusVersion
865    pub fn eval_version(self, initial_budget: ExBudget, version: &Language) -> EvalResult {
866        let mut machine = Machine::new(version.clone(), CostModel::default(), initial_budget, 200);
867
868        let term = machine.run(self.term);
869
870        EvalResult::new(term, machine.ex_budget, initial_budget, machine.logs)
871    }
872
873    pub fn eval_as(
874        self,
875        version: &Language,
876        costs: &[i64],
877        initial_budget: Option<&ExBudget>,
878    ) -> EvalResult {
879        let budget = initial_budget.copied().unwrap_or_default();
880
881        let mut machine = Machine::new(
882            version.clone(),
883            initialize_cost_model(version, costs),
884            budget,
885            200, //slippage
886        );
887
888        let term = machine.run(self.term);
889
890        EvalResult::new(term, machine.ex_budget, budget, machine.logs)
891    }
892}
893
894impl Program<DeBruijn> {
895    pub fn eval(&self, initial_budget: ExBudget) -> EvalResult {
896        let program: Program<NamedDeBruijn> = self.clone().into();
897        program.eval(initial_budget)
898    }
899
900    pub fn eval_version(self, initial_budget: ExBudget, version: &Language) -> EvalResult {
901        let program: Program<NamedDeBruijn> = self.clone().into();
902        program.eval_version(initial_budget, version)
903    }
904}
905
906impl Term<NamedDeBruijn> {
907    pub fn is_valid_script_result(&self) -> bool {
908        !matches!(self, Term::Error)
909    }
910}