whisky_pallas/utils/
phase_two.rs1use pallas::codec::minicbor;
2use pallas::ledger::primitives::conway::{CostModels as PallasCostModels, Tx};
3use pallas_primitives::conway::Redeemer as PallasRedeemer;
4use uplc::machine::cost_model::ExBudget;
5use uplc::tx::error::Error;
6use uplc::tx::{eval, iter_redeemers, DataLookupTable, ResolvedInput, SlotConfig};
7use uplc::Fragment;
8
9pub enum PhaseTwoEvalResult {
10 Success(PallasRedeemer),
11 Error(PallasRedeemer, Error),
12}
13
14pub fn eval_phase_two(
15 tx: &Tx,
16 utxos: &[ResolvedInput],
17 cost_mdls: Option<&PallasCostModels>,
18 slot_config: &SlotConfig,
19) -> Result<Vec<PhaseTwoEvalResult>, Error> {
20 let mut tx_bytes = Vec::new();
23 minicbor::encode(tx, &mut tx_bytes)
24 .map_err(|e| Error::FragmentDecode(format!("Failed to encode tx: {:?}", e).into()))?;
25
26 let tx_for_uplc =
28 pallas_primitives::conway::MintedTx::decode_fragment(&tx_bytes).map_err(|e| {
29 Error::FragmentDecode(format!("Failed to decode tx for uplc: {:?}", e).into())
30 })?;
31
32 let lookup_table = DataLookupTable::from_transaction(&tx_for_uplc, utxos);
33
34 let cost_mdls_for_uplc = cost_mdls
36 .map(|cm| {
37 let mut cm_bytes = Vec::new();
38 minicbor::encode(cm, &mut cm_bytes).ok()?;
39 pallas_primitives::conway::CostModels::decode_fragment(&cm_bytes).ok()
40 })
41 .flatten();
42
43 let redeemers = tx_for_uplc.transaction_witness_set.redeemer.as_ref();
44
45 match redeemers {
46 Some(rs) => {
47 let mut results = Vec::new();
48 for (key, data, ex_units) in iter_redeemers(rs) {
49 let remaining_budget = ExBudget {
50 cpu: i64::MAX,
51 mem: i64::MAX,
52 };
53 let redeemer_for_uplc = pallas_primitives::conway::Redeemer {
54 tag: key.tag,
55 index: key.index,
56 data: data.clone(),
57 ex_units,
58 };
59
60 let eval_result = eval::eval_redeemer(
61 &tx_for_uplc,
62 utxos,
63 slot_config,
64 &redeemer_for_uplc,
65 &lookup_table,
66 cost_mdls_for_uplc.as_ref(),
67 &remaining_budget,
68 );
69
70 let pallas_redeemer = redeemer_for_uplc.clone();
72
73 match eval_result {
74 Ok(updated_redeemer) => {
75 results.push(PhaseTwoEvalResult::Success(updated_redeemer))
76 }
77 Err(error) => results.push(PhaseTwoEvalResult::Error(pallas_redeemer, error)),
78 }
79 }
80
81 Ok(results)
82 }
83 None => Ok(vec![]),
84 }
85}