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 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}