diff --git a/crates/uplc/src/tx.rs b/crates/uplc/src/tx.rs index a1ee051b..7d1c29a6 100644 --- a/crates/uplc/src/tx.rs +++ b/crates/uplc/src/tx.rs @@ -49,6 +49,8 @@ pub fn eval_phase_two( Some(rs) => { let mut collected_redeemers = vec![]; + let mut remaining_budget = initial_budget.unwrap_or(&ExBudget::default()).clone(); + for redeemer in rs.iter() { let redeemer = eval::eval_redeemer( tx, @@ -57,9 +59,14 @@ pub fn eval_phase_two( redeemer, &lookup_table, cost_mdls, - initial_budget, + &remaining_budget, )?; + // The substraction is safe here as ex units counting is done during evaluation. + // Redeemer would fail already if budget was negative. + remaining_budget.cpu -= redeemer.ex_units.steps as i64; + remaining_budget.mem -= redeemer.ex_units.mem as i64; + collected_redeemers.push(redeemer) } diff --git a/crates/uplc/src/tx/eval.rs b/crates/uplc/src/tx/eval.rs index 2c08f0bb..2ff5daaa 100644 --- a/crates/uplc/src/tx/eval.rs +++ b/crates/uplc/src/tx/eval.rs @@ -693,7 +693,7 @@ pub fn eval_redeemer( redeemer: &Redeemer, lookup_table: &DataLookupTable, cost_mdls_opt: Option<&CostMdls>, - initial_budget: Option<&ExBudget>, + initial_budget: &ExBudget, ) -> Result { let result = || { let purpose = get_script_purpose( @@ -733,7 +733,7 @@ pub fn eval_redeemer( return Err(Error::V1CostModelNotFound); }; - program.eval_as(&Language::PlutusV1, costs, initial_budget) + program.eval_as(&Language::PlutusV1, costs, Some(initial_budget)) } else { program.eval_v1() }; @@ -743,11 +743,6 @@ pub fn eval_redeemer( Err(err) => return Err(Error::Machine(err, budget, logs)), } - let initial_budget = match initial_budget { - Some(b) => *b, - None => ExBudget::default(), - }; - let new_redeemer = Redeemer { tag: redeemer.tag.clone(), index: redeemer.index, @@ -784,7 +779,7 @@ pub fn eval_redeemer( return Err(Error::V2CostModelNotFound); }; - program.eval_as(&Language::PlutusV2, costs, initial_budget) + program.eval_as(&Language::PlutusV2, costs, Some(initial_budget)) } else { program.eval(ExBudget::default()) }; @@ -794,11 +789,6 @@ pub fn eval_redeemer( Err(err) => return Err(Error::Machine(err, budget, logs)), } - let initial_budget = match initial_budget { - Some(b) => *b, - None => ExBudget::default(), - }; - let new_redeemer = Redeemer { tag: redeemer.tag.clone(), index: redeemer.index, @@ -837,7 +827,7 @@ pub fn eval_redeemer( return Err(Error::V1CostModelNotFound); }; - program.eval_as(&Language::PlutusV1, costs, initial_budget) + program.eval_as(&Language::PlutusV1, costs, Some(initial_budget)) } else { program.eval_v1() }; @@ -847,11 +837,6 @@ pub fn eval_redeemer( Err(err) => return Err(Error::Machine(err, budget, logs)), } - let initial_budget = match initial_budget { - Some(b) => *b, - None => ExBudget::default(), - }; - let new_redeemer = Redeemer { tag: redeemer.tag.clone(), index: redeemer.index, @@ -887,7 +872,7 @@ pub fn eval_redeemer( return Err(Error::V2CostModelNotFound); }; - program.eval_as(&Language::PlutusV2, costs, initial_budget) + program.eval_as(&Language::PlutusV2, costs, Some(initial_budget)) } else { program.eval(ExBudget::default()) }; @@ -897,11 +882,6 @@ pub fn eval_redeemer( Err(err) => return Err(Error::Machine(err, budget, logs)), } - let initial_budget = match initial_budget { - Some(b) => *b, - None => ExBudget::default(), - }; - let new_redeemer = Redeemer { tag: redeemer.tag.clone(), index: redeemer.index,