Skip to content

Commit cec2dd7

Browse files
authored
Merge pull request #478 from Emurgo/ruslan/language-encoding-fix
Release / Babbage 11.0.0-rc.6
2 parents a58bfa5 + 70fd854 commit cec2dd7

File tree

9 files changed

+160
-27
lines changed

9 files changed

+160
-27
lines changed

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "cardano-serialization-lib",
3-
"version": "11.0.0-rc.1",
3+
"version": "11.0.0-rc.6",
44
"description": "(De)serialization functions for the Cardano blockchain along with related utility functions",
55
"scripts": {
66
"rust:build-nodejs": "(rimraf ./rust/pkg && cd rust; wasm-pack build --target=nodejs; wasm-pack pack) && npm run js:flowgen",

rust/Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rust/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "cardano-serialization-lib"
3-
version = "11.0.0-rc.1"
3+
version = "11.0.0-rc.6"
44
edition = "2018"
55
authors = ["EMURGO"]
66
license = "MIT"

rust/pkg/cardano_serialization_lib.js.flow

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5953,6 +5953,9 @@ declare export class TransactionBuilder {
59535953
* in the builder to be used when building the tx body.
59545954
* In case there are no plutus input witnesses present - nothing will change
59555955
* You can set specific hash value using `.set_script_data_hash`
5956+
* NOTE: this function will check which language versions are used in the present scripts
5957+
* and will assert and require for a corresponding cost-model to be present in the passed map.
5958+
* Only the cost-models for the present language versions will be used in the hash calculation.
59565959
* @param {Costmdls} cost_models
59575960
*/
59585961
calc_script_data_hash(cost_models: Costmdls): void;

rust/src/plutus.rs

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -279,25 +279,39 @@ impl Costmdls {
279279

280280
pub(crate) fn language_views_encoding(&self) -> Vec<u8> {
281281
let mut serializer = Serializer::new_vec();
282-
let mut keys_bytes: Vec<(Language, Vec<u8>)> = self.0.iter().map(|(k, _v)| (k.clone(), k.to_bytes())).collect();
282+
fn key_len(l: &Language) -> usize {
283+
if l.kind() == LanguageKind::PlutusV1 {
284+
let mut serializer = Serializer::new_vec();
285+
serializer.write_bytes(l.to_bytes()).unwrap();
286+
serializer.finalize().len()
287+
} else {
288+
l.to_bytes().len()
289+
}
290+
}
291+
let mut keys: Vec<Language> = self.0.iter().map(|(k, _v)| k.clone()).collect();
283292
// keys must be in canonical ordering first
284-
keys_bytes.sort_by(|lhs, rhs| match lhs.1.len().cmp(&rhs.1.len()) {
285-
std::cmp::Ordering::Equal => lhs.1.cmp(&rhs.1),
293+
keys.sort_by(|lhs, rhs| match key_len(lhs).cmp(&key_len(rhs)) {
294+
std::cmp::Ordering::Equal => lhs.cmp(&rhs),
286295
len_order => len_order,
287296
});
288297
serializer.write_map(cbor_event::Len::Len(self.0.len() as u64)).unwrap();
289-
for (key, key_bytes) in keys_bytes.iter() {
290-
serializer.write_bytes(key_bytes).unwrap();
291-
let cost_model = self.0.get(&key).unwrap();
292-
// Due to a bug in the cardano-node input-output-hk/cardano-ledger-specs/issues/2512
293-
// we must use indefinite length serialization in this inner bytestring to match it
294-
let mut cost_model_serializer = Serializer::new_vec();
295-
cost_model_serializer.write_array(cbor_event::Len::Indefinite).unwrap();
296-
for cost in &cost_model.0 {
297-
cost.serialize(&mut cost_model_serializer).unwrap();
298+
for key in keys.iter() {
299+
if key.kind() == LanguageKind::PlutusV1 {
300+
serializer.write_bytes(key.to_bytes()).unwrap();
301+
let cost_model = self.0.get(&key).unwrap();
302+
// Due to a bug in the cardano-node input-output-hk/cardano-ledger-specs/issues/2512
303+
// we must use indefinite length serialization in this inner bytestring to match it
304+
let mut cost_model_serializer = Serializer::new_vec();
305+
cost_model_serializer.write_array(cbor_event::Len::Indefinite).unwrap();
306+
for cost in &cost_model.0 {
307+
cost.serialize(&mut cost_model_serializer).unwrap();
308+
}
309+
cost_model_serializer.write_special(cbor_event::Special::Break).unwrap();
310+
serializer.write_bytes(cost_model_serializer.finalize()).unwrap();
311+
} else {
312+
serializer.serialize(key).unwrap();
313+
serializer.serialize(self.0.get(&key).unwrap()).unwrap();
298314
}
299-
cost_model_serializer.write_special(cbor_event::Special::Break).unwrap();
300-
serializer.write_bytes(cost_model_serializer.finalize()).unwrap();
301315
}
302316
let out = serializer.finalize();
303317
println!("language_views = {}", hex::encode(out.clone()));
@@ -400,7 +414,7 @@ impl Language {
400414

401415
#[wasm_bindgen]
402416
#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
403-
pub struct Languages(Vec<Language>);
417+
pub struct Languages(pub(crate) Vec<Language>);
404418

405419
#[wasm_bindgen]
406420
impl Languages {
@@ -419,6 +433,10 @@ impl Languages {
419433
pub fn add(&mut self, elem: Language) {
420434
self.0.push(elem);
421435
}
436+
437+
pub(crate) fn list() -> Languages {
438+
Languages(vec![Language::new_plutus_v1(), Language::new_plutus_v2()])
439+
}
422440
}
423441

424442
#[wasm_bindgen]

rust/src/tx_builder.rs

Lines changed: 94 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1420,12 +1420,27 @@ impl TransactionBuilder {
14201420
/// in the builder to be used when building the tx body.
14211421
/// In case there are no plutus input witnesses present - nothing will change
14221422
/// You can set specific hash value using `.set_script_data_hash`
1423-
pub fn calc_script_data_hash(&mut self, cost_models: &Costmdls) {
1423+
/// NOTE: this function will check which language versions are used in the present scripts
1424+
/// and will assert and require for a corresponding cost-model to be present in the passed map.
1425+
/// Only the cost-models for the present language versions will be used in the hash calculation.
1426+
pub fn calc_script_data_hash(&mut self, cost_models: &Costmdls) -> Result<(), JsError> {
1427+
let mut retained_cost_models = Costmdls::new();
14241428
if let Some(pw) = self.inputs.get_plutus_input_scripts() {
1425-
let (_, datums, redeemers) = pw.collect();
1429+
let (scripts, datums, redeemers) = pw.collect();
1430+
for lang in Languages::list().0 {
1431+
if scripts.has_version(&lang) {
1432+
match cost_models.get(&lang) {
1433+
Some(cost) => { retained_cost_models.insert(&lang, &cost); },
1434+
_ => return Err(JsError::from_str(
1435+
&format!("Missing cost model for language version: {:?}", lang)
1436+
)),
1437+
}
1438+
}
1439+
}
14261440
self.script_data_hash =
1427-
Some(hash_script_data(&redeemers, cost_models, Some(datums)));
1441+
Some(hash_script_data(&redeemers, &retained_cost_models, Some(datums)));
14281442
}
1443+
Ok(())
14291444
}
14301445

14311446
/// Sets the specified hash value.
@@ -5033,7 +5048,7 @@ mod tests {
50335048
// Setting script data hash removes the error
50345049
tx_builder.calc_script_data_hash(
50355050
&TxBuilderConstants::plutus_default_cost_models(),
5036-
);
5051+
).unwrap();
50375052

50385053
// Using SAFE `.build_tx`
50395054
let res2 = tx_builder.build_tx();
@@ -5094,7 +5109,7 @@ mod tests {
50945109
// Calc the script data hash
50955110
tx_builder.calc_script_data_hash(
50965111
&TxBuilderConstants::plutus_default_cost_models(),
5097-
);
5112+
).unwrap();
50985113

50995114
let tx: Transaction = tx_builder.build_tx().unwrap();
51005115
assert!(tx.witness_set.redeemers.is_some());
@@ -5190,7 +5205,7 @@ mod tests {
51905205

51915206
tx_builder.calc_script_data_hash(
51925207
&TxBuilderConstants::plutus_default_cost_models(),
5193-
);
5208+
).unwrap();
51945209

51955210
let tx: Transaction = tx_builder.build_tx().unwrap();
51965211

@@ -5335,7 +5350,7 @@ mod tests {
53355350

53365351
tx_builder.calc_script_data_hash(
53375352
&TxBuilderConstants::plutus_default_cost_models(),
5338-
);
5353+
).unwrap();
53395354

53405355
let w: &TransactionWitnessSet = &tx_builder.build_tx().unwrap().witness_set;
53415356

@@ -5998,5 +6013,77 @@ mod tests {
59986013
assert!(tx_builder.total_collateral.is_none());
59996014
assert!(tx_builder.collateral_return.is_none());
60006015
}
6016+
6017+
#[test]
6018+
fn test_costmodel_retaining_for_v1() {
6019+
let mut tx_builder = create_reallistic_tx_builder();
6020+
tx_builder.set_fee(&to_bignum(42));
6021+
tx_builder.set_collateral(&create_collateral());
6022+
6023+
let (script1, _) = plutus_script_and_hash(0);
6024+
let datum = PlutusData::new_integer(&BigInt::from_str("42").unwrap());
6025+
let redeemer = Redeemer::new(
6026+
&RedeemerTag::new_spend(),
6027+
&to_bignum(0),
6028+
&datum,
6029+
&ExUnits::new(&to_bignum(1700), &to_bignum(368100)),
6030+
);
6031+
tx_builder.add_plutus_script_input(
6032+
&PlutusWitness::new(&script1, &datum, &redeemer),
6033+
&TransactionInput::new(&genesis_id(), 0),
6034+
&Value::new(&to_bignum(1_000_000)),
6035+
);
6036+
6037+
// Setting script data hash removes the error
6038+
tx_builder.calc_script_data_hash(
6039+
&TxBuilderConstants::plutus_vasil_cost_models(),
6040+
).unwrap();
6041+
6042+
// Using SAFE `.build_tx`
6043+
let res2 = tx_builder.build_tx();
6044+
assert!(res2.is_ok());
6045+
6046+
let v1 = Language::new_plutus_v1();
6047+
let v1_costmodel = TxBuilderConstants::plutus_vasil_cost_models().get(&v1).unwrap();
6048+
let mut retained_cost_models = Costmdls::new();
6049+
retained_cost_models.insert(&v1, &v1_costmodel);
6050+
6051+
let data_hash = hash_script_data(
6052+
&Redeemers::from(vec![redeemer.clone()]),
6053+
&retained_cost_models,
6054+
Some(PlutusList::from(vec![datum])),
6055+
);
6056+
assert_eq!(tx_builder.script_data_hash.unwrap(), data_hash);
6057+
}
6058+
6059+
#[test]
6060+
fn test_costmodel_retaining_fails_on_missing_costmodel() {
6061+
let mut tx_builder = create_reallistic_tx_builder();
6062+
tx_builder.set_fee(&to_bignum(42));
6063+
tx_builder.set_collateral(&create_collateral());
6064+
6065+
let (script1, _) = plutus_script_and_hash(0);
6066+
let datum = PlutusData::new_integer(&BigInt::from_str("42").unwrap());
6067+
let redeemer = Redeemer::new(
6068+
&RedeemerTag::new_spend(),
6069+
&to_bignum(0),
6070+
&datum,
6071+
&ExUnits::new(&to_bignum(1700), &to_bignum(368100)),
6072+
);
6073+
tx_builder.add_plutus_script_input(
6074+
&PlutusWitness::new(&script1, &datum, &redeemer),
6075+
&TransactionInput::new(&genesis_id(), 0),
6076+
&Value::new(&to_bignum(1_000_000)),
6077+
);
6078+
6079+
let v2 = Language::new_plutus_v2();
6080+
let v2_costmodel = TxBuilderConstants::plutus_vasil_cost_models().get(&v2).unwrap();
6081+
let mut retained_cost_models = Costmdls::new();
6082+
retained_cost_models.insert(&v2, &v2_costmodel);
6083+
6084+
// Setting script data hash removes the error
6085+
let calc_result = tx_builder.calc_script_data_hash(&retained_cost_models);
6086+
assert!(calc_result.is_err());
6087+
}
60016088
}
60026089

rust/src/tx_builder_constants.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ mod tests {
6262
);
6363
assert_eq!(
6464
hex::encode(TxBuilderConstants::plutus_vasil_cost_models().language_views_encoding()),
65-
"a241005901b69f1a0003236119032c01011903e819023b00011903e8195e7104011903e818201a0001ca761928eb041959d818641959d818641959d818641959d818641959d818641959d81864186418641959d81864194c5118201a0002acfa182019b551041a000363151901ff00011a00015c3518201a000797751936f404021a0002ff941a0006ea7818dc0001011903e8196ff604021a0003bd081a00034ec5183e011a00102e0f19312a011a00032e801901a5011a0002da781903e819cf06011a00013a34182019a8f118201903e818201a00013aac0119e143041903e80a1a00030219189c011a00030219189c011a0003207c1901d9011a000330001901ff0119ccf3182019fd40182019ffd5182019581e18201940b318201a00012adf18201a0002ff941a0006ea7818dc0001011a00010f92192da7000119eabb18201a0002ff941a0006ea7818dc0001011a0002ff941a0006ea7818dc0001011a000c504e197712041a001d6af61a0001425b041a00040c660004001a00014fab18201a0003236119032c010119a0de18201a00033d7618201979f41820197fb8182019a95d1820197df718201995aa18201a009063b91903fd0aff41015901d19f1a0003236119032c01011903e819023b00011903e8195e7104011903e818201a0001ca761928eb041959d818641959d818641959d818641959d818641959d818641959d81864186418641959d81864194c5118201a0002acfa182019b551041a000363151901ff00011a00015c3518201a000797751936f404021a0002ff941a0006ea7818dc0001011903e8196ff604021a0003bd081a00034ec5183e011a00102e0f19312a011a00032e801901a5011a0002da781903e819cf06011a00013a34182019a8f118201903e818201a00013aac0119e143041903e80a1a00030219189c011a00030219189c011a0003207c1901d9011a000330001901ff0119ccf3182019fd40182019ffd5182019581e18201940b318201a00012adf18201a0002ff941a0006ea7818dc0001011a00010f92192da7000119eabb18201a0002ff941a0006ea7818dc0001011a0002ff941a0006ea7818dc0001011a0011b22c1a0005fdde00021a000c504e197712041a001d6af61a0001425b041a00040c660004001a00014fab18201a0003236119032c010119a0de18201a00033d7618201979f41820197fb8182019a95d1820197df718201995aa18201a0223accc0a1a009063b91903fd0a1a02515e841980b30aff",
65+
"a20198af1a0003236119032c01011903e819023b00011903e8195e7104011903e818201a0001ca761928eb041959d818641959d818641959d818641959d818641959d818641959d81864186418641959d81864194c5118201a0002acfa182019b551041a000363151901ff00011a00015c3518201a000797751936f404021a0002ff941a0006ea7818dc0001011903e8196ff604021a0003bd081a00034ec5183e011a00102e0f19312a011a00032e801901a5011a0002da781903e819cf06011a00013a34182019a8f118201903e818201a00013aac0119e143041903e80a1a00030219189c011a00030219189c011a0003207c1901d9011a000330001901ff0119ccf3182019fd40182019ffd5182019581e18201940b318201a00012adf18201a0002ff941a0006ea7818dc0001011a00010f92192da7000119eabb18201a0002ff941a0006ea7818dc0001011a0002ff941a0006ea7818dc0001011a0011b22c1a0005fdde00021a000c504e197712041a001d6af61a0001425b041a00040c660004001a00014fab18201a0003236119032c010119a0de18201a00033d7618201979f41820197fb8182019a95d1820197df718201995aa18201a0223accc0a1a009063b91903fd0a1a02515e841980b30a41005901b69f1a0003236119032c01011903e819023b00011903e8195e7104011903e818201a0001ca761928eb041959d818641959d818641959d818641959d818641959d818641959d81864186418641959d81864194c5118201a0002acfa182019b551041a000363151901ff00011a00015c3518201a000797751936f404021a0002ff941a0006ea7818dc0001011903e8196ff604021a0003bd081a00034ec5183e011a00102e0f19312a011a00032e801901a5011a0002da781903e819cf06011a00013a34182019a8f118201903e818201a00013aac0119e143041903e80a1a00030219189c011a00030219189c011a0003207c1901d9011a000330001901ff0119ccf3182019fd40182019ffd5182019581e18201940b318201a00012adf18201a0002ff941a0006ea7818dc0001011a00010f92192da7000119eabb18201a0002ff941a0006ea7818dc0001011a0002ff941a0006ea7818dc0001011a000c504e197712041a001d6af61a0001425b041a00040c660004001a00014fab18201a0003236119032c010119a0de18201a00033d7618201979f41820197fb8182019a95d1820197df718201995aa18201a009063b91903fd0aff",
6666
);
6767
}
6868
}

rust/src/utils.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1367,6 +1367,7 @@ pub(crate) fn opt64<T>(o: &Option<T>) -> u64 {
13671367

13681368
#[cfg(test)]
13691369
mod tests {
1370+
use crate::tx_builder_constants::TxBuilderConstants;
13701371
use super::*;
13711372

13721373
// this is what is used in mainnet
@@ -2446,4 +2447,28 @@ mod tests {
24462447
to_bignum(0),
24472448
);
24482449
}
2450+
2451+
#[test]
2452+
fn test_vasil_v1_costmodel_hashing() {
2453+
let v1 = Language::new_plutus_v1();
2454+
let v1_cost_model = TxBuilderConstants::plutus_vasil_cost_models()
2455+
.get(&v1).unwrap();
2456+
let mut costmodels = Costmdls::new();
2457+
costmodels.insert(&v1, &v1_cost_model);
2458+
let hash = hash_script_data(
2459+
&Redeemers(vec![
2460+
Redeemer::new(
2461+
&RedeemerTag::new_spend(),
2462+
&BigNum::zero(),
2463+
&PlutusData::new_integer(&BigInt::from_str("42").unwrap()),
2464+
&ExUnits::new(&to_bignum(1700), &to_bignum(368100)),
2465+
)
2466+
]),
2467+
&costmodels,
2468+
Some(PlutusList::from(vec![
2469+
PlutusData::new_integer(&BigInt::from_str("42").unwrap())
2470+
])),
2471+
);
2472+
assert_eq!(hex::encode(hash.to_bytes()), "f4e4522ff98b6ba0ab5042d44da2458cd5fa6f97dc42aca1def58193f17a1375");
2473+
}
24492474
}

0 commit comments

Comments
 (0)