parameratize cost model

This commit is contained in:
Kasey White 2022-09-17 21:12:48 -04:00
parent d426f4922f
commit 472cea6c41
7 changed files with 2143 additions and 51 deletions

View File

@ -52,7 +52,7 @@ fn main() -> anyhow::Result<()> {
slot_length, slot_length,
}; };
eval_tx(tx_babbage, &resolved_inputs, &slot_config)?; // eval_tx(tx_babbage, &resolved_inputs, &slot_config)?;
} }
} }
}, },

View File

@ -1,13 +1,13 @@
use std::{fmt::Display, rc::Rc}; use std::{fmt::Display, rc::Rc};
use pallas_primitives::alonzo::PlutusData; use pallas_primitives::{alonzo::PlutusData, babbage::Language};
use crate::{ use crate::{
builtins::DefaultFunction, builtins::DefaultFunction,
debruijn::{self, Converter}, debruijn::{self, Converter},
flat::Binder, flat::Binder,
machine::{ machine::{
cost_model::{CostModel, ExBudget}, cost_model::{initialize_cost_model, CostModel, ExBudget},
Machine, Machine,
}, },
}; };
@ -488,7 +488,33 @@ impl Program<NamedDeBruijn> {
ExBudget, ExBudget,
Vec<String>, Vec<String>,
) { ) {
let mut machine = Machine::new(CostModel::default(), ExBudget::default(), 200); let mut machine = Machine::new(
Language::PlutusV2,
CostModel::default(),
ExBudget::default(),
200,
);
let term = machine.run(&self.term);
(term, machine.ex_budget, machine.logs)
}
pub fn eval_with_params(
&self,
version: &Language,
costs: &[i64],
) -> (
Result<Term<NamedDeBruijn>, crate::machine::Error>,
ExBudget,
Vec<String>,
) {
let mut machine = Machine::new(
version.clone(),
initialize_cost_model(version, costs),
ExBudget::default(),
200, //slippage
);
let term = machine.run(&self.term); let term = machine.run(&self.term);

View File

@ -11,7 +11,7 @@ mod runtime;
use cost_model::{ExBudget, StepKind}; use cost_model::{ExBudget, StepKind};
pub use error::Error; pub use error::Error;
use pallas_primitives::babbage::{BigInt, PlutusData}; use pallas_primitives::babbage::{BigInt, Language, PlutusData};
use self::{cost_model::CostModel, runtime::BuiltinRuntime}; use self::{cost_model::CostModel, runtime::BuiltinRuntime};
@ -39,10 +39,16 @@ pub struct Machine {
unbudgeted_steps: [u32; 8], unbudgeted_steps: [u32; 8],
pub logs: Vec<String>, pub logs: Vec<String>,
stack: Vec<MachineStep>, stack: Vec<MachineStep>,
version: Language,
} }
impl Machine { impl Machine {
pub fn new(costs: CostModel, initial_budget: ExBudget, slippage: u32) -> Machine { pub fn new(
version: Language,
costs: CostModel,
initial_budget: ExBudget,
slippage: u32,
) -> Machine {
Machine { Machine {
costs, costs,
ex_budget: initial_budget, ex_budget: initial_budget,
@ -50,6 +56,7 @@ impl Machine {
unbudgeted_steps: [0; 8], unbudgeted_steps: [0; 8],
logs: vec![], logs: vec![],
stack: vec![], stack: vec![],
version,
} }
} }
@ -347,8 +354,10 @@ impl Machine {
runtime: BuiltinRuntime, runtime: BuiltinRuntime,
) -> Result<Value, Error> { ) -> Result<Value, Error> {
if runtime.is_ready() { if runtime.is_ready() {
let cost = runtime.to_ex_budget(&self.costs.builtin_costs); let cost = match self.version {
Language::PlutusV1 => runtime.to_ex_budget_v1(&self.costs.builtin_costs),
Language::PlutusV2 => runtime.to_ex_budget_v2(&self.costs.builtin_costs),
};
self.spend_budget(cost)?; self.spend_budget(cost)?;
runtime.call(&mut self.logs) runtime.call(&mut self.logs)

File diff suppressed because it is too large Load Diff

View File

@ -63,8 +63,12 @@ impl BuiltinRuntime {
Ok(()) Ok(())
} }
pub fn to_ex_budget(&self, costs: &BuiltinCosts) -> ExBudget { pub fn to_ex_budget_v2(&self, costs: &BuiltinCosts) -> ExBudget {
costs.to_ex_budget(self.fun, &self.args) costs.to_ex_budget_v2(self.fun, &self.args)
}
pub fn to_ex_budget_v1(&self, costs: &BuiltinCosts) -> ExBudget {
costs.to_ex_budget_v1(self.fun, &self.args)
} }
} }

View File

@ -1,9 +1,11 @@
use pallas_primitives::{ use pallas_primitives::{
babbage::{CostMdls, MintedTx, Redeemer, TransactionInput, TransactionOutput}, babbage::{CostMdls, Language, MintedTx, Redeemer, TransactionInput, TransactionOutput},
Fragment, Fragment,
}; };
use pallas_traverse::{Era, MultiEraTx}; use pallas_traverse::{Era, MultiEraTx};
use crate::Error;
use self::script_context::{ResolvedInput, SlotConfig}; use self::script_context::{ResolvedInput, SlotConfig};
mod eval; mod eval;
@ -13,46 +15,63 @@ mod to_plutus_data;
pub fn eval_tx( pub fn eval_tx(
tx: &MintedTx, tx: &MintedTx,
utxos: &[ResolvedInput], utxos: &[ResolvedInput],
//TODO: costMdls cost_mdls: &CostMdls,
version: &Language,
slot_config: &SlotConfig, slot_config: &SlotConfig,
) -> anyhow::Result<Vec<Redeemer>> { ) -> anyhow::Result<Vec<Redeemer>> {
let redeemers = tx.transaction_witness_set.redeemer.as_ref(); let redeemers = tx.transaction_witness_set.redeemer.as_ref();
let lookup_table = eval::get_script_and_datum_lookup_table(tx, utxos); let lookup_table = eval::get_script_and_datum_lookup_table(tx, utxos);
match redeemers { let costs_maybe = match version {
Some(rs) => { Language::PlutusV1 => cost_mdls.plutus_v1.as_ref(),
let mut collected_redeemers = vec![]; Language::PlutusV2 => cost_mdls.plutus_v2.as_ref(),
for redeemer in rs.iter() { };
collected_redeemers.push(eval::eval_redeemer(
tx, if let Some(costs) = costs_maybe {
utxos, match redeemers {
slot_config, Some(rs) => {
redeemer, let mut collected_redeemers = vec![];
&lookup_table, for redeemer in rs.iter() {
)?) collected_redeemers.push(eval::eval_redeemer(
tx,
utxos,
slot_config,
redeemer,
&lookup_table,
version,
costs,
)?)
}
Ok(collected_redeemers)
} }
Ok(collected_redeemers) None => Ok(vec![]),
} }
None => Ok(vec![]), } else {
Err(anyhow::Error::msg(format!(
"Missing cost model for version: {:?}",
version
)))
} }
} }
pub fn eval_tx_raw( pub fn eval_tx_raw(
tx_bytes: &Vec<u8>, tx_bytes: &[u8],
utxos_bytes: &Vec<(Vec<u8>, Vec<u8>)>, utxos_bytes: &[(Vec<u8>, Vec<u8>)],
cost_mdls_bytes: &Vec<u8>, cost_mdls_bytes: &[u8],
version_bytes: u32,
slot_config: (u64, u64), slot_config: (u64, u64),
) -> Result<Vec<Vec<u8>>, ()> { ) -> Result<Vec<Vec<u8>>, Error> {
let multi_era_tx = MultiEraTx::decode(Era::Babbage, &tx_bytes) let multi_era_tx = MultiEraTx::decode(Era::Babbage, tx_bytes)
.or_else(|_| MultiEraTx::decode(Era::Alonzo, &tx_bytes)) .or_else(|_| MultiEraTx::decode(Era::Alonzo, tx_bytes))
.or_else(|_| Err(()))?; // TODO: proper error message .map_err(|_| Error::from("Wrong era. Please use Babbage or Alonzo"))?; // TODO: proper error message
let cost_mdls = CostMdls::decode_fragment(&cost_mdls_bytes).or_else(|_| Err(()))?; // TODO: proper error message let cost_mdls = CostMdls::decode_fragment(cost_mdls_bytes)
.map_err(|_| Error::from("Unable to decode cost models"))?; // TODO: proper error message
let utxos: Vec<ResolvedInput> = utxos_bytes let utxos: Vec<ResolvedInput> = utxos_bytes
.iter() .iter()
.map(|(input, output)| ResolvedInput { .map(|(input, _output)| ResolvedInput {
input: TransactionInput::decode_fragment(input).unwrap(), input: TransactionInput::decode_fragment(input).unwrap(),
output: TransactionOutput::decode_fragment(input).unwrap(), output: TransactionOutput::decode_fragment(input).unwrap(),
}) })
@ -63,13 +82,19 @@ pub fn eval_tx_raw(
slot_length: slot_config.1, slot_length: slot_config.1,
}; };
let version = match version_bytes {
1 => Language::PlutusV1,
2 => Language::PlutusV2,
_ => unreachable!(),
};
match multi_era_tx { match multi_era_tx {
MultiEraTx::Babbage(tx) => match eval_tx(&tx, &utxos, &sc) { MultiEraTx::Babbage(tx) => match eval_tx(&tx, &utxos, &cost_mdls, &version, &sc) {
Ok(redeemers) => Ok(redeemers Ok(redeemers) => Ok(redeemers
.iter() .iter()
.map(|r| r.encode_fragment().unwrap()) .map(|r| r.encode_fragment().unwrap())
.collect()), .collect()),
Err(_) => Err(()), Err(_) => Err(Error::from("Can't eval without redeemers")),
}, },
// MultiEraTx::AlonzoCompatible(tx, _) => match eval_tx(&tx, &utxos, &sc) { // MultiEraTx::AlonzoCompatible(tx, _) => match eval_tx(&tx, &utxos, &sc) {
// Ok(redeemers) => Ok(redeemers // Ok(redeemers) => Ok(redeemers
@ -79,7 +104,7 @@ pub fn eval_tx_raw(
// Err(_) => Err(()), // Err(_) => Err(()),
// }, // },
// TODO: I probably did a mistake here with using MintedTx which is only compatible with Babbage tx. // TODO: I probably did a mistake here with using MintedTx which is only compatible with Babbage tx.
_ => Err(()), _ => Err(Error::from("Wrong era. Please use babbage")),
} }
} }
@ -87,7 +112,7 @@ pub fn eval_tx_raw(
mod tests { mod tests {
use pallas_codec::utils::MaybeIndefArray; use pallas_codec::utils::MaybeIndefArray;
use pallas_primitives::{ use pallas_primitives::{
babbage::{TransactionInput, TransactionOutput}, babbage::{CostMdls, Language, TransactionInput, TransactionOutput},
Fragment, Fragment,
}; };
use pallas_traverse::{Era, MultiEraTx}; use pallas_traverse::{Era, MultiEraTx};
@ -130,12 +155,196 @@ mod tests {
slot_length: 1000, slot_length: 1000,
}; };
let costs: Vec<i64> = vec![
205665,
812,
1,
1,
1000,
571,
0,
1,
1000,
24177,
4,
1,
1000,
32,
117366,
10475,
4,
23000,
100,
23000,
100,
23000,
100,
23000,
100,
23000,
100,
23000,
100,
100,
100,
23000,
100,
19537,
32,
175354,
32,
46417,
4,
221973,
511,
0,
1,
89141,
32,
497525,
14068,
4,
2,
196500,
453240,
220,
0,
1,
1,
1000,
28662,
4,
2,
245000,
216773,
62,
1,
1060367,
12586,
1,
208512,
421,
1,
187000,
1000,
52998,
1,
80436,
32,
43249,
32,
1000,
32,
80556,
1,
57667,
4,
1000,
10,
197145,
156,
1,
197145,
156,
1,
204924,
473,
1,
208896,
511,
1,
52467,
32,
64832,
32,
65493,
32,
22558,
32,
16563,
32,
76511,
32,
196500,
453240,
220,
0,
1,
1,
69522,
11687,
0,
1,
60091,
32,
196500,
453240,
220,
0,
1,
1,
196500,
453240,
220,
0,
1,
1,
1159724,
392670,
0,
2,
806990,
30482,
4,
1927926,
82523,
4,
265318,
0,
4,
0,
85931,
32,
205665,
812,
1,
1,
41182,
32,
212342,
32,
31220,
32,
32696,
32,
43357,
32,
32247,
32,
38314,
32,
20000000000,
20000000000,
9462713,
1021,
10,
20000000000,
0,
20000000000,
];
let cost_mdl = CostMdls {
plutus_v1: None,
plutus_v2: Some(costs),
};
let multi_era_tx = MultiEraTx::decode(Era::Babbage, &tx_bytes) let multi_era_tx = MultiEraTx::decode(Era::Babbage, &tx_bytes)
.or_else(|_| MultiEraTx::decode(Era::Alonzo, &tx_bytes)) .or_else(|_| MultiEraTx::decode(Era::Alonzo, &tx_bytes))
.unwrap(); .unwrap();
match multi_era_tx { match multi_era_tx {
MultiEraTx::Babbage(tx) => { MultiEraTx::Babbage(tx) => {
let redeemers = eval_tx(&tx, &utxos, &slot_config).unwrap(); let redeemers =
eval_tx(&tx, &utxos, &cost_mdl, &Language::PlutusV2, &slot_config).unwrap();
assert_eq!(redeemers.len(), 1) assert_eq!(redeemers.len(), 1)
} }
@ -181,12 +390,196 @@ mod tests {
slot_length: 1000, slot_length: 1000,
}; };
let costs: Vec<i64> = vec![
205665,
812,
1,
1,
1000,
571,
0,
1,
1000,
24177,
4,
1,
1000,
32,
117366,
10475,
4,
23000,
100,
23000,
100,
23000,
100,
23000,
100,
23000,
100,
23000,
100,
100,
100,
23000,
100,
19537,
32,
175354,
32,
46417,
4,
221973,
511,
0,
1,
89141,
32,
497525,
14068,
4,
2,
196500,
453240,
220,
0,
1,
1,
1000,
28662,
4,
2,
245000,
216773,
62,
1,
1060367,
12586,
1,
208512,
421,
1,
187000,
1000,
52998,
1,
80436,
32,
43249,
32,
1000,
32,
80556,
1,
57667,
4,
1000,
10,
197145,
156,
1,
197145,
156,
1,
204924,
473,
1,
208896,
511,
1,
52467,
32,
64832,
32,
65493,
32,
22558,
32,
16563,
32,
76511,
32,
196500,
453240,
220,
0,
1,
1,
69522,
11687,
0,
1,
60091,
32,
196500,
453240,
220,
0,
1,
1,
196500,
453240,
220,
0,
1,
1,
1159724,
392670,
0,
2,
806990,
30482,
4,
1927926,
82523,
4,
265318,
0,
4,
0,
85931,
32,
205665,
812,
1,
1,
41182,
32,
212342,
32,
31220,
32,
32696,
32,
43357,
32,
32247,
32,
38314,
32,
20000000000,
20000000000,
9462713,
1021,
10,
20000000000,
0,
20000000000,
];
let cost_mdl = CostMdls {
plutus_v1: None,
plutus_v2: Some(costs),
};
let multi_era_tx = MultiEraTx::decode(Era::Babbage, &tx_bytes) let multi_era_tx = MultiEraTx::decode(Era::Babbage, &tx_bytes)
.or_else(|_| MultiEraTx::decode(Era::Alonzo, &tx_bytes)) .or_else(|_| MultiEraTx::decode(Era::Alonzo, &tx_bytes))
.unwrap(); .unwrap();
match multi_era_tx { match multi_era_tx {
MultiEraTx::Babbage(tx) => { MultiEraTx::Babbage(tx) => {
let redeemers = eval_tx(&tx, &utxos, &slot_config).unwrap(); let redeemers =
eval_tx(&tx, &utxos, &cost_mdl, &Language::PlutusV2, &slot_config).unwrap();
println!("{:?}", redeemers.len()); println!("{:?}", redeemers.len());
} }
@ -232,12 +625,32 @@ mod tests {
slot_length: 1000, slot_length: 1000,
}; };
let costs: Vec<i64> = vec![
205665, 812, 1, 1, 1000, 571, 0, 1, 1000, 24177, 4, 1, 1000, 32, 117366, 10475, 4,
23000, 100, 23000, 100, 23000, 100, 23000, 100, 23000, 100, 23000, 100, 100, 100,
23000, 100, 19537, 32, 175354, 32, 46417, 4, 221973, 511, 0, 1, 89141, 32, 497525,
14068, 4, 2, 196500, 453240, 220, 0, 1, 1, 1000, 28662, 4, 2, 245000, 216773, 62, 1,
1060367, 12586, 1, 208512, 421, 1, 187000, 1000, 52998, 1, 80436, 32, 43249, 32, 1000,
32, 80556, 1, 57667, 4, 1000, 10, 197145, 156, 1, 197145, 156, 1, 204924, 473, 1,
208896, 511, 1, 52467, 32, 64832, 32, 65493, 32, 22558, 32, 16563, 32, 76511, 32,
196500, 453240, 220, 0, 1, 1, 69522, 11687, 0, 1, 60091, 32, 196500, 453240, 220, 0, 1,
1, 196500, 453240, 220, 0, 1, 1, 806990, 30482, 4, 1927926, 82523, 4, 265318, 0, 4, 0,
85931, 32, 205665, 812, 1, 1, 41182, 32, 212342, 32, 31220, 32, 32696, 32, 43357, 32,
32247, 32, 38314, 32, 9462713, 1021, 10,
];
let cost_mdl = CostMdls {
plutus_v1: Some(costs),
plutus_v2: None,
};
let multi_era_tx = MultiEraTx::decode(Era::Babbage, &tx_bytes) let multi_era_tx = MultiEraTx::decode(Era::Babbage, &tx_bytes)
.or_else(|_| MultiEraTx::decode(Era::Alonzo, &tx_bytes)) .or_else(|_| MultiEraTx::decode(Era::Alonzo, &tx_bytes))
.unwrap(); .unwrap();
match multi_era_tx { match multi_era_tx {
MultiEraTx::Babbage(tx) => { MultiEraTx::Babbage(tx) => {
let redeemers = eval_tx(&tx, &utxos, &slot_config).unwrap(); let redeemers =
eval_tx(&tx, &utxos, &cost_mdl, &Language::PlutusV1, &slot_config).unwrap();
println!("{:?}", redeemers.len()); println!("{:?}", redeemers.len());
} }

View File

@ -7,9 +7,9 @@ use pallas_addresses::{Address, ScriptHash, StakePayload};
use pallas_codec::utils::{KeyValuePairs, MaybeIndefArray}; use pallas_codec::utils::{KeyValuePairs, MaybeIndefArray};
use pallas_crypto::hash::Hash; use pallas_crypto::hash::Hash;
use pallas_primitives::babbage::{ use pallas_primitives::babbage::{
Certificate, DatumHash, DatumOption, ExUnits, Mint, MintedTx, PlutusV1Script, PlutusV2Script, Certificate, DatumHash, DatumOption, ExUnits, Language, Mint, MintedTx, PlutusV1Script,
PolicyId, Redeemer, RedeemerTag, RewardAccount, Script, StakeCredential, TransactionInput, PlutusV2Script, PolicyId, Redeemer, RedeemerTag, RewardAccount, Script, StakeCredential,
TransactionOutput, Value, Withdrawals, TransactionInput, TransactionOutput, Value, Withdrawals,
}; };
use pallas_traverse::{ComputeHash, OriginalHash}; use pallas_traverse::{ComputeHash, OriginalHash};
use std::{collections::HashMap, convert::TryInto, ops::Deref, vec}; use std::{collections::HashMap, convert::TryInto, ops::Deref, vec};
@ -556,6 +556,8 @@ pub fn eval_redeemer(
slot_config: &SlotConfig, slot_config: &SlotConfig,
redeemer: &Redeemer, redeemer: &Redeemer,
lookup_table: &DataLookupTable, lookup_table: &DataLookupTable,
version: &Language,
costs: &[i64],
) -> anyhow::Result<Redeemer> { ) -> anyhow::Result<Redeemer> {
let purpose = get_script_purpose( let purpose = get_script_purpose(
redeemer, redeemer,
@ -585,7 +587,7 @@ pub fn eval_redeemer(
.apply_data(datum) .apply_data(datum)
.apply_data(redeemer.data.clone()) .apply_data(redeemer.data.clone())
.apply_data(script_context.to_plutus_data()) .apply_data(script_context.to_plutus_data())
.eval(); .eval_with_params(version, costs);
match result.0 { match result.0 {
Ok(_) => {} Ok(_) => {}