From 9dd3ead3dff395dc3e7d8b242885418ffaa045b0 Mon Sep 17 00:00:00 2001 From: microproofs Date: Thu, 17 Oct 2024 20:01:01 -0400 Subject: [PATCH 1/3] IntegerToByteString takes in the second param itself --- crates/uplc/src/machine.rs | 2 +- crates/uplc/src/machine/cost_model.rs | 46 +++++++++++++++++---------- crates/uplc/src/machine/runtime.rs | 17 +++++----- 3 files changed, 40 insertions(+), 25 deletions(-) diff --git a/crates/uplc/src/machine.rs b/crates/uplc/src/machine.rs index 6efbdf3e..1e54f9e6 100644 --- a/crates/uplc/src/machine.rs +++ b/crates/uplc/src/machine.rs @@ -320,7 +320,7 @@ impl Machine { } fn eval_builtin_app(&mut self, runtime: BuiltinRuntime) -> Result { - let cost = runtime.to_ex_budget(&self.costs.builtin_costs); + let cost = runtime.to_ex_budget(&self.costs.builtin_costs)?; self.spend_budget(cost)?; diff --git a/crates/uplc/src/machine/cost_model.rs b/crates/uplc/src/machine/cost_model.rs index e2a1503a..9eb8124d 100644 --- a/crates/uplc/src/machine/cost_model.rs +++ b/crates/uplc/src/machine/cost_model.rs @@ -1,5 +1,6 @@ -use super::Value; +use super::{runtime, Error, Value}; use crate::builtins::DefaultFunction; +use num_bigint::BigInt; use pallas_primitives::conway::Language; use std::collections::HashMap; @@ -1741,8 +1742,8 @@ impl Default for BuiltinCosts { } impl BuiltinCosts { - pub fn to_ex_budget(&self, fun: DefaultFunction, args: &[Value]) -> ExBudget { - match fun { + pub fn to_ex_budget(&self, fun: DefaultFunction, args: &[Value]) -> Result { + Ok(match fun { DefaultFunction::AddInteger => ExBudget { mem: self .add_integer @@ -2307,18 +2308,31 @@ impl BuiltinCosts { .cpu .cost(args[0].to_ex_mem(), args[1].to_ex_mem()), }, - DefaultFunction::IntegerToByteString => ExBudget { - mem: self.integer_to_byte_string.mem.cost( - args[0].to_ex_mem(), - args[1].to_ex_mem(), - args[2].to_ex_mem(), - ), - cpu: self.integer_to_byte_string.cpu.cost( - args[0].to_ex_mem(), - args[1].to_ex_mem(), - args[2].to_ex_mem(), - ), - }, + DefaultFunction::IntegerToByteString => { + let uplc_int = args[1].unwrap_integer()?; + + if uplc_int > &BigInt::from(runtime::INTEGER_TO_BYTE_STRING_MAXIMUM_OUTPUT_LENGTH) { + return Err(Error::IntegerToByteStringSizeTooBig( + uplc_int.clone(), + runtime::INTEGER_TO_BYTE_STRING_MAXIMUM_OUTPUT_LENGTH, + )); + } + + let arg1 = u64::try_from(uplc_int).unwrap().try_into().unwrap(); + + ExBudget { + mem: self.integer_to_byte_string.mem.cost( + args[0].to_ex_mem(), + arg1, + args[2].to_ex_mem(), + ), + cpu: self.integer_to_byte_string.cpu.cost( + args[0].to_ex_mem(), + arg1, + args[2].to_ex_mem(), + ), + } + } DefaultFunction::ByteStringToInteger => ExBudget { mem: self .byte_string_to_integer @@ -2329,7 +2343,7 @@ impl BuiltinCosts { .cpu .cost(args[0].to_ex_mem(), args[1].to_ex_mem()), }, - } + }) } } diff --git a/crates/uplc/src/machine/runtime.rs b/crates/uplc/src/machine/runtime.rs index c69bd038..25387f12 100644 --- a/crates/uplc/src/machine/runtime.rs +++ b/crates/uplc/src/machine/runtime.rs @@ -31,7 +31,7 @@ const BLST_P1_COMPRESSED_SIZE: usize = 48; const BLST_P2_COMPRESSED_SIZE: usize = 96; -const INTEGER_TO_BYTE_STRING_MAXIMUM_OUTPUT_LENGTH: i64 = 8192; +pub const INTEGER_TO_BYTE_STRING_MAXIMUM_OUTPUT_LENGTH: i64 = 8192; //#[derive(std::cmp::PartialEq)] //pub enum EvalMode { @@ -96,7 +96,7 @@ impl BuiltinRuntime { Ok(()) } - pub fn to_ex_budget(&self, costs: &BuiltinCosts) -> ExBudget { + pub fn to_ex_budget(&self, costs: &BuiltinCosts) -> Result { costs.to_ex_budget(self.fun, &self.args) } } @@ -1388,12 +1388,13 @@ impl DefaultFunction { return Err(Error::IntegerToByteStringNegativeSize(size.clone())); } - if size > &INTEGER_TO_BYTE_STRING_MAXIMUM_OUTPUT_LENGTH.into() { - return Err(Error::IntegerToByteStringSizeTooBig( - size.clone(), - INTEGER_TO_BYTE_STRING_MAXIMUM_OUTPUT_LENGTH, - )); - } + // Since this is checked at cost time it is no longer needed + // if size > &INTEGER_TO_BYTE_STRING_MAXIMUM_OUTPUT_LENGTH.into() { + // return Err(Error::IntegerToByteStringSizeTooBig( + // size.clone(), + // INTEGER_TO_BYTE_STRING_MAXIMUM_OUTPUT_LENGTH, + // )); + // } if size.is_zero() && integer_log2(input.clone()) From 53685dd1d56be2b4546eca9c4bd800410873afb2 Mon Sep 17 00:00:00 2001 From: microproofs Date: Fri, 18 Oct 2024 13:07:49 -0400 Subject: [PATCH 2/3] Update cost model to properly calculate integer_to_bytearray Also fix conformance tests to match plutus --- crates/uplc/src/machine/cost_model.rs | 19 +++++++++++++------ crates/uplc/src/machine/runtime.rs | 8 ++++---- ...ct-output-extra-width.uplc.budget.expected | 2 +- ...-input-fits-max-width.uplc.budget.expected | 2 +- .../maximum-width-zero.uplc.budget.expected | 2 +- .../bounded/zero/zero.uplc.budget.expected | 2 +- .../maximum-input.uplc.budget.expected | 2 +- ...ct-output-extra-width.uplc.budget.expected | 2 +- ...-input-fits-max-width.uplc.budget.expected | 2 +- .../maximum-width-zero.uplc.budget.expected | 2 +- .../bounded/zero/zero.uplc.budget.expected | 2 +- .../maximum-input.uplc.budget.expected | 2 +- 12 files changed, 27 insertions(+), 20 deletions(-) diff --git a/crates/uplc/src/machine/cost_model.rs b/crates/uplc/src/machine/cost_model.rs index 9eb8124d..033d421a 100644 --- a/crates/uplc/src/machine/cost_model.rs +++ b/crates/uplc/src/machine/cost_model.rs @@ -1,6 +1,7 @@ use super::{runtime, Error, Value}; use crate::builtins::DefaultFunction; use num_bigint::BigInt; +use num_traits::Signed; use pallas_primitives::conway::Language; use std::collections::HashMap; @@ -2309,26 +2310,32 @@ impl BuiltinCosts { .cost(args[0].to_ex_mem(), args[1].to_ex_mem()), }, DefaultFunction::IntegerToByteString => { - let uplc_int = args[1].unwrap_integer()?; + let size = args[1].unwrap_integer()?; - if uplc_int > &BigInt::from(runtime::INTEGER_TO_BYTE_STRING_MAXIMUM_OUTPUT_LENGTH) { + if size.is_negative() { + return Err(Error::IntegerToByteStringNegativeSize(size.clone())); + } + + if size > &BigInt::from(runtime::INTEGER_TO_BYTE_STRING_MAXIMUM_OUTPUT_LENGTH) { return Err(Error::IntegerToByteStringSizeTooBig( - uplc_int.clone(), + size.clone(), runtime::INTEGER_TO_BYTE_STRING_MAXIMUM_OUTPUT_LENGTH, )); } - let arg1 = u64::try_from(uplc_int).unwrap().try_into().unwrap(); + let arg1: i64 = u64::try_from(size).unwrap().try_into().unwrap(); + + let arg1_exmem = if arg1 == 0 { 0 } else { ((arg1 - 1) / 8) + 1 }; ExBudget { mem: self.integer_to_byte_string.mem.cost( args[0].to_ex_mem(), - arg1, + arg1_exmem, args[2].to_ex_mem(), ), cpu: self.integer_to_byte_string.cpu.cost( args[0].to_ex_mem(), - arg1, + arg1_exmem, args[2].to_ex_mem(), ), } diff --git a/crates/uplc/src/machine/runtime.rs b/crates/uplc/src/machine/runtime.rs index 25387f12..bb4f44c4 100644 --- a/crates/uplc/src/machine/runtime.rs +++ b/crates/uplc/src/machine/runtime.rs @@ -1384,11 +1384,11 @@ impl DefaultFunction { let size = args[1].unwrap_integer()?; let input = args[2].unwrap_integer()?; - if size.is_negative() { - return Err(Error::IntegerToByteStringNegativeSize(size.clone())); - } - // Since this is checked at cost time it is no longer needed + // if size.is_negative() { + // return Err(Error::IntegerToByteStringNegativeSize(size.clone())); + // } + // if size > &INTEGER_TO_BYTE_STRING_MAXIMUM_OUTPUT_LENGTH.into() { // return Err(Error::IntegerToByteStringSizeTooBig( // size.clone(), diff --git a/crates/uplc/test_data/conformance/v3/builtin/semantics/integerToByteString/big-endian/bounded/correct-output-extra-width/correct-output-extra-width.uplc.budget.expected b/crates/uplc/test_data/conformance/v3/builtin/semantics/integerToByteString/big-endian/bounded/correct-output-extra-width/correct-output-extra-width.uplc.budget.expected index ce3a2a71..5e03de21 100644 --- a/crates/uplc/test_data/conformance/v3/builtin/semantics/integerToByteString/big-endian/bounded/correct-output-extra-width/correct-output-extra-width.uplc.budget.expected +++ b/crates/uplc/test_data/conformance/v3/builtin/semantics/integerToByteString/big-endian/bounded/correct-output-extra-width/correct-output-extra-width.uplc.budget.expected @@ -1,2 +1,2 @@ ({cpu: 1434707 -| mem: 801}) +| mem: 802}) diff --git a/crates/uplc/test_data/conformance/v3/builtin/semantics/integerToByteString/big-endian/bounded/max-input-fits-max-width/max-input-fits-max-width.uplc.budget.expected b/crates/uplc/test_data/conformance/v3/builtin/semantics/integerToByteString/big-endian/bounded/max-input-fits-max-width/max-input-fits-max-width.uplc.budget.expected index ef373193..288d460e 100644 --- a/crates/uplc/test_data/conformance/v3/builtin/semantics/integerToByteString/big-endian/bounded/max-input-fits-max-width/max-input-fits-max-width.uplc.budget.expected +++ b/crates/uplc/test_data/conformance/v3/builtin/semantics/integerToByteString/big-endian/bounded/max-input-fits-max-width/max-input-fits-max-width.uplc.budget.expected @@ -1,2 +1,2 @@ ({cpu: 96871400 -| mem: 801}) +| mem: 1824}) diff --git a/crates/uplc/test_data/conformance/v3/builtin/semantics/integerToByteString/big-endian/bounded/maximum-width-zero/maximum-width-zero.uplc.budget.expected b/crates/uplc/test_data/conformance/v3/builtin/semantics/integerToByteString/big-endian/bounded/maximum-width-zero/maximum-width-zero.uplc.budget.expected index ce3a2a71..e05af8ae 100644 --- a/crates/uplc/test_data/conformance/v3/builtin/semantics/integerToByteString/big-endian/bounded/maximum-width-zero/maximum-width-zero.uplc.budget.expected +++ b/crates/uplc/test_data/conformance/v3/builtin/semantics/integerToByteString/big-endian/bounded/maximum-width-zero/maximum-width-zero.uplc.budget.expected @@ -1,2 +1,2 @@ ({cpu: 1434707 -| mem: 801}) +| mem: 1824}) diff --git a/crates/uplc/test_data/conformance/v3/builtin/semantics/integerToByteString/big-endian/bounded/zero/zero.uplc.budget.expected b/crates/uplc/test_data/conformance/v3/builtin/semantics/integerToByteString/big-endian/bounded/zero/zero.uplc.budget.expected index ce3a2a71..5e03de21 100644 --- a/crates/uplc/test_data/conformance/v3/builtin/semantics/integerToByteString/big-endian/bounded/zero/zero.uplc.budget.expected +++ b/crates/uplc/test_data/conformance/v3/builtin/semantics/integerToByteString/big-endian/bounded/zero/zero.uplc.budget.expected @@ -1,2 +1,2 @@ ({cpu: 1434707 -| mem: 801}) +| mem: 802}) diff --git a/crates/uplc/test_data/conformance/v3/builtin/semantics/integerToByteString/big-endian/unbounded/maximum-input/maximum-input.uplc.budget.expected b/crates/uplc/test_data/conformance/v3/builtin/semantics/integerToByteString/big-endian/unbounded/maximum-input/maximum-input.uplc.budget.expected index ef373193..288d460e 100644 --- a/crates/uplc/test_data/conformance/v3/builtin/semantics/integerToByteString/big-endian/unbounded/maximum-input/maximum-input.uplc.budget.expected +++ b/crates/uplc/test_data/conformance/v3/builtin/semantics/integerToByteString/big-endian/unbounded/maximum-input/maximum-input.uplc.budget.expected @@ -1,2 +1,2 @@ ({cpu: 96871400 -| mem: 801}) +| mem: 1824}) diff --git a/crates/uplc/test_data/conformance/v3/builtin/semantics/integerToByteString/little-endian/bounded/correct-output-extra-width/correct-output-extra-width.uplc.budget.expected b/crates/uplc/test_data/conformance/v3/builtin/semantics/integerToByteString/little-endian/bounded/correct-output-extra-width/correct-output-extra-width.uplc.budget.expected index ce3a2a71..5e03de21 100644 --- a/crates/uplc/test_data/conformance/v3/builtin/semantics/integerToByteString/little-endian/bounded/correct-output-extra-width/correct-output-extra-width.uplc.budget.expected +++ b/crates/uplc/test_data/conformance/v3/builtin/semantics/integerToByteString/little-endian/bounded/correct-output-extra-width/correct-output-extra-width.uplc.budget.expected @@ -1,2 +1,2 @@ ({cpu: 1434707 -| mem: 801}) +| mem: 802}) diff --git a/crates/uplc/test_data/conformance/v3/builtin/semantics/integerToByteString/little-endian/bounded/max-input-fits-max-width/max-input-fits-max-width.uplc.budget.expected b/crates/uplc/test_data/conformance/v3/builtin/semantics/integerToByteString/little-endian/bounded/max-input-fits-max-width/max-input-fits-max-width.uplc.budget.expected index ef373193..288d460e 100644 --- a/crates/uplc/test_data/conformance/v3/builtin/semantics/integerToByteString/little-endian/bounded/max-input-fits-max-width/max-input-fits-max-width.uplc.budget.expected +++ b/crates/uplc/test_data/conformance/v3/builtin/semantics/integerToByteString/little-endian/bounded/max-input-fits-max-width/max-input-fits-max-width.uplc.budget.expected @@ -1,2 +1,2 @@ ({cpu: 96871400 -| mem: 801}) +| mem: 1824}) diff --git a/crates/uplc/test_data/conformance/v3/builtin/semantics/integerToByteString/little-endian/bounded/maximum-width-zero/maximum-width-zero.uplc.budget.expected b/crates/uplc/test_data/conformance/v3/builtin/semantics/integerToByteString/little-endian/bounded/maximum-width-zero/maximum-width-zero.uplc.budget.expected index ce3a2a71..e05af8ae 100644 --- a/crates/uplc/test_data/conformance/v3/builtin/semantics/integerToByteString/little-endian/bounded/maximum-width-zero/maximum-width-zero.uplc.budget.expected +++ b/crates/uplc/test_data/conformance/v3/builtin/semantics/integerToByteString/little-endian/bounded/maximum-width-zero/maximum-width-zero.uplc.budget.expected @@ -1,2 +1,2 @@ ({cpu: 1434707 -| mem: 801}) +| mem: 1824}) diff --git a/crates/uplc/test_data/conformance/v3/builtin/semantics/integerToByteString/little-endian/bounded/zero/zero.uplc.budget.expected b/crates/uplc/test_data/conformance/v3/builtin/semantics/integerToByteString/little-endian/bounded/zero/zero.uplc.budget.expected index ce3a2a71..5e03de21 100644 --- a/crates/uplc/test_data/conformance/v3/builtin/semantics/integerToByteString/little-endian/bounded/zero/zero.uplc.budget.expected +++ b/crates/uplc/test_data/conformance/v3/builtin/semantics/integerToByteString/little-endian/bounded/zero/zero.uplc.budget.expected @@ -1,2 +1,2 @@ ({cpu: 1434707 -| mem: 801}) +| mem: 802}) diff --git a/crates/uplc/test_data/conformance/v3/builtin/semantics/integerToByteString/little-endian/unbounded/maximum-input/maximum-input.uplc.budget.expected b/crates/uplc/test_data/conformance/v3/builtin/semantics/integerToByteString/little-endian/unbounded/maximum-input/maximum-input.uplc.budget.expected index ef373193..288d460e 100644 --- a/crates/uplc/test_data/conformance/v3/builtin/semantics/integerToByteString/little-endian/unbounded/maximum-input/maximum-input.uplc.budget.expected +++ b/crates/uplc/test_data/conformance/v3/builtin/semantics/integerToByteString/little-endian/unbounded/maximum-input/maximum-input.uplc.budget.expected @@ -1,2 +1,2 @@ ({cpu: 96871400 -| mem: 801}) +| mem: 1824}) From 365b3bf5bf74afaa4a44140f73aa10ad8bd01b0d Mon Sep 17 00:00:00 2001 From: KtorZ Date: Sat, 19 Oct 2024 11:00:46 +0200 Subject: [PATCH 3/3] Remove dead-code and clarify note. --- crates/uplc/src/machine/runtime.rs | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/crates/uplc/src/machine/runtime.rs b/crates/uplc/src/machine/runtime.rs index bb4f44c4..124212a8 100644 --- a/crates/uplc/src/machine/runtime.rs +++ b/crates/uplc/src/machine/runtime.rs @@ -33,12 +33,6 @@ const BLST_P2_COMPRESSED_SIZE: usize = 96; pub const INTEGER_TO_BYTE_STRING_MAXIMUM_OUTPUT_LENGTH: i64 = 8192; -//#[derive(std::cmp::PartialEq)] -//pub enum EvalMode { -// Immediate, -// Deferred, -//} - pub enum BuiltinSemantics { V1, V2, @@ -1384,17 +1378,12 @@ impl DefaultFunction { let size = args[1].unwrap_integer()?; let input = args[2].unwrap_integer()?; - // Since this is checked at cost time it is no longer needed - // if size.is_negative() { - // return Err(Error::IntegerToByteStringNegativeSize(size.clone())); - // } - - // if size > &INTEGER_TO_BYTE_STRING_MAXIMUM_OUTPUT_LENGTH.into() { - // return Err(Error::IntegerToByteStringSizeTooBig( - // size.clone(), - // INTEGER_TO_BYTE_STRING_MAXIMUM_OUTPUT_LENGTH, - // )); - // } + // NOTE: + // We ought to also check for negative size and too large sizes. These checks + // however happens prior to calling the builtin as part of the costing step. So by + // the time we reach this builtin call, the size can be assumed to be + // + // >= 0 && < INTEGER_TO_BYTE_STRING_MAXIMUM_OUTPUT_LENGTH if size.is_zero() && integer_log2(input.clone())