Skip to content

Commit efe3983

Browse files
authored
Update for new CDDL changes: (#193)
bounded bytes update: IntersectMBO/cardano-ledger@a8e0953 The change to constr_data was actually the implementation by us accidentally so we don't need to change for that part, only bounded_bytes. cost model representation update: IntersectMBO/cardano-ledger@ecb2cec
1 parent a23d1ad commit efe3983

File tree

2 files changed

+170
-52
lines changed

2 files changed

+170
-52
lines changed

rust/src/plutus.rs

Lines changed: 40 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -84,32 +84,38 @@ impl ConstrPlutusData {
8484
const GENERAL_FORM_TAG: u64 = 102;
8585
}
8686

87+
const COST_MODEL_OP_COUNT: usize = 166;
88+
8789
#[wasm_bindgen]
8890
#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
89-
pub struct CostModel(std::collections::BTreeMap<String, BigInt>);
91+
pub struct CostModel(Vec<Int>);
9092

9193
to_from_bytes!(CostModel);
9294

9395
#[wasm_bindgen]
9496
impl CostModel {
9597
pub fn new() -> Self {
96-
Self(std::collections::BTreeMap::new())
97-
}
98-
99-
pub fn len(&self) -> usize {
100-
self.0.len()
101-
}
102-
103-
pub fn insert(&mut self, key: String, value: &BigInt) -> Option<BigInt> {
104-
self.0.insert(key, value.clone())
98+
let mut costs = Vec::with_capacity(COST_MODEL_OP_COUNT);
99+
for _ in 0 .. COST_MODEL_OP_COUNT {
100+
costs.push(Int::new_i32(0));
101+
}
102+
Self(costs)
105103
}
106104

107-
pub fn get(&self, key: String) -> Option<BigInt> {
108-
self.0.get(&key).map(|v| v.clone())
105+
pub fn set(&mut self, operation: usize, cost: &Int) -> Result<Int, JsError> {
106+
if operation >= COST_MODEL_OP_COUNT {
107+
return Err(JsError::from_str(&format!("CostModel operation {} out of bounds. Max is {}", operation, COST_MODEL_OP_COUNT)));
108+
}
109+
let old = self.0[operation].clone();
110+
self.0[operation] = cost.clone();
111+
Ok(old)
109112
}
110113

111-
pub fn keys(&self) -> Strings {
112-
Strings(self.0.iter().map(|(k, _v)| k.clone()).collect::<Vec<_>>())
114+
pub fn get(&self, operation: usize) -> Result<Int, JsError> {
115+
if operation >= COST_MODEL_OP_COUNT {
116+
return Err(JsError::from_str(&format!("CostModel operation {} out of bounds. Max is {}", operation, COST_MODEL_OP_COUNT)));
117+
}
118+
Ok(self.0[operation].clone())
113119
}
114120
}
115121

@@ -295,8 +301,6 @@ enum PlutusDataEnum {
295301
#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
296302
pub struct PlutusData(PlutusDataEnum);
297303

298-
const PLUTUS_BYTES_MAX_LEN: usize = 64;
299-
300304
to_from_bytes!(PlutusData);
301305

302306
#[wasm_bindgen]
@@ -317,12 +321,8 @@ impl PlutusData {
317321
Self(PlutusDataEnum::Integer(integer.clone()))
318322
}
319323

320-
pub fn new_bytes(bytes: Vec<u8>) -> Result<PlutusData, JsError> {
321-
if bytes.len() > PLUTUS_BYTES_MAX_LEN {
322-
Err(JsError::from_str(&format!("Max Plutus bytes too long: {}, max = {}", bytes.len(), PLUTUS_BYTES_MAX_LEN)))
323-
} else {
324-
Ok(Self(PlutusDataEnum::Bytes(bytes)))
325-
}
324+
pub fn new_bytes(bytes: Vec<u8>) -> Self {
325+
Self(PlutusDataEnum::Bytes(bytes))
326326
}
327327

328328
pub fn kind(&self) -> PlutusDataKind {
@@ -628,34 +628,36 @@ impl Deserialize for ConstrPlutusData {
628628

629629
impl cbor_event::se::Serialize for CostModel {
630630
fn serialize<'se, W: Write>(&self, serializer: &'se mut Serializer<W>) -> cbor_event::Result<&'se mut Serializer<W>> {
631-
serializer.write_map(cbor_event::Len::Len(self.0.len() as u64))?;
632-
for (key, value) in &self.0 {
633-
serializer.write_text(&key)?;
634-
value.serialize(serializer)?;
631+
serializer.write_map(cbor_event::Len::Len(COST_MODEL_OP_COUNT as u64))?;
632+
for cost in &self.0 {
633+
cost.serialize(serializer)?;
635634
}
636635
Ok(serializer)
637636
}
638637
}
639638

640639
impl Deserialize for CostModel {
641640
fn deserialize<R: BufRead + Seek>(raw: &mut Deserializer<R>) -> Result<Self, DeserializeError> {
642-
let mut table = std::collections::BTreeMap::new();
641+
let mut arr = Vec::new();
643642
(|| -> Result<_, DeserializeError> {
644-
let len = raw.map()?;
645-
while match len { cbor_event::Len::Len(n) => table.len() < n as usize, cbor_event::Len::Indefinite => true, } {
643+
let len = raw.array()?;
644+
while match len { cbor_event::Len::Len(n) => arr.len() < n as usize, cbor_event::Len::Indefinite => true, } {
646645
if raw.cbor_type()? == CBORType::Special {
647646
assert_eq!(raw.special()?, CBORSpecial::Break);
648647
break;
649648
}
650-
let key = String::deserialize(raw)?;
651-
let value = BigInt::deserialize(raw)?;
652-
if table.insert(key.clone(), value).is_some() {
653-
return Err(DeserializeFailure::DuplicateKey(Key::Str(key)).into());
654-
}
649+
arr.push(Int::deserialize(raw)?);
650+
}
651+
if arr.len() != COST_MODEL_OP_COUNT {
652+
return Err(DeserializeFailure::OutOfRange{
653+
min: COST_MODEL_OP_COUNT,
654+
max: COST_MODEL_OP_COUNT,
655+
found: arr.len()
656+
}.into());
655657
}
656658
Ok(())
657659
})().map_err(|e| e.annotate("CostModel"))?;
658-
Ok(Self(table))
660+
Ok(Self(arr.try_into().unwrap()))
659661
}
660662
}
661663

@@ -862,7 +864,7 @@ impl cbor_event::se::Serialize for PlutusDataEnum {
862864
x.serialize(serializer)
863865
},
864866
PlutusDataEnum::Bytes(x) => {
865-
serializer.write_bytes(&x)
867+
write_bounded_bytes(serializer, &x)
866868
},
867869
}
868870
}
@@ -901,18 +903,10 @@ impl Deserialize for PlutusDataEnum {
901903
Err(_) => raw.as_mut_ref().seek(SeekFrom::Start(initial_position)).unwrap(),
902904
};
903905
match (|raw: &mut Deserializer<_>| -> Result<_, DeserializeError> {
904-
Ok(raw.bytes()?)
906+
Ok(read_bounded_bytes(raw)?)
905907
})(raw)
906908
{
907-
Ok(variant) => if variant.len() <= PLUTUS_BYTES_MAX_LEN {
908-
return Ok(PlutusDataEnum::Bytes(variant));
909-
} else {
910-
return Err(DeserializeFailure::OutOfRange{
911-
min: 0,
912-
max: PLUTUS_BYTES_MAX_LEN,
913-
found: variant.len(),
914-
}.into());
915-
}
909+
Ok(variant) => return Ok(PlutusDataEnum::Bytes(variant)),
916910
Err(_) => raw.as_mut_ref().seek(SeekFrom::Start(initial_position)).unwrap(),
917911
};
918912
Err(DeserializeError::new("PlutusDataEnum", DeserializeFailure::NoVariantMatched.into()))

rust/src/utils.rs

Lines changed: 130 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,87 @@ impl Deserialize for Int {
488488
}
489489
}
490490

491+
const BOUNDED_BYTES_CHUNK_SIZE: usize = 64;
492+
493+
pub (crate) fn write_bounded_bytes<'se, W: Write>(serializer: &'se mut Serializer<W>, bytes: &[u8]) -> cbor_event::Result<&'se mut Serializer<W>> {
494+
if bytes.len() <= BOUNDED_BYTES_CHUNK_SIZE {
495+
serializer.write_bytes(bytes)
496+
} else {
497+
// to get around not having access from outside the library we just write the raw CBOR indefinite byte string code here
498+
serializer.write_raw_bytes(&[0x5f])?;
499+
for chunk in bytes.chunks(BOUNDED_BYTES_CHUNK_SIZE) {
500+
serializer.write_bytes(chunk)?;
501+
}
502+
serializer.write_special(CBORSpecial::Break)
503+
}
504+
}
505+
506+
pub (crate) fn read_bounded_bytes<R: BufRead + Seek>(raw: &mut Deserializer<R>) -> Result<Vec<u8>, DeserializeError> {
507+
use std::io::Read;
508+
let t = raw.cbor_type()?;
509+
if t != CBORType::Bytes {
510+
return Err(cbor_event::Error::Expected(CBORType::Bytes, t).into());
511+
}
512+
let (len, len_sz) = raw.cbor_len()?;
513+
match len {
514+
cbor_event::Len::Len(_) => {
515+
let bytes = raw.bytes()?;
516+
if bytes.len() > BOUNDED_BYTES_CHUNK_SIZE {
517+
return Err(DeserializeFailure::OutOfRange{
518+
min: 0,
519+
max: BOUNDED_BYTES_CHUNK_SIZE,
520+
found: bytes.len(),
521+
}.into());
522+
}
523+
Ok(bytes)
524+
},
525+
cbor_event::Len::Indefinite => {
526+
// this is CBOR indefinite encoding, but we must check that each chunk
527+
// is at most 64 big so we can't just use cbor_event's implementation
528+
// and check after the fact.
529+
// This is a slightly adopted version of what I made internally in cbor_event
530+
// but with the extra checks and not having access to non-pub methods.
531+
let mut bytes = Vec::new();
532+
raw.advance(1 + len_sz)?;
533+
// TODO: also change this + check at end of loop to the following after we update cbor_event
534+
//while raw.cbor_type()? != CBORType::Special || !raw.special_break()? {
535+
while raw.cbor_type()? != CBORType::Special {
536+
let chunk_t = raw.cbor_type()?;
537+
if chunk_t != CBORType::Bytes {
538+
return Err(cbor_event::Error::Expected(CBORType::Bytes, chunk_t).into());
539+
}
540+
let (chunk_len, chunk_len_sz) = raw.cbor_len()?;
541+
match chunk_len {
542+
// TODO: use this error instead once that PR is merged into cbor_event
543+
//cbor_event::Len::Indefinite => return Err(cbor_event::Error::InvalidIndefiniteString.into()),
544+
cbor_event::Len::Indefinite => return Err(cbor_event::Error::CustomError(String::from("Illegal CBOR: Indefinite string found inside indefinite string")).into()),
545+
cbor_event::Len::Len(len) => {
546+
if chunk_len_sz > BOUNDED_BYTES_CHUNK_SIZE {
547+
return Err(DeserializeFailure::OutOfRange{
548+
min: 0,
549+
max: BOUNDED_BYTES_CHUNK_SIZE,
550+
found: chunk_len_sz,
551+
}.into());
552+
}
553+
raw.advance(1 + chunk_len_sz)?;
554+
raw
555+
.as_mut_ref()
556+
.by_ref()
557+
.take(len)
558+
.read_to_end(&mut bytes)
559+
.map_err(|e| cbor_event::Error::IoError(e))?;
560+
}
561+
}
562+
}
563+
if raw.special()? != CBORSpecial::Break {
564+
return Err(DeserializeFailure::EndingBreakMissing.into());
565+
}
566+
Ok(bytes)
567+
},
568+
}
569+
570+
}
571+
491572
#[wasm_bindgen]
492573
#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
493574
pub struct BigInt(num_bigint::BigInt);
@@ -538,15 +619,15 @@ impl cbor_event::se::Serialize for BigInt {
538619
num_bigint::Sign::Plus |
539620
num_bigint::Sign::NoSign => {
540621
serializer.write_tag(2u64)?;
541-
serializer.write_bytes(bytes)?;
622+
write_bounded_bytes(serializer, &bytes)?;
542623
},
543624
// negative bigint
544625
num_bigint::Sign::Minus => {
545626
serializer.write_tag(3u64)?;
546627
use std::ops::Neg;
547628
// CBOR RFC defines this as the bytes of -n -1
548629
let adjusted = self.0.clone().neg().checked_sub(&num_bigint::BigInt::from(1u32)).unwrap().to_biguint().unwrap();
549-
serializer.write_bytes(adjusted.to_bytes_be())?;
630+
write_bounded_bytes(serializer, &adjusted.to_bytes_be())?;
550631
},
551632
}
552633
}
@@ -561,10 +642,7 @@ impl Deserialize for BigInt {
561642
// bigint
562643
CBORType::Tag => {
563644
let tag = raw.tag()?;
564-
let bytes = raw.bytes()?;
565-
if bytes.len() > 64 {
566-
return Err(DeserializeFailure::OutOfRange{ found: bytes.len(), min: 0, max: 64}.into())
567-
}
645+
let bytes = read_bounded_bytes(raw)?;
568646
match tag {
569647
// positive bigint
570648
2 => Ok(Self(num_bigint::BigInt::from_bytes_be(num_bigint::Sign::Plus, &bytes))),
@@ -1673,4 +1751,50 @@ mod tests {
16731751
let x_rt = BigInt::from_bytes(x.to_bytes()).unwrap();
16741752
assert_eq!(x.to_str(), x_rt.to_str());
16751753
}
1754+
1755+
#[test]
1756+
fn bounded_bytes_read_chunked() {
1757+
use std::io::Cursor;
1758+
let chunks = vec![
1759+
vec![
1760+
0x52, 0x73, 0x6F, 0x6D, 0x65, 0x20, 0x72, 0x61, 0x6E, 0x64, 0x6F, 0x6D, 0x20, 0x73,
1761+
0x74, 0x72, 0x69, 0x6E, 0x67,
1762+
],
1763+
vec![0x44, 0x01, 0x02, 0x03, 0x04],
1764+
];
1765+
let mut expected = Vec::new();
1766+
for chunk in chunks.iter() {
1767+
expected.extend_from_slice(&chunk[1..]);
1768+
}
1769+
let mut vec = vec![0x5f];
1770+
for mut chunk in chunks {
1771+
vec.append(&mut chunk);
1772+
}
1773+
vec.push(0xff);
1774+
let mut raw = Deserializer::from(Cursor::new(vec.clone()));
1775+
let found = read_bounded_bytes(&mut raw).unwrap();
1776+
assert_eq!(found, expected);
1777+
}
1778+
1779+
#[test]
1780+
fn bounded_bytes_write_chunked() {
1781+
let mut chunk_64 = vec![0x58, BOUNDED_BYTES_CHUNK_SIZE as u8];
1782+
chunk_64.extend(std::iter::repeat(37).take(BOUNDED_BYTES_CHUNK_SIZE));
1783+
let chunks = vec![
1784+
chunk_64,
1785+
vec![0x44, 0x01, 0x02, 0x03, 0x04],
1786+
];
1787+
let mut input = Vec::new();
1788+
input.extend_from_slice(&chunks[0][2..]);
1789+
input.extend_from_slice(&chunks[1][1..]);
1790+
let mut serializer = cbor_event::se::Serializer::new_vec();
1791+
write_bounded_bytes(&mut serializer, &input).unwrap();
1792+
let written = serializer.finalize();
1793+
let mut expected = vec![0x5f];
1794+
for mut chunk in chunks {
1795+
expected.append(&mut chunk);
1796+
}
1797+
expected.push(0xff);
1798+
assert_eq!(expected, written);
1799+
}
16761800
}

0 commit comments

Comments
 (0)