Detect difference in cost model length to maintain compatability with mainnet and testnet

This commit is contained in:
microproofs 2024-11-30 13:12:51 +07:00
parent 4839273449
commit 5cf3275793
No known key found for this signature in database
GPG Key ID: 14F93C84DE6AFD17
4 changed files with 231 additions and 86 deletions

View File

@ -505,7 +505,7 @@ pub fn plutus(id_gen: &IdGenerator) -> TypeInfo {
annotations: HashMap::new(), annotations: HashMap::new(),
}; };
for builtin in DefaultFunction::iter() { for builtin in DefaultFunction::iter().take(75) {
let value = from_default_function(builtin, id_gen); let value = from_default_function(builtin, id_gen);
plutus.values.insert(builtin.aiken_name(), value); plutus.values.insert(builtin.aiken_name(), value);

View File

@ -1,6 +1,5 @@
use super::{runtime, Error, Value}; use super::{value::integer_log2, Error, Value};
use crate::builtins::DefaultFunction; use crate::builtins::DefaultFunction;
use num_bigint::BigInt;
use num_traits::Signed; use num_traits::Signed;
use pallas_primitives::conway::Language; use pallas_primitives::conway::Language;
use std::collections::HashMap; use std::collections::HashMap;
@ -356,6 +355,7 @@ pub struct BuiltinCosts {
count_set_bits: CostingFun<OneArgument>, count_set_bits: CostingFun<OneArgument>,
find_first_set_bit: CostingFun<OneArgument>, find_first_set_bit: CostingFun<OneArgument>,
ripemd_160: CostingFun<OneArgument>, ripemd_160: CostingFun<OneArgument>,
exp_mod_int: CostingFun<ThreeArguments>,
} }
impl BuiltinCosts { impl BuiltinCosts {
@ -850,6 +850,10 @@ impl BuiltinCosts {
cpu: OneArgument::ConstantCost(30000000000), cpu: OneArgument::ConstantCost(30000000000),
mem: OneArgument::ConstantCost(30000000000), mem: OneArgument::ConstantCost(30000000000),
}, },
exp_mod_int: CostingFun {
cpu: ThreeArguments::ConstantCost(30000000000),
mem: ThreeArguments::ConstantCost(30000000000),
},
} }
} }
@ -1344,6 +1348,10 @@ impl BuiltinCosts {
cpu: OneArgument::ConstantCost(30000000000), cpu: OneArgument::ConstantCost(30000000000),
mem: OneArgument::ConstantCost(30000000000), mem: OneArgument::ConstantCost(30000000000),
}, },
exp_mod_int: CostingFun {
cpu: ThreeArguments::ConstantCost(30000000000),
mem: ThreeArguments::ConstantCost(30000000000),
},
} }
} }
@ -1948,6 +1956,11 @@ impl BuiltinCosts {
}), }),
mem: OneArgument::ConstantCost(3), mem: OneArgument::ConstantCost(3),
}, },
// Not yet properly costed
exp_mod_int: CostingFun {
cpu: ThreeArguments::ConstantCost(30000000000),
mem: ThreeArguments::ConstantCost(30000000000),
},
} }
} }
} }
@ -2526,32 +2539,17 @@ impl BuiltinCosts {
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()), .cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
}, },
DefaultFunction::IntegerToByteString => { DefaultFunction::IntegerToByteString => {
let size = args[1].unwrap_integer()?; let size = args[1].cost_as_size()?;
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 { ExBudget {
mem: self.integer_to_byte_string.mem.cost( mem: self.integer_to_byte_string.mem.cost(
args[0].to_ex_mem(), args[0].to_ex_mem(),
arg1_exmem, size,
args[2].to_ex_mem(), args[2].to_ex_mem(),
), ),
cpu: self.integer_to_byte_string.cpu.cost( cpu: self.integer_to_byte_string.cpu.cost(
args[0].to_ex_mem(), args[0].to_ex_mem(),
arg1_exmem, size,
args[2].to_ex_mem(), args[2].to_ex_mem(),
), ),
} }
@ -2616,16 +2614,87 @@ impl BuiltinCosts {
.cpu .cpu
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()), .cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
}, },
DefaultFunction::WriteBits => todo!(), DefaultFunction::WriteBits => {
DefaultFunction::ReplicateByte => todo!(), let list = args[1].unwrap_list().unwrap();
DefaultFunction::ShiftByteString => todo!(),
DefaultFunction::RotateByteString => todo!(), ExBudget {
DefaultFunction::CountSetBits => todo!(), mem: self.write_bits.mem.cost(
DefaultFunction::FindFirstSetBit => todo!(), args[0].to_ex_mem(),
DefaultFunction::Ripemd_160 => todo!(), list.1.len() as i64,
DefaultFunction::ExpModInteger => todo!(), args[2].to_ex_mem(),
// DefaultFunction::CaseList => todo!(), ),
// DefaultFunction::CaseData => todo!(), cpu: self.write_bits.cpu.cost(
args[0].to_ex_mem(),
list.1.len() as i64,
args[2].to_ex_mem(),
),
}
}
DefaultFunction::ReplicateByte => {
let size = args[0].cost_as_size()?;
ExBudget {
mem: self.replicate_byte.mem.cost(size, args[1].to_ex_mem()),
cpu: self.replicate_byte.cpu.cost(size, args[1].to_ex_mem()),
}
}
DefaultFunction::ShiftByteString => {
let literal = args[1].unwrap_integer()?;
let arg1: i64 = u64::try_from(literal.abs()).unwrap().try_into().unwrap();
ExBudget {
mem: self.shift_byte_string.mem.cost(args[0].to_ex_mem(), arg1),
cpu: self.shift_byte_string.cpu.cost(args[0].to_ex_mem(), arg1),
}
}
DefaultFunction::RotateByteString => {
let literal = args[1].unwrap_integer()?;
let arg1: i64 = u64::try_from(literal.abs()).unwrap().try_into().unwrap();
ExBudget {
mem: self.rotate_byte_string.mem.cost(args[0].to_ex_mem(), arg1),
cpu: self.rotate_byte_string.cpu.cost(args[0].to_ex_mem(), arg1),
}
}
DefaultFunction::CountSetBits => ExBudget {
mem: self.count_set_bits.mem.cost(args[0].to_ex_mem()),
cpu: self.count_set_bits.cpu.cost(args[0].to_ex_mem()),
},
DefaultFunction::FindFirstSetBit => ExBudget {
mem: self.find_first_set_bit.mem.cost(args[0].to_ex_mem()),
cpu: self.find_first_set_bit.cpu.cost(args[0].to_ex_mem()),
},
DefaultFunction::Ripemd_160 => ExBudget {
mem: self.ripemd_160.mem.cost(args[0].to_ex_mem()),
cpu: self.ripemd_160.cpu.cost(args[0].to_ex_mem()),
},
DefaultFunction::ExpModInteger => {
let arg3 = args[2].unwrap_integer()?;
if arg3.lt(&(0.into())) {
return Err(Error::OutsideNaturalBounds(arg3.clone()));
}
let arg3_exmem = if *arg3 == 0.into() {
1
} else {
(integer_log2(arg3.abs()) / 64) + 1
};
ExBudget {
mem: self.exp_mod_int.mem.cost(
args[0].to_ex_mem(),
args[1].to_ex_mem(),
arg3_exmem,
),
cpu: self.exp_mod_int.cpu.cost(
args[0].to_ex_mem(),
args[1].to_ex_mem(),
arg3_exmem,
),
}
}
}) })
} }
} }
@ -2982,12 +3051,8 @@ pub fn initialize_cost_model(version: &Language, costs: &[i64]) -> CostModel {
} }
} }
Language::PlutusV3 => { Language::PlutusV3 => {
assert!( // We can't have an assert here. This will literally break mainnet
costs.len() == 297, let mut main: HashMap<&str, i64> = hashmap! {
"expecting 297 cost parameters, but got {:?}",
costs.len()
);
hashmap! {
"add_integer-cpu-arguments-intercept" => costs[0], "add_integer-cpu-arguments-intercept" => costs[0],
"add_integer-cpu-arguments-slope" => costs[1], "add_integer-cpu-arguments-slope" => costs[1],
"add_integer-mem-arguments-intercept" => costs[2], "add_integer-mem-arguments-intercept" => costs[2],
@ -3239,53 +3304,62 @@ pub fn initialize_cost_model(version: &Language, costs: &[i64]) -> CostModel {
"byteStringToInteger-cpu-arguments-c2" => costs[248], "byteStringToInteger-cpu-arguments-c2" => costs[248],
"byteStringToInteger-mem-arguments-intercept" => costs[249], "byteStringToInteger-mem-arguments-intercept" => costs[249],
"byteStringToInteger-mem-arguments-slope" => costs[250], "byteStringToInteger-mem-arguments-slope" => costs[250],
"andByteString-cpu-arguments-intercept"=> costs[251], };
"andByteString-cpu-arguments-slope1"=> costs[252],
"andByteString-cpu-arguments-slope2"=> costs[253], if costs.len() == 297 {
"andByteString-memory-arguments-intercept"=> costs[254], let test = hashmap! {
"andByteString-memory-arguments-slope"=> costs[255], "andByteString-cpu-arguments-intercept"=> costs[251],
"orByteString-cpu-arguments-intercept"=> costs[256], "andByteString-cpu-arguments-slope1"=> costs[252],
"orByteString-cpu-arguments-slope1"=> costs[257], "andByteString-cpu-arguments-slope2"=> costs[253],
"orByteString-cpu-arguments-slope2"=> costs[258], "andByteString-memory-arguments-intercept"=> costs[254],
"orByteString-memory-arguments-intercept"=> costs[259], "andByteString-memory-arguments-slope"=> costs[255],
"orByteString-memory-arguments-slope"=> costs[260], "orByteString-cpu-arguments-intercept"=> costs[256],
"xorByteString-cpu-arguments-intercept"=> costs[261], "orByteString-cpu-arguments-slope1"=> costs[257],
"xorByteString-cpu-arguments-slope1"=> costs[262], "orByteString-cpu-arguments-slope2"=> costs[258],
"xorByteString-cpu-arguments-slope2"=> costs[263], "orByteString-memory-arguments-intercept"=> costs[259],
"xorByteString-memory-arguments-intercept"=> costs[264], "orByteString-memory-arguments-slope"=> costs[260],
"xorByteString-memory-arguments-slope"=> costs[265], "xorByteString-cpu-arguments-intercept"=> costs[261],
"complementByteString-cpu-arguments-intercept"=> costs[266], "xorByteString-cpu-arguments-slope1"=> costs[262],
"complementByteString-cpu-arguments-slope"=> costs[267], "xorByteString-cpu-arguments-slope2"=> costs[263],
"complementByteString-memory-arguments-intercept"=> costs[268], "xorByteString-memory-arguments-intercept"=> costs[264],
"complementByteString-memory-arguments-slope"=> costs[269], "xorByteString-memory-arguments-slope"=> costs[265],
"readBit-cpu-arguments"=> costs[270], "complementByteString-cpu-arguments-intercept"=> costs[266],
"readBit-memory-arguments"=> costs[271], "complementByteString-cpu-arguments-slope"=> costs[267],
"writeBits-cpu-arguments-intercept"=> costs[272], "complementByteString-memory-arguments-intercept"=> costs[268],
"writeBits-cpu-arguments-slope"=> costs[273], "complementByteString-memory-arguments-slope"=> costs[269],
"writeBits-memory-arguments-intercept"=> costs[274], "readBit-cpu-arguments"=> costs[270],
"writeBits-memory-arguments-slope"=> costs[275], "readBit-memory-arguments"=> costs[271],
"replicateByte-cpu-arguments-intercept"=> costs[276], "writeBits-cpu-arguments-intercept"=> costs[272],
"replicateByte-cpu-arguments-slope"=> costs[277], "writeBits-cpu-arguments-slope"=> costs[273],
"replicateByte-memory-arguments-intercept"=> costs[278], "writeBits-memory-arguments-intercept"=> costs[274],
"replicateByte-memory-arguments-slope"=> costs[279], "writeBits-memory-arguments-slope"=> costs[275],
"shiftByteString-cpu-arguments-intercept"=> costs[280], "replicateByte-cpu-arguments-intercept"=> costs[276],
"shiftByteString-cpu-arguments-slope"=> costs[281], "replicateByte-cpu-arguments-slope"=> costs[277],
"shiftByteString-memory-arguments-intercept"=> costs[282], "replicateByte-memory-arguments-intercept"=> costs[278],
"shiftByteString-memory-arguments-slope"=> costs[283], "replicateByte-memory-arguments-slope"=> costs[279],
"rotateByteString-cpu-arguments-intercept"=> costs[284], "shiftByteString-cpu-arguments-intercept"=> costs[280],
"rotateByteString-cpu-arguments-slope"=> costs[285], "shiftByteString-cpu-arguments-slope"=> costs[281],
"rotateByteString-memory-arguments-intercept"=> costs[286], "shiftByteString-memory-arguments-intercept"=> costs[282],
"rotateByteString-memory-arguments-slope"=> costs[287], "shiftByteString-memory-arguments-slope"=> costs[283],
"countSetBits-cpu-arguments-intercept"=> costs[288], "rotateByteString-cpu-arguments-intercept"=> costs[284],
"countSetBits-cpu-arguments-slope"=> costs[289], "rotateByteString-cpu-arguments-slope"=> costs[285],
"countSetBits-memory-arguments"=> costs[290], "rotateByteString-memory-arguments-intercept"=> costs[286],
"findFirstSetBit-cpu-arguments-intercept"=> costs[291], "rotateByteString-memory-arguments-slope"=> costs[287],
"findFirstSetBit-cpu-arguments-slope"=> costs[292], "countSetBits-cpu-arguments-intercept"=> costs[288],
"findFirstSetBit-memory-arguments"=> costs[293], "countSetBits-cpu-arguments-slope"=> costs[289],
"ripemd_160-cpu-arguments-intercept"=> costs[294], "countSetBits-memory-arguments"=> costs[290],
"ripemd_160-cpu-arguments-slope"=> costs[295], "findFirstSetBit-cpu-arguments-intercept"=> costs[291],
"ripemd_160-memory-arguments"=> costs[296], "findFirstSetBit-cpu-arguments-slope"=> costs[292],
"findFirstSetBit-memory-arguments"=> costs[293],
"ripemd_160-cpu-arguments-intercept"=> costs[294],
"ripemd_160-cpu-arguments-slope"=> costs[295],
"ripemd_160-memory-arguments"=> costs[296],
};
Extend::extend::<HashMap<&str, i64>>(&mut main, test);
} }
main
} }
}; };
@ -5025,6 +5099,24 @@ pub fn initialize_cost_model(version: &Language, costs: &[i64]) -> CostModel {
), ),
}, },
}, },
exp_mod_int: match version {
Language::PlutusV1 | Language::PlutusV2 => CostingFun {
cpu: ThreeArguments::ConstantCost(30000000000),
mem: ThreeArguments::ConstantCost(30000000000),
},
Language::PlutusV3 => CostingFun {
cpu: ThreeArguments::ConstantCost(
*cost_map
.get("expModInteger-cpu-arguments")
.unwrap_or(&30000000000),
),
mem: ThreeArguments::ConstantCost(
*cost_map
.get("expModInteger-memory-arguments")
.unwrap_or(&30000000000),
),
},
},
}, },
} }
} }
@ -5152,8 +5244,8 @@ impl ThreeArguments {
y y
} }
} }
ThreeArguments::LinearInMaxYZ(linear_size) => todo!(), ThreeArguments::LinearInMaxYZ(l) => y.max(z) * l.slope + l.intercept,
ThreeArguments::LinearInYandZ(two_variable_linear_size) => todo!(), ThreeArguments::LinearInYandZ(l) => y * l.slope1 + z * l.slope2 + l.intercept,
} }
} }
} }
@ -5327,6 +5419,33 @@ mod tests {
assert_eq!(CostModel::v2(), cost_model); assert_eq!(CostModel::v2(), cost_model);
} }
#[test]
fn assert_default_cost_model_v3_mainnet_2024_11_30() {
let costs: Vec<i64> = vec![
100788, 420, 1, 1, 1000, 173, 0, 1, 1000, 59957, 4, 1, 11183, 32, 201305, 8356, 4,
16000, 100, 16000, 100, 16000, 100, 16000, 100, 16000, 100, 16000, 100, 100, 100,
16000, 100, 94375, 32, 132994, 32, 61462, 4, 72010, 178, 0, 1, 22151, 32, 91189, 769,
4, 2, 85848, 123203, 7305, -900, 1716, 549, 57, 85848, 0, 1, 1, 1000, 42921, 4, 2,
24548, 29498, 38, 1, 898148, 27279, 1, 51775, 558, 1, 39184, 1000, 60594, 1, 141895,
32, 83150, 32, 15299, 32, 76049, 1, 13169, 4, 22100, 10, 28999, 74, 1, 28999, 74, 1,
43285, 552, 1, 44749, 541, 1, 33852, 32, 68246, 32, 72362, 32, 7243, 32, 7391, 32,
11546, 32, 85848, 123203, 7305, -900, 1716, 549, 57, 85848, 0, 1, 90434, 519, 0, 1,
74433, 32, 85848, 123203, 7305, -900, 1716, 549, 57, 85848, 0, 1, 1, 85848, 123203,
7305, -900, 1716, 549, 57, 85848, 0, 1, 955506, 213312, 0, 2, 270652, 22588, 4,
1457325, 64566, 4, 20467, 1, 4, 0, 141992, 32, 100788, 420, 1, 1, 81663, 32, 59498, 32,
20142, 32, 24588, 32, 20744, 32, 25933, 32, 24623, 32, 43053543, 10, 53384111, 14333,
10, 43574283, 26308, 10, 16000, 100, 16000, 100, 962335, 18, 2780678, 6, 442008, 1,
52538055, 3756, 18, 267929, 18, 76433006, 8868, 18, 52948122, 18, 1995836, 36, 3227919,
12, 901022, 1, 166917843, 4307, 36, 284546, 36, 158221314, 26549, 36, 74698472, 36,
333849714, 1, 254006273, 72, 2174038, 72, 2261318, 64571, 4, 207616, 8310, 4, 1293828,
28716, 63, 0, 1, 1006041, 43623, 251, 0, 1,
];
let cost_model = initialize_cost_model(&Language::PlutusV3, &costs);
assert_eq!(CostModel::v3(), cost_model);
}
#[test] #[test]
fn assert_default_cost_model_v3_preprod_2024_11_22() { fn assert_default_cost_model_v3_preprod_2024_11_22() {
let costs: Vec<i64> = vec![ let costs: Vec<i64> = vec![

View File

@ -120,6 +120,8 @@ pub enum Error {
DeserialisationError(String, Value), DeserialisationError(String, Value),
#[error("integer overflow")] #[error("integer overflow")]
OverflowError, OverflowError,
#[error("{0} is not within the bounds of Natural")]
OutsideNaturalBounds(BigInt),
#[error("blst error {0:?}")] #[error("blst error {0:?}")]
Blst(blst::BLST_ERROR), Blst(blst::BLST_ERROR),
#[error("blst::hashToGroup")] #[error("blst::hashToGroup")]

View File

@ -1,4 +1,7 @@
use super::{runtime::BuiltinRuntime, Error}; use super::{
runtime::{self, BuiltinRuntime},
Error,
};
use crate::{ use crate::{
ast::{Constant, NamedDeBruijn, Term, Type}, ast::{Constant, NamedDeBruijn, Term, Type},
builtins::DefaultFunction, builtins::DefaultFunction,
@ -208,6 +211,27 @@ impl Value {
matches!(self, Value::Con(b) if matches!(b.as_ref(), Constant::Bool(_))) matches!(self, Value::Con(b) if matches!(b.as_ref(), Constant::Bool(_)))
} }
pub fn cost_as_size(&self) -> Result<i64, Error> {
let size = self.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 };
Ok(arg1_exmem)
}
// TODO: Make this to_ex_mem not recursive. // TODO: Make this to_ex_mem not recursive.
pub fn to_ex_mem(&self) -> i64 { pub fn to_ex_mem(&self) -> i64 {
match self { match self {