Skip to content

Commit 2354cbd

Browse files
committed
Merge remote-tracking branch 'origin/master' into release/9.1.2
2 parents 28f0988 + 7728a29 commit 2354cbd

File tree

1 file changed

+70
-20
lines changed

1 file changed

+70
-20
lines changed

rust/src/plutus.rs

Lines changed: 70 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -52,36 +52,60 @@ impl PlutusScripts {
5252
#[wasm_bindgen]
5353
#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
5454
pub struct ConstrPlutusData {
55-
tag: Int,
55+
alternative: BigNum,
5656
data: PlutusList,
5757
}
5858

5959
to_from_bytes!(ConstrPlutusData);
6060

6161
#[wasm_bindgen]
6262
impl ConstrPlutusData {
63-
pub fn tag(&self) -> Int {
64-
self.tag.clone()
63+
pub fn alternative(&self) -> BigNum {
64+
self.alternative.clone()
6565
}
6666

6767
pub fn data(&self) -> PlutusList {
6868
self.data.clone()
6969
}
7070

71-
pub fn new(tag: Int, data: &PlutusList) -> Self {
71+
pub fn new(alternative: &BigNum, data: &PlutusList) -> Self {
7272
Self {
73-
tag,
73+
alternative: alternative.clone(),
7474
data: data.clone(),
7575
}
7676
}
7777
}
7878

7979
impl ConstrPlutusData {
80-
fn is_tag_compact(tag: i128) -> bool {
81-
(tag >= 121 && tag <= 127) || (tag >= 1280 && tag <= 1400)
80+
// see: https://github.com/input-output-hk/plutus/blob/1f31e640e8a258185db01fa899da63f9018c0e85/plutus-core/plutus-core/src/PlutusCore/Data.hs#L61
81+
// We don't directly serialize the alternative in the tag, instead the scheme is:
82+
// - Alternatives 0-6 -> tags 121-127, followed by the arguments in a list
83+
// - Alternatives 7-127 -> tags 1280-1400, followed by the arguments in a list
84+
// - Any alternatives, including those that don't fit in the above -> tag 102 followed by a list containing
85+
// an unsigned integer for the actual alternative, and then the arguments in a (nested!) list.
86+
const GENERAL_FORM_TAG: u64 = 102;
87+
88+
// None -> needs general tag serialization, not compact
89+
fn alternative_to_compact_cbor_tag(alt: u64) -> Option<u64> {
90+
if alt <= 6 {
91+
Some(121 + alt)
92+
} else if alt >= 7 && alt <= 127 {
93+
Some(1280 - 7 + alt)
94+
} else {
95+
None
96+
}
8297
}
8398

84-
const GENERAL_FORM_TAG: u64 = 102;
99+
// None -> General tag(=102) OR Invalid CBOR tag for this scheme
100+
fn compact_cbor_tag_to_alternative(cbor_tag: u64) -> Option<u64> {
101+
if cbor_tag >= 121 && cbor_tag <= 127 {
102+
Some(cbor_tag - 121)
103+
} else if cbor_tag >= 1280 && cbor_tag <= 1400 {
104+
Some(cbor_tag - 1280 + 7)
105+
} else {
106+
None
107+
}
108+
}
85109
}
86110

87111
const COST_MODEL_OP_COUNT: usize = 166;
@@ -606,15 +630,15 @@ impl Deserialize for PlutusScripts {
606630
// TODO: write tests for this hand-coded implementation?
607631
impl cbor_event::se::Serialize for ConstrPlutusData {
608632
fn serialize<'se, W: Write>(&self, serializer: &'se mut Serializer<W>) -> cbor_event::Result<&'se mut Serializer<W>> {
609-
if Self::is_tag_compact(self.tag.0) {
633+
if let Some(compact_tag) = Self::alternative_to_compact_cbor_tag(from_bignum(&self.alternative)) {
610634
// compact form
611-
serializer.write_tag(self.tag.0 as u64)?;
635+
serializer.write_tag(compact_tag as u64)?;
612636
self.data.serialize(serializer)
613637
} else {
614638
// general form
615639
serializer.write_tag(Self::GENERAL_FORM_TAG)?;
616640
serializer.write_array(cbor_event::Len::Len(2))?;
617-
self.tag.serialize(serializer)?;
641+
self.alternative.serialize(serializer)?;
618642
self.data.serialize(serializer)
619643
}
620644
}
@@ -623,13 +647,13 @@ impl cbor_event::se::Serialize for ConstrPlutusData {
623647
impl Deserialize for ConstrPlutusData {
624648
fn deserialize<R: BufRead + Seek>(raw: &mut Deserializer<R>) -> Result<Self, DeserializeError> {
625649
(|| -> Result<_, DeserializeError> {
626-
let (tag, data) = match raw.tag()? {
650+
let (alternative, data) = match raw.tag()? {
627651
// general form
628652
Self::GENERAL_FORM_TAG => {
629653
let len = raw.array()?;
630654
let mut read_len = CBORReadLen::new(len);
631655
read_len.read_elems(2)?;
632-
let tag = Int::deserialize(raw)?;
656+
let alternative = BigNum::deserialize(raw)?;
633657
let data = (|| -> Result<_, DeserializeError> {
634658
Ok(PlutusList::deserialize(raw)?)
635659
})().map_err(|e| e.annotate("datas"))?;
@@ -640,17 +664,22 @@ impl Deserialize for ConstrPlutusData {
640664
_ => return Err(DeserializeFailure::EndingBreakMissing.into()),
641665
},
642666
}
643-
(tag, data)
667+
(alternative, data)
644668
},
645669
// concise form
646-
tag if Self::is_tag_compact(tag.into()) => (Int::new(&to_bignum(tag)), PlutusList::deserialize(raw)?),
647-
invalid_tag => return Err(DeserializeFailure::TagMismatch{
648-
found: invalid_tag,
649-
expected: Self::GENERAL_FORM_TAG,
650-
}.into()),
670+
tag => {
671+
if let Some(alternative) = Self::compact_cbor_tag_to_alternative(tag) {
672+
(to_bignum(alternative), PlutusList::deserialize(raw)?)
673+
} else {
674+
return Err(DeserializeFailure::TagMismatch{
675+
found: tag,
676+
expected: Self::GENERAL_FORM_TAG,
677+
}.into());
678+
}
679+
},
651680
};
652681
Ok(ConstrPlutusData{
653-
tag,
682+
alternative,
654683
data,
655684
})
656685
})().map_err(|e| e.annotate("ConstrPlutusData"))
@@ -1131,3 +1160,24 @@ impl Deserialize for Strings {
11311160
Ok(Self(arr))
11321161
}
11331162
}
1163+
1164+
#[cfg(test)]
1165+
mod tests {
1166+
use super::*;
1167+
1168+
#[test]
1169+
pub fn plutus_constr_data() {
1170+
let constr_0 = PlutusData::new_constr_plutus_data(
1171+
&ConstrPlutusData::new(&to_bignum(0), &PlutusList::new())
1172+
);
1173+
let constr_0_hash = hex::encode(hash_plutus_data(&constr_0).to_bytes());
1174+
assert_eq!(constr_0_hash, "923918e403bf43c34b4ef6b48eb2ee04babed17320d8d1b9ff9ad086e86f44ec");
1175+
let constr_0_roundtrip = PlutusData::from_bytes(constr_0.to_bytes()).unwrap();
1176+
assert_eq!(constr_0, constr_0_roundtrip);
1177+
let constr_1854 = PlutusData::new_constr_plutus_data(
1178+
&ConstrPlutusData::new(&to_bignum(1854), &PlutusList::new())
1179+
);
1180+
let constr_1854_roundtrip = PlutusData::from_bytes(constr_1854.to_bytes()).unwrap();
1181+
assert_eq!(constr_1854, constr_1854_roundtrip);
1182+
}
1183+
}

0 commit comments

Comments
 (0)