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>,
|
||||
}
|
||||
|
||||
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.
|
||||
/// 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`,
|
||||
|
@ -374,14 +400,3 @@ impl From<Term<FakeNamedDeBruijn>> for Term<NamedDeBruijn> {
|
|||
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,
|
||||
BBuiltin = 6,
|
||||
}
|
||||
|
||||
impl TryFrom<u8> for StepKind {
|
||||
type Error = de::Error;
|
||||
|
||||
|
@ -41,6 +42,7 @@ enum ExBudgetCategory {
|
|||
BBuiltinApp(DefaultFunction),
|
||||
BStartup,
|
||||
}
|
||||
|
||||
/// Can be negative
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
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 flat;
|
||||
pub mod interpreter;
|
||||
pub mod machine;
|
||||
pub mod parser;
|
||||
mod pretty;
|
||||
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