Skip to content

Commit 1239fcd

Browse files
authored
Merge pull request #474 from Emurgo/ruslan/plutusv2-fix
[babbage] CostModel range check fix (for PlutusV2)
2 parents 28a140e + 8d99fad commit 1239fcd

File tree

4 files changed

+30
-26
lines changed

4 files changed

+30
-26
lines changed

rust/pkg/cardano_serialization_lib.js.flow

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1412,11 +1412,15 @@ declare export class CostModel {
14121412
static from_bytes(bytes: Uint8Array): CostModel;
14131413

14141414
/**
1415+
* Creates a new CostModels instance of an unrestricted length
14151416
* @returns {CostModel}
14161417
*/
14171418
static new(): CostModel;
14181419

14191420
/**
1421+
* Sets the cost at the specified index to the specified value.
1422+
* In case the operation index is larger than the previous largest used index,
1423+
* it will fill any inbetween indexes with zeroes
14201424
* @param {number} operation
14211425
* @param {Int} cost
14221426
* @returns {Int}

rust/src/plutus.rs

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -200,8 +200,6 @@ impl ConstrPlutusData {
200200
}
201201
}
202202

203-
const COST_MODEL_OP_COUNT: usize = 166;
204-
205203
#[wasm_bindgen]
206204
#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
207205
pub struct CostModel(Vec<Int>);
@@ -210,26 +208,32 @@ to_from_bytes!(CostModel);
210208

211209
#[wasm_bindgen]
212210
impl CostModel {
211+
212+
/// Creates a new CostModels instance of an unrestricted length
213213
pub fn new() -> Self {
214-
let mut costs = Vec::with_capacity(COST_MODEL_OP_COUNT);
215-
for _ in 0 .. COST_MODEL_OP_COUNT {
216-
costs.push(Int::new_i32(0));
217-
}
218-
Self(costs)
214+
Self(Vec::new())
219215
}
220216

217+
/// Sets the cost at the specified index to the specified value.
218+
/// In case the operation index is larger than the previous largest used index,
219+
/// it will fill any inbetween indexes with zeroes
221220
pub fn set(&mut self, operation: usize, cost: &Int) -> Result<Int, JsError> {
222-
if operation >= COST_MODEL_OP_COUNT {
223-
return Err(JsError::from_str(&format!("CostModel operation {} out of bounds. Max is {}", operation, COST_MODEL_OP_COUNT)));
221+
let len = self.0.len();
222+
let idx = operation.clone();
223+
if idx >= len {
224+
for _ in 0 .. (idx - len + 1) {
225+
self.0.push(Int::new_i32(0));
226+
}
224227
}
225-
let old = self.0[operation].clone();
226-
self.0[operation] = cost.clone();
228+
let old = self.0[idx].clone();
229+
self.0[idx] = cost.clone();
227230
Ok(old)
228231
}
229232

230233
pub fn get(&self, operation: usize) -> Result<Int, JsError> {
231-
if operation >= COST_MODEL_OP_COUNT {
232-
return Err(JsError::from_str(&format!("CostModel operation {} out of bounds. Max is {}", operation, COST_MODEL_OP_COUNT)));
234+
let max = self.0.len();
235+
if operation >= max {
236+
return Err(JsError::from_str(&format!("CostModel operation {} out of bounds. Max is {}", operation, max)));
233237
}
234238
Ok(self.0[operation].clone())
235239
}
@@ -898,7 +902,7 @@ impl Deserialize for ConstrPlutusData {
898902

899903
impl cbor_event::se::Serialize for CostModel {
900904
fn serialize<'se, W: Write>(&self, serializer: &'se mut Serializer<W>) -> cbor_event::Result<&'se mut Serializer<W>> {
901-
serializer.write_array(cbor_event::Len::Len(COST_MODEL_OP_COUNT as u64))?;
905+
serializer.write_array(cbor_event::Len::Len(self.0.len() as u64))?;
902906
for cost in &self.0 {
903907
cost.serialize(serializer)?;
904908
}
@@ -918,13 +922,6 @@ impl Deserialize for CostModel {
918922
}
919923
arr.push(Int::deserialize(raw)?);
920924
}
921-
if arr.len() != COST_MODEL_OP_COUNT {
922-
return Err(DeserializeFailure::OutOfRange{
923-
min: COST_MODEL_OP_COUNT,
924-
max: COST_MODEL_OP_COUNT,
925-
found: arr.len()
926-
}.into());
927-
}
928925
Ok(())
929926
})().map_err(|e| e.annotate("CostModel"))?;
930927
Ok(Self(arr.try_into().unwrap()))
@@ -1574,4 +1571,11 @@ mod tests {
15741571
Language::new_plutus_v2(),
15751572
);
15761573
}
1574+
1575+
#[test]
1576+
fn test_cost_model_roundtrip() {
1577+
use crate::tx_builder_constants::TxBuilderConstants;
1578+
let costmodels = TxBuilderConstants::plutus_vasil_cost_models();
1579+
assert_eq!(costmodels, Costmdls::from_bytes(costmodels.to_bytes()).unwrap());
1580+
}
15771581
}

rust/src/tx_builder.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1593,7 +1593,6 @@ impl TransactionBuilder {
15931593

15941594
#[cfg(test)]
15951595
mod tests {
1596-
use itertools::Itertools;
15971596
use super::*;
15981597
use fees::*;
15991598
use crate::fakes::{fake_base_address, fake_bytes_32, fake_key_hash, fake_tx_hash, fake_tx_input, fake_tx_input2, fake_value, fake_value2};
@@ -5901,7 +5900,7 @@ mod tests {
59015900
let fake_out = TransactionOutput::new(&collateral_return_address, &possible_ret);
59025901
let min_ada = min_ada_for_output(&fake_out, &tx_builder.config.utxo_cost()).unwrap();
59035902

5904-
let mut total_collateral_value = to_bignum(collateral_input_value).checked_sub(&min_ada).unwrap();
5903+
let total_collateral_value = to_bignum(collateral_input_value).checked_sub(&min_ada).unwrap();
59055904

59065905
tx_builder.set_total_collateral_and_return(
59075906
&total_collateral_value,
@@ -5923,8 +5922,6 @@ mod tests {
59235922
let mut tx_builder = create_reallistic_tx_builder();
59245923
tx_builder.set_fee(&to_bignum(123456));
59255924

5926-
let masset = fake_multiasset(123);
5927-
59285925
let mut inp = TxInputsBuilder::new();
59295926
let collateral_input_value = 2_000_000;
59305927
inp.add_input(

rust/src/tx_builder_constants.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use super::*;
2-
use crate::plutus::{Costmdls, CostModel, Language};
32

43
// The first element is the cost model, which is an array of 166 operations costs, ordered by asc operaion names.
54
// The second value is the pre-calculated `language_views_encoding` value required for the script hash creation.

0 commit comments

Comments
 (0)