feat: clean up the machine a bit
This commit is contained in:
parent
de476c801b
commit
795d9ee028
|
@ -14,6 +14,32 @@ pub struct Program<T> {
|
||||||
pub term: Term<T>,
|
pub term: Term<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T> Program<T>
|
||||||
|
where
|
||||||
|
T: Clone,
|
||||||
|
{
|
||||||
|
/// We use this to apply the validator to Datum,
|
||||||
|
/// then redeemer, then ScriptContext. If datum is
|
||||||
|
/// even necessary (i.e. minting policy).
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// program.apply(&datum)
|
||||||
|
/// .apply(&redeemer)
|
||||||
|
/// .apply(&script_context);
|
||||||
|
/// ```
|
||||||
|
pub fn apply(&self, program: &Self) -> Self {
|
||||||
|
let applied_term = Term::Apply {
|
||||||
|
function: Box::new(self.term.clone()),
|
||||||
|
argument: Box::new(program.term.clone()),
|
||||||
|
};
|
||||||
|
|
||||||
|
Program {
|
||||||
|
version: self.version,
|
||||||
|
term: applied_term,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// This represents a term in Untyped Plutus Core.
|
/// This represents a term in Untyped Plutus Core.
|
||||||
/// We need a generic type for the different forms that a program may be in.
|
/// We need a generic type for the different forms that a program may be in.
|
||||||
/// Specifically, `Var` and `parameter_name` in `Lambda` can be a `Name`,
|
/// Specifically, `Var` and `parameter_name` in `Lambda` can be a `Name`,
|
||||||
|
@ -374,14 +400,3 @@ impl From<Term<FakeNamedDeBruijn>> for Term<NamedDeBruijn> {
|
||||||
converter.fake_named_debruijn_to_named_debruijn(value)
|
converter.fake_named_debruijn_to_named_debruijn(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn apply_program<T>(p1: Program<T>, p2: Program<T>) -> Program<T> {
|
|
||||||
let applied_term = Term::Apply {
|
|
||||||
function: Box::new(p1.term),
|
|
||||||
argument: Box::new(p2.term),
|
|
||||||
};
|
|
||||||
Program {
|
|
||||||
version: p1.version,
|
|
||||||
term: applied_term,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ enum StepKind {
|
||||||
BForce = 5,
|
BForce = 5,
|
||||||
BBuiltin = 6,
|
BBuiltin = 6,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<u8> for StepKind {
|
impl TryFrom<u8> for StepKind {
|
||||||
type Error = de::Error;
|
type Error = de::Error;
|
||||||
|
|
||||||
|
@ -41,6 +42,7 @@ enum ExBudgetCategory {
|
||||||
BBuiltinApp(DefaultFunction),
|
BBuiltinApp(DefaultFunction),
|
||||||
BStartup,
|
BStartup,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Can be negative
|
/// Can be negative
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
struct ExBudget {
|
struct ExBudget {
|
||||||
|
@ -146,27 +148,3 @@ fn spend_accumulated_budget_cek(unbudgeted_steps: &mut Vec<u32>, current_budget:
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn spend_budget_cek(
|
|
||||||
current_budget: &mut ExBudget,
|
|
||||||
category: ExBudgetCategory,
|
|
||||||
spend_budget: ExBudget,
|
|
||||||
) {
|
|
||||||
current_budget.mem -= spend_budget.mem;
|
|
||||||
current_budget.cpu -= spend_budget.cpu;
|
|
||||||
if current_budget.mem < 0 || current_budget.cpu < 0 {
|
|
||||||
panic!("Budget exhausted {:?}", current_budget);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_cost_by_step(step: StepKind) -> ExBudget {
|
|
||||||
match (step) {
|
|
||||||
StepKind::BConst => ExBudget { mem: 100, cpu: 100 },
|
|
||||||
StepKind::BVar => ExBudget { mem: 100, cpu: 100 },
|
|
||||||
StepKind::BLamAbs => ExBudget { mem: 100, cpu: 100 },
|
|
||||||
StepKind::BApply => ExBudget { mem: 100, cpu: 100 },
|
|
||||||
StepKind::BDelay => ExBudget { mem: 100, cpu: 100 },
|
|
||||||
StepKind::BForce => ExBudget { mem: 100, cpu: 100 },
|
|
||||||
StepKind::BBuiltin => ExBudget { mem: 100, cpu: 100 },
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ pub mod builtins;
|
||||||
mod debruijn;
|
mod debruijn;
|
||||||
mod flat;
|
mod flat;
|
||||||
pub mod interpreter;
|
pub mod interpreter;
|
||||||
|
pub mod machine;
|
||||||
pub mod parser;
|
pub mod parser;
|
||||||
mod pretty;
|
mod pretty;
|
||||||
pub mod program_builder;
|
pub mod program_builder;
|
||||||
|
|
|
@ -0,0 +1,132 @@
|
||||||
|
use crate::{
|
||||||
|
ast::{Constant, DeBruijn, Term},
|
||||||
|
builtins::DefaultFunction,
|
||||||
|
};
|
||||||
|
|
||||||
|
mod error;
|
||||||
|
|
||||||
|
pub use error::Error;
|
||||||
|
|
||||||
|
pub struct Machine {
|
||||||
|
costs: Costs,
|
||||||
|
ex_budget: ExBudget,
|
||||||
|
frames: Vec<Context>,
|
||||||
|
slippage: u32,
|
||||||
|
env: Vec<Value>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Machine {
|
||||||
|
pub fn new(costs: Costs, initial_budget: ExBudget, slippage: u32) -> Machine {
|
||||||
|
Machine {
|
||||||
|
costs,
|
||||||
|
ex_budget: initial_budget,
|
||||||
|
slippage,
|
||||||
|
frames: vec![],
|
||||||
|
env: vec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(
|
||||||
|
&mut self,
|
||||||
|
term: &Term<DeBruijn>,
|
||||||
|
) -> Result<(Term<DeBruijn>, usize, Vec<String>), Error> {
|
||||||
|
let startup_budget = self.costs.get(StepKind::StartUp);
|
||||||
|
|
||||||
|
self.spend_budget(startup_budget)?;
|
||||||
|
|
||||||
|
self.push_frame(Context::NoFrame);
|
||||||
|
|
||||||
|
self.enter_compute(term)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn enter_compute(&mut self, term: &Term<DeBruijn>) {}
|
||||||
|
|
||||||
|
fn spend_budget(&mut self, spend_budget: ExBudget) -> Result<(), Error> {
|
||||||
|
self.ex_budget.mem -= spend_budget.mem;
|
||||||
|
self.ex_budget.cpu -= spend_budget.cpu;
|
||||||
|
|
||||||
|
if self.ex_budget.mem < 0 || self.ex_budget.cpu < 0 {
|
||||||
|
Err(Error::OutOfExError(self.ex_budget))
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_frame(&mut self, frame: Context) {
|
||||||
|
self.frames.push(frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Context {
|
||||||
|
FrameApplyFun(Term<DeBruijn>, Term<DeBruijn>),
|
||||||
|
FrameApplyArg(Vec<Value>, Term<DeBruijn>, Box<Context>),
|
||||||
|
FrameForce(Box<Context>),
|
||||||
|
NoFrame,
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Value {
|
||||||
|
Con(Constant),
|
||||||
|
Delay(Term<DeBruijn>, Vec<Value>),
|
||||||
|
Lambda(DeBruijn, Term<DeBruijn>, Vec<Value>),
|
||||||
|
Builtin(
|
||||||
|
DefaultFunction,
|
||||||
|
Term<DeBruijn>,
|
||||||
|
// Need to figure out run time stuff
|
||||||
|
// BuiltinRuntime (CekValue uni fun)
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Can be negative
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
struct ExBudget {
|
||||||
|
mem: i32,
|
||||||
|
cpu: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExBudget {
|
||||||
|
pub fn occurence(&mut self, n: i32) {
|
||||||
|
self.mem *= n;
|
||||||
|
self.cpu *= n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum StepKind {
|
||||||
|
Constant,
|
||||||
|
Var,
|
||||||
|
Lambda,
|
||||||
|
Apply,
|
||||||
|
Delay,
|
||||||
|
Force,
|
||||||
|
Builtin,
|
||||||
|
StartUp,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// There's no entry for Error since we'll be exiting anyway; also, what would
|
||||||
|
/// happen if calling 'Error' caused the budget to be exceeded?
|
||||||
|
struct Costs {
|
||||||
|
startup: ExBudget,
|
||||||
|
var: ExBudget,
|
||||||
|
constant: ExBudget,
|
||||||
|
lambda: ExBudget,
|
||||||
|
delay: ExBudget,
|
||||||
|
force: ExBudget,
|
||||||
|
apply: ExBudget,
|
||||||
|
/// Just the cost of evaluating a Builtin node, not the builtin itself.
|
||||||
|
builtin: ExBudget,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Costs {
|
||||||
|
/// Get the cost of a step
|
||||||
|
pub fn get(&self, step: StepKind) -> ExBudget {
|
||||||
|
match step {
|
||||||
|
StepKind::Constant => self.constant,
|
||||||
|
StepKind::Var => self.var,
|
||||||
|
StepKind::Lambda => self.lambda,
|
||||||
|
StepKind::Apply => self.apply,
|
||||||
|
StepKind::Delay => self.delay,
|
||||||
|
StepKind::Force => self.force,
|
||||||
|
StepKind::Builtin => self.builtin,
|
||||||
|
StepKind::StartUp => self.startup,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
use super::ExBudget;
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
#[error("Over budget mem: {} & cpu: {}", .0.mem, .0.cpu)]
|
||||||
|
OutOfExError(ExBudget),
|
||||||
|
}
|
Loading…
Reference in New Issue