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..033d421a 100644 --- a/crates/uplc/src/machine/cost_model.rs +++ b/crates/uplc/src/machine/cost_model.rs @@ -1,5 +1,7 @@ -use super::Value; +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; @@ -1741,8 +1743,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 +2309,37 @@ 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 size = args[1].unwrap_integer()?; + + 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( + size.clone(), + runtime::INTEGER_TO_BYTE_STRING_MAXIMUM_OUTPUT_LENGTH, + )); + } + + 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_exmem, + args[2].to_ex_mem(), + ), + cpu: self.integer_to_byte_string.cpu.cost( + args[0].to_ex_mem(), + arg1_exmem, + args[2].to_ex_mem(), + ), + } + } DefaultFunction::ByteStringToInteger => ExBudget { mem: self .byte_string_to_integer @@ -2329,7 +2350,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..124212a8 100644 --- a/crates/uplc/src/machine/runtime.rs +++ b/crates/uplc/src/machine/runtime.rs @@ -31,13 +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; - -//#[derive(std::cmp::PartialEq)] -//pub enum EvalMode { -// Immediate, -// Deferred, -//} +pub const INTEGER_TO_BYTE_STRING_MAXIMUM_OUTPUT_LENGTH: i64 = 8192; pub enum BuiltinSemantics { V1, @@ -96,7 +90,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) } } @@ -1384,16 +1378,12 @@ impl DefaultFunction { let size = args[1].unwrap_integer()?; let input = args[2].unwrap_integer()?; - 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()) 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})