Skip to main content

amaru_uplc/
program.rs

1use crate::{
2    arena::Arena,
3    binder::Eval,
4    machine::{
5        cost_model::builtin_costs::{
6            builtin_costs_v1::BuiltinCostsV1, builtin_costs_v2::BuiltinCostsV2,
7            builtin_costs_v3::BuiltinCostsV3, BuiltinCostModel,
8        },
9        BuiltinSemantics, CostModel, EvalResult, ExBudget, Machine, PlutusVersion,
10    },
11    term::Term,
12};
13
14#[derive(Debug)]
15pub struct Program<'a, V> {
16    pub version: &'a Version<'a>,
17    pub term: &'a Term<'a, V>,
18}
19
20impl<'a, V> Program<'a, V> {
21    pub fn new(arena: &'a Arena, version: &'a Version<'a>, term: &'a Term<'a, V>) -> &'a Self {
22        let program = Program { version, term };
23
24        arena.alloc(program)
25    }
26
27    pub fn apply(&'a self, arena: &'a Arena, term: &'a Term<'a, V>) -> &'a Self {
28        let term = self.term.apply(arena, term);
29
30        Self::new(arena, self.version, term)
31    }
32}
33
34impl<'a, V> Program<'a, V>
35where
36    V: Eval<'a>,
37{
38    pub fn eval(&'a self, arena: &'a Arena) -> EvalResult<'a, V> {
39        self.eval_version(arena, PlutusVersion::V3)
40    }
41
42    /// Evaluate with explicit Plutus version
43    pub fn eval_version(
44        &'a self,
45        arena: &'a Arena,
46        plutus_version: PlutusVersion,
47    ) -> EvalResult<'a, V> {
48        self.eval_version_budget(arena, plutus_version, ExBudget::default())
49    }
50
51    pub fn eval_version_budget(
52        &'a self,
53        arena: &'a Arena,
54        plutus_version: PlutusVersion,
55        initial_budget: ExBudget,
56    ) -> EvalResult<'a, V> {
57        match plutus_version {
58            PlutusVersion::V1 => self.evaluate(
59                arena,
60                CostModel::<BuiltinCostsV1>::default(),
61                plutus_version,
62                initial_budget,
63            ),
64            PlutusVersion::V2 => self.evaluate(
65                arena,
66                CostModel::<BuiltinCostsV2>::default(),
67                plutus_version,
68                initial_budget,
69            ),
70            PlutusVersion::V3 => self.evaluate(
71                arena,
72                CostModel::<BuiltinCostsV3>::default(),
73                plutus_version,
74                initial_budget,
75            ),
76        }
77    }
78
79    fn evaluate<B: BuiltinCostModel>(
80        &'a self,
81        arena: &'a Arena,
82        cost_model: CostModel<B>,
83        plutus_version: PlutusVersion,
84        initial_budget: ExBudget,
85    ) -> EvalResult<'a, V> {
86        let mut machine = Machine::new(
87            arena,
88            initial_budget,
89            cost_model,
90            BuiltinSemantics::from(&plutus_version),
91        );
92        let term = machine.run(self.term);
93        let mut info = machine.info();
94        info.consumed_budget = initial_budget - info.consumed_budget;
95        EvalResult { term, info }
96    }
97
98    pub fn eval_with_params(
99        &'a self,
100        arena: &'a Arena,
101        plutus_version: PlutusVersion,
102        cost_model: &[i64],
103        initial_budget: ExBudget,
104    ) -> EvalResult<'a, V> {
105        match plutus_version {
106            PlutusVersion::V1 => self.evaluate(
107                arena,
108                CostModel::<BuiltinCostsV1>::initialize_cost_model(&plutus_version, cost_model),
109                plutus_version,
110                initial_budget,
111            ),
112            PlutusVersion::V2 => self.evaluate(
113                arena,
114                CostModel::<BuiltinCostsV2>::initialize_cost_model(&plutus_version, cost_model),
115                plutus_version,
116                initial_budget,
117            ),
118            PlutusVersion::V3 => self.evaluate(
119                arena,
120                CostModel::<BuiltinCostsV3>::initialize_cost_model(&plutus_version, cost_model),
121                plutus_version,
122                initial_budget,
123            ),
124        }
125    }
126}
127
128#[derive(Debug, Copy, Clone)]
129pub struct Version<'a>(&'a (usize, usize, usize));
130
131impl<'a> Version<'a> {
132    pub fn new(arena: &'a Arena, major: usize, minor: usize, patch: usize) -> &'a mut Self {
133        let version = arena.alloc((major, minor, patch));
134
135        arena.alloc(Version(version))
136    }
137
138    pub fn plutus_v1(arena: &'a Arena) -> &'a mut Self {
139        Self::new(arena, 1, 0, 0)
140    }
141
142    pub fn plutus_v2(arena: &'a Arena) -> &'a mut Self {
143        Self::new(arena, 1, 0, 0)
144    }
145
146    pub fn plutus_v3(arena: &'a Arena) -> &'a mut Self {
147        Self::new(arena, 1, 1, 0)
148    }
149
150    pub fn is_v1_0_0(&'a self) -> bool {
151        self.0 .0 == 1 && self.0 .1 == 0 && self.0 .2 == 0
152    }
153
154    pub fn is_v1_1_0(&'a self) -> bool {
155        self.0 .0 == 1 && self.0 .1 == 1 && self.0 .2 == 0
156    }
157
158    pub fn is_valid_version(&'a self) -> bool {
159        self.is_v1_0_0() || self.is_v1_1_0()
160    }
161
162    pub fn is_less_than_1_1_0(&'a self) -> bool {
163        self.0 .0 == 0 || self.0 .1 == 0
164    }
165
166    pub fn major(&'a self) -> usize {
167        self.0 .0
168    }
169
170    pub fn minor(&'a self) -> usize {
171        self.0 .1
172    }
173
174    pub fn patch(&'a self) -> usize {
175        self.0 .2
176    }
177}