From 73e367ad534d752e496aed85e373eb49d79dff92 Mon Sep 17 00:00:00 2001 From: Kasey White Date: Fri, 26 Aug 2022 00:21:18 -0400 Subject: [PATCH] add a data builtin and do ex_mem for pairs, list, data --- Cargo.lock | 27 ++-------- add_integers.uplc | 2 +- crates/cli/Cargo.toml | 1 + crates/uplc/Cargo.toml | 2 +- crates/uplc/src/lib.rs | 7 +++ crates/uplc/src/machine.rs | 76 +++++++++++++++++++++++++-- crates/uplc/src/machine/cost_model.rs | 5 +- crates/uplc/src/machine/runtime.rs | 29 ++++++++-- crates/uplc/src/pretty.rs | 21 ++++++-- 9 files changed, 133 insertions(+), 37 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 264bd549..eb68783f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,6 +8,7 @@ version = "0.0.10" dependencies = [ "anyhow", "clap", + "hex", "uplc", ] @@ -251,16 +252,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5e575910763b21a0db7df5e142907fe944bff84d1dfc78e2ba92e7f3bdfd36b" dependencies = [ "half", - "minicbor-derive 0.11.0", -] - -[[package]] -name = "minicbor" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a20020e8e2d1881d8736f64011bb5ff99f1db9947ce3089706945c8915695cb" -dependencies = [ - "minicbor-derive 0.12.0", + "minicbor-derive", ] [[package]] @@ -274,17 +266,6 @@ dependencies = [ "syn", ] -[[package]] -name = "minicbor-derive" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8608fb1c805b5b6b3d5ab7bd95c40c396df622b64d77b2d621a5eae1eed050ee" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "num-traits" version = "0.2.15" @@ -306,7 +287,7 @@ version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dce0ea17341c1a0e43e2bb4a637740198dcb09826879ce3ac5ae1c6f4398a5d" dependencies = [ - "minicbor 0.17.1", + "minicbor", ] [[package]] @@ -646,7 +627,7 @@ dependencies = [ "cryptoxide", "flat-rs", "hex", - "minicbor 0.18.0", + "minicbor", "pallas-primitives", "peg", "pretty", diff --git a/add_integers.uplc b/add_integers.uplc index bb78578c..7ebfc193 100644 --- a/add_integers.uplc +++ b/add_integers.uplc @@ -1,5 +1,5 @@ (program 1.0.0 - [ (builtin remainderInteger) (con integer 5) (con integer 2)] + (con (pair bool integer) (True, 1)) ) diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index 58e09c0a..37c4ca03 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -13,4 +13,5 @@ authors = ["Lucas Rosa ", "Kasey White "] [dependencies] anyhow = "1.0.57" clap = { version = "3.1.14", features = ["derive"] } +hex = "0.4.3" uplc = { path = '../uplc', version = "0.0.10" } diff --git a/crates/uplc/Cargo.toml b/crates/uplc/Cargo.toml index 19063b57..181a810d 100644 --- a/crates/uplc/Cargo.toml +++ b/crates/uplc/Cargo.toml @@ -16,7 +16,7 @@ exclude = ["test_data/*"] cryptoxide = "0.4.2" flat-rs = { path = "../flat", version = "0.0.10" } hex = "0.4.3" -minicbor = { version = "0.18.0", features = ["std"] } +minicbor = { version = "0.17.1", features = ["std"] } pallas-primitives = "0.12.0" peg = "0.8.0" pretty = "0.11.3" diff --git a/crates/uplc/src/lib.rs b/crates/uplc/src/lib.rs index ce1c2da4..ba0be0b5 100644 --- a/crates/uplc/src/lib.rs +++ b/crates/uplc/src/lib.rs @@ -6,3 +6,10 @@ pub mod machine; pub mod parser; mod pretty; pub mod program_builder; + +pub use pallas_primitives::alonzo::PlutusData; +use pallas_primitives::Fragment; + +pub fn plutus_data(bytes: &[u8]) -> PlutusData { + PlutusData::decode_fragment(bytes).unwrap() +} diff --git a/crates/uplc/src/machine.rs b/crates/uplc/src/machine.rs index 3521b12d..6b80e518 100644 --- a/crates/uplc/src/machine.rs +++ b/crates/uplc/src/machine.rs @@ -1,4 +1,4 @@ -use std::rc::Rc; +use std::{collections::VecDeque, ops::Deref, rc::Rc}; use crate::{ ast::{Constant, NamedDeBruijn, Term, Type}, @@ -11,6 +11,7 @@ mod runtime; use cost_model::{ExBudget, StepKind}; pub use error::Error; +use pallas_primitives::babbage::{BigInt, PlutusData}; use self::{cost_model::CostModel, runtime::BuiltinRuntime}; @@ -436,6 +437,7 @@ impl Value { matches!(self, Value::Con(Constant::Bool(_))) } + // TODO: Make this to_ex_mem not recursive. pub fn to_ex_mem(&self) -> i64 { match self { Value::Con(c) => match c { @@ -453,8 +455,10 @@ impl Value { Constant::ProtoList(_, items) => items.iter().fold(0, |acc, constant| { acc + Value::Con(constant.clone()).to_ex_mem() }), - Constant::ProtoPair(_, _, _, _) => todo!(), - Constant::Data(_) => todo!(), + Constant::ProtoPair(_, _, l, r) => { + Value::Con(*l.clone()).to_ex_mem() + Value::Con(*r.clone()).to_ex_mem() + } + Constant::Data(item) => self.data_to_ex_mem(item), }, Value::Delay(_, _) => 1, Value::Lambda { .. } => 1, @@ -462,6 +466,70 @@ impl Value { } } + // I made data not recursive since data tends to be deeply nested + // thus causing a significant hit on performance + pub fn data_to_ex_mem(&self, data: &PlutusData) -> i64 { + let mut stack: VecDeque<&PlutusData> = VecDeque::new(); + let mut total = 0; + stack.push_front(data); + while let Some(item) = stack.pop_front() { + // each time we deconstruct a data we add 4 memory units + total += 4; + match item { + PlutusData::Constr(c) => { + // note currently tag is not factored into cost of memory + // create new stack with of items from the list of data + let mut new_stack: VecDeque<&PlutusData> = + VecDeque::from_iter(c.fields.deref().iter()); + // Append old stack to the back of the new stack + new_stack.append(&mut stack); + stack = new_stack; + } + PlutusData::Map(m) => { + let mut new_stack: VecDeque<&PlutusData>; + // create new stack with of items from the list of pairs of data + new_stack = m.deref().iter().fold(VecDeque::new(), |mut acc, d| { + acc.push_back(&d.0); + acc.push_back(&d.1); + acc + }); + // Append old stack to the back of the new stack + new_stack.append(&mut stack); + stack = new_stack; + } + PlutusData::BigInt(i) => { + if let BigInt::Int(g) = i { + let numb: i64 = (*g).try_into().unwrap(); + total += Value::Con(Constant::Integer(numb as isize)).to_ex_mem(); + } else { + unreachable!() + }; + } + PlutusData::BoundedBytes(b) => { + let byte_string: Vec = b.deref().clone(); + total += Value::Con(Constant::ByteString(byte_string)).to_ex_mem(); + } + PlutusData::Array(a) => { + // create new stack with of items from the list of data + let mut new_stack: VecDeque<&PlutusData> = + VecDeque::from_iter(a.deref().iter()); + // Append old stack to the back of the new stack + new_stack.append(&mut stack); + stack = new_stack; + } + PlutusData::ArrayIndef(a) => { + // create new stack with of items from the list of data + let mut new_stack: VecDeque<&PlutusData> = + VecDeque::from_iter(a.deref().iter()); + // Append old stack to the back of the new stack + new_stack.append(&mut stack); + stack = new_stack; + } + } + } + total + } + pub fn expect_type(&self, r#type: Type) -> Result<(), Error> { let constant: Constant = self.clone().try_into()?; @@ -522,7 +590,7 @@ impl From<&Constant> for Type { Constant::ProtoPair(t1, t2, _, _) => { Type::Pair(Box::new(t1.clone()), Box::new(t2.clone())) } - Constant::Data(_) => todo!(), + Constant::Data(_) => Type::Data, } } } diff --git a/crates/uplc/src/machine/cost_model.rs b/crates/uplc/src/machine/cost_model.rs index 143a7f4c..f75dd61b 100644 --- a/crates/uplc/src/machine/cost_model.rs +++ b/crates/uplc/src/machine/cost_model.rs @@ -825,7 +825,10 @@ impl BuiltinCosts { DefaultFunction::ListData => todo!(), DefaultFunction::IData => todo!(), DefaultFunction::BData => todo!(), - DefaultFunction::UnConstrData => todo!(), + DefaultFunction::UnConstrData => ExBudget { + mem: self.un_constr_data.mem.cost(args[0].to_ex_mem()), + cpu: self.un_constr_data.cpu.cost(args[0].to_ex_mem()), + }, DefaultFunction::UnMapData => todo!(), DefaultFunction::UnListData => todo!(), DefaultFunction::UnIData => todo!(), diff --git a/crates/uplc/src/machine/runtime.rs b/crates/uplc/src/machine/runtime.rs index bdf819c8..694984fa 100644 --- a/crates/uplc/src/machine/runtime.rs +++ b/crates/uplc/src/machine/runtime.rs @@ -1,3 +1,7 @@ +use std::ops::Deref; + +use pallas_primitives::babbage::PlutusData; + use crate::{ ast::{Constant, Type}, builtins::DefaultFunction, @@ -116,7 +120,7 @@ impl DefaultFunction { DefaultFunction::ListData => todo!(), DefaultFunction::IData => todo!(), DefaultFunction::BData => todo!(), - DefaultFunction::UnConstrData => todo!(), + DefaultFunction::UnConstrData => 1, DefaultFunction::UnMapData => todo!(), DefaultFunction::UnListData => todo!(), DefaultFunction::UnIData => todo!(), @@ -175,7 +179,7 @@ impl DefaultFunction { DefaultFunction::ListData => todo!(), DefaultFunction::IData => todo!(), DefaultFunction::BData => todo!(), - DefaultFunction::UnConstrData => todo!(), + DefaultFunction::UnConstrData => 0, DefaultFunction::UnMapData => todo!(), DefaultFunction::UnListData => todo!(), DefaultFunction::UnIData => todo!(), @@ -278,7 +282,7 @@ impl DefaultFunction { DefaultFunction::ListData => todo!(), DefaultFunction::IData => todo!(), DefaultFunction::BData => todo!(), - DefaultFunction::UnConstrData => todo!(), + DefaultFunction::UnConstrData => arg.expect_type(Type::Data), DefaultFunction::UnMapData => todo!(), DefaultFunction::UnListData => todo!(), DefaultFunction::UnIData => todo!(), @@ -625,7 +629,24 @@ impl DefaultFunction { DefaultFunction::ListData => todo!(), DefaultFunction::IData => todo!(), DefaultFunction::BData => todo!(), - DefaultFunction::UnConstrData => todo!(), + DefaultFunction::UnConstrData => match &args[0] { + Value::Con(Constant::Data(PlutusData::Constr(c))) => { + Ok(Value::Con(Constant::ProtoPair( + Type::Integer, + Type::List(Box::new(Type::Data)), + Box::new(Constant::Integer(c.tag as isize)), + Box::new(Constant::ProtoList( + Type::Data, + c.fields + .deref() + .iter() + .map(|d| Constant::Data(d.clone())) + .collect(), + )), + ))) + } + _ => unreachable!(), + }, DefaultFunction::UnMapData => todo!(), DefaultFunction::UnListData => todo!(), DefaultFunction::UnIData => todo!(), diff --git a/crates/uplc/src/pretty.rs b/crates/uplc/src/pretty.rs index 06b18fa2..b3ace6cb 100644 --- a/crates/uplc/src/pretty.rs +++ b/crates/uplc/src/pretty.rs @@ -185,7 +185,22 @@ impl Constant { RcDoc::text(","), )) .append(RcDoc::text("]")), - Constant::ProtoPair(_, _, _, _) => todo!(), + Constant::ProtoPair(r#type1, r#type2, left, right) => RcDoc::text("(") + .append( + RcDoc::text("pair") + .append(RcDoc::line()) + .append(r#type1.to_doc()) + .append(RcDoc::line()) + .append(r#type2.to_doc()), + ) + .append(RcDoc::line_()) + .append(RcDoc::text(")")) + .append(RcDoc::line()) + .append(RcDoc::text("(")) + .append(left.to_doc_list()) + .append(RcDoc::text(",")) + .append(right.to_doc_list()) + .append(RcDoc::text(")")), Constant::Data(_) => todo!(), } } @@ -206,7 +221,7 @@ impl Constant { )) .append(RcDoc::text("]")), Constant::ProtoPair(_, _, _, _) => todo!(), - Constant::Data(_) => todo!(), + Constant::Data(data) => RcDoc::text("todo"), } } } @@ -228,7 +243,7 @@ impl Type { .append(RcDoc::line_()) .append(RcDoc::text(")")), Type::Pair(_, _) => todo!(), - Type::Data => todo!(), + Type::Data => RcDoc::text("data"), } } }