From b83394be74284a8c326c9965714acc5a10be0401 Mon Sep 17 00:00:00 2001 From: rvcas Date: Fri, 5 Aug 2022 00:23:26 -0400 Subject: [PATCH] feat: decode proto list and proto pair Co-authored-by: Kasey White --- crates/flat/src/decode/decoder.rs | 8 +- crates/uplc/src/flat.rs | 219 ++++++++++++++++++++++++------ 2 files changed, 181 insertions(+), 46 deletions(-) diff --git a/crates/flat/src/decode/decoder.rs b/crates/flat/src/decode/decoder.rs index 972e2332..ad0efd60 100644 --- a/crates/flat/src/decode/decoder.rs +++ b/crates/flat/src/decode/decoder.rs @@ -137,10 +137,10 @@ impl<'b> Decoder<'b> { /// Otherwise we decode an item in the list with the decoder function passed in. /// Then decode the next bit in the buffer and repeat above. /// Returns a list of items decoded with the decoder function. - pub fn decode_list_with>( - &mut self, - decoder_func: for<'r> fn(&'r mut Decoder) -> Result, - ) -> Result, Error> { + pub fn decode_list_with, F>(&mut self, decoder_func: F) -> Result, Error> + where + F: Copy + FnOnce(&mut Decoder) -> Result, + { let mut vec_array: Vec = Vec::new(); while self.bit()? { vec_array.push(decoder_func(self)?) diff --git a/crates/uplc/src/flat.rs b/crates/uplc/src/flat.rs index f5dc8da5..427989fe 100644 --- a/crates/uplc/src/flat.rs +++ b/crates/uplc/src/flat.rs @@ -1,4 +1,4 @@ -use std::fmt::Debug; +use std::{collections::VecDeque, fmt::Debug}; use flat_rs::{ de::{self, Decode, Decoder}, @@ -296,13 +296,34 @@ fn encode_type(typ: &Type, bytes: &mut Vec) { impl<'b> Decode<'b> for Constant { fn decode(d: &mut Decoder) -> Result { - match decode_constant(d)? { - 0 => Ok(Constant::Integer(isize::decode(d)?)), - 1 => Ok(Constant::ByteString(Vec::::decode(d)?)), - 2 => Ok(Constant::String(String::decode(d)?)), - 3 => Ok(Constant::Unit), - 4 => Ok(Constant::Bool(bool::decode(d)?)), - 8 => { + match &decode_constant(d)?[..] { + [0] => Ok(Constant::Integer(isize::decode(d)?)), + [1] => Ok(Constant::ByteString(Vec::::decode(d)?)), + [2] => Ok(Constant::String(String::decode(d)?)), + [3] => Ok(Constant::Unit), + [4] => Ok(Constant::Bool(bool::decode(d)?)), + [7, 5, rest @ ..] => { + let mut rest = VecDeque::from(rest.to_vec()); + + let typ = decode_type(&mut rest)?; + + let list: Vec = + d.decode_list_with(|d| decode_constant_value(typ.clone(), d))?; + + Ok(Constant::ProtoList(typ, list)) + } + [7, 7, 6, rest @ ..] => { + let mut rest = VecDeque::from(rest.to_vec()); + + let type1 = decode_type(&mut rest)?; + let type2 = decode_type(&mut rest)?; + + let a = decode_constant_value(type1.clone(), d)?; + let b = decode_constant_value(type2.clone(), d)?; + + Ok(Constant::ProtoPair(type1, type2, Box::new(a), Box::new(b))) + } + [8] => { let cbor = Vec::::decode(d)?; let data = PlutusData::decode_fragment(&cbor) @@ -311,13 +332,86 @@ impl<'b> Decode<'b> for Constant { Ok(Constant::Data(data)) } x => Err(de::Error::Message(format!( - "Unknown constant constructor tag: {}", + "Unknown constant constructor tag: {:?}", x ))), } } } +fn decode_constant_value(typ: Type, d: &mut Decoder) -> Result { + match typ { + Type::Integer => Ok(Constant::Integer(isize::decode(d)?)), + Type::ByteString => Ok(Constant::ByteString(Vec::::decode(d)?)), + Type::String => Ok(Constant::String(String::decode(d)?)), + Type::Unit => Ok(Constant::Unit), + Type::Bool => Ok(Constant::Bool(bool::decode(d)?)), + Type::List(sub_type) => { + let list: Vec = + d.decode_list_with(|d| decode_constant_value(*sub_type.clone(), d))?; + + Ok(Constant::ProtoList(*sub_type, list)) + } + Type::Pair(type1, type2) => { + let a = decode_constant_value(*type1.clone(), d)?; + let b = decode_constant_value(*type2.clone(), d)?; + + Ok(Constant::ProtoPair( + *type1, + *type2, + Box::new(a), + Box::new(b), + )) + } + Type::Data => { + let cbor = Vec::::decode(d)?; + + let data = PlutusData::decode_fragment(&cbor) + .map_err(|err| de::Error::Message(err.to_string()))?; + + Ok(Constant::Data(data)) + } + } +} + +fn decode_type(types: &mut VecDeque) -> Result { + match types.pop_front() { + Some(4) => Ok(Type::Bool), + Some(0) => Ok(Type::Integer), + Some(2) => Ok(Type::String), + Some(1) => Ok(Type::ByteString), + Some(3) => Ok(Type::Unit), + Some(8) => Ok(Type::Data), + Some(7) => match types.pop_front() { + Some(5) => Ok(Type::List(Box::new(decode_type(types)?))), + Some(7) => match types.pop_front() { + Some(6) => { + let type1 = decode_type(types)?; + let type2 = decode_type(types)?; + + Ok(Type::Pair(Box::new(type1), Box::new(type2))) + } + Some(x) => Err(de::Error::Message(format!( + "Unknown constant type tag: {}", + x + ))), + None => Err(de::Error::Message("Unexpected empty buffer".to_string())), + }, + Some(x) => Err(de::Error::Message(format!( + "Unknown constant type tag: {}", + x + ))), + None => Err(de::Error::Message("Unexpected empty buffer".to_string())), + }, + + Some(x) => Err(de::Error::Message(format!( + "Unknown constant type tag: {}", + x + ))), + None => Err(de::Error::Message("Unexpected empty buffer".to_string())), + } +} + impl Encode for Unique { fn encode(&self, e: &mut Encoder) -> Result<(), en::Error> { isize::from(*self).encode(e)?; @@ -506,16 +600,8 @@ pub fn encode_constant(tag: &[u8], e: &mut Encoder) -> Result<(), en::Error> { Ok(()) } -pub fn decode_constant(d: &mut Decoder) -> Result { - let u8_list = d.decode_list_with(decode_constant_tag)?; - if u8_list.len() > 1 { - Err(de::Error::Message( - "Improper encoding on constant tag. Should be list of one item encoded in 4 bits" - .to_string(), - )) - } else { - Ok(u8_list[0]) - } +pub fn decode_constant(d: &mut Decoder) -> Result, de::Error> { + d.decode_list_with(decode_constant_tag) } pub fn encode_constant_tag(tag: &u8, e: &mut Encoder) -> Result<(), en::Error> { @@ -541,12 +627,13 @@ mod test { term: Term::Constant(Constant::Integer(11)), }; - let bytes = program.to_flat().unwrap(); + let expected_bytes = vec![ + 0b00001011, 0b00010110, 0b00100001, 0b01001000, 0b00000101, 0b10000001, + ]; - assert_eq!( - bytes, - vec![0b00001011, 0b00010110, 0b00100001, 0b01001000, 0b00000101, 0b10000001] - ) + let actual_bytes = program.to_flat().unwrap(); + + assert_eq!(actual_bytes, expected_bytes) } #[test] @@ -562,15 +649,14 @@ mod test { )), }; - let bytes = program.to_flat().unwrap(); + let expected_bytes = vec![ + 0b00000001, 0b00000000, 0b00000000, 0b01001011, 0b11010110, 0b11110101, 0b10000011, + 0b00001110, 0b01100001, 0b01000001, + ]; - assert_eq!( - bytes, - vec![ - 0b00000001, 0b00000000, 0b00000000, 0b01001011, 0b11010110, 0b11110101, 0b10000011, - 0b00001110, 0b01100001, 0b01000001 - ] - ) + let actual_bytes = program.to_flat().unwrap(); + + assert_eq!(actual_bytes, expected_bytes) } #[test] @@ -590,20 +676,69 @@ mod test { )), }; - let bytes = program.to_flat().unwrap(); + let expected_bytes = vec![ + 0b00000001, 0b00000000, 0b00000000, 0b01001011, 0b11011110, 0b11010111, 0b10111101, + 0b10100001, 0b01001000, 0b00000101, 0b10100010, 0b11000001, + ]; - assert_eq!( - bytes, - vec![ - 0b00000001, 0b00000000, 0b00000000, 0b01001011, 0b11011110, 0b11010111, 0b10111101, - 0b10100001, 0b01001000, 0b00000101, 0b10100010, 0b11000001 - ] - ) + let actual_bytes = program.to_flat().unwrap(); + + assert_eq!(actual_bytes, expected_bytes) + } + + #[test] + fn flat_decode_list_list_integer() { + let bytes = vec![ + 0b00000001, 0b00000000, 0b00000000, 0b01001011, 0b11010110, 0b11110101, 0b10000011, + 0b00001110, 0b01100001, 0b01000001, + ]; + + let expected_program = Program:: { + version: (1, 0, 0), + term: Term::Constant(Constant::ProtoList( + Type::List(Box::new(Type::Integer)), + vec![ + Constant::ProtoList(Type::Integer, vec![Constant::Integer(7)]), + Constant::ProtoList(Type::Integer, vec![Constant::Integer(5)]), + ], + )), + }; + + let actual_program: Program = Program::unflat(&bytes).unwrap(); + + assert_eq!(actual_program, expected_program) + } + + #[test] + fn flat_decode_pair_pair_integer_bool_integer() { + let bytes = vec![ + 0b00000001, 0b00000000, 0b00000000, 0b01001011, 0b11011110, 0b11010111, 0b10111101, + 0b10100001, 0b01001000, 0b00000101, 0b10100010, 0b11000001, + ]; + + let expected_program = Program:: { + version: (1, 0, 0), + term: Term::Constant(Constant::ProtoPair( + Type::Pair(Box::new(Type::Integer), Box::new(Type::Bool)), + Type::Integer, + Box::new(Constant::ProtoPair( + Type::Integer, + Type::Bool, + Box::new(Constant::Integer(11)), + Box::new(Constant::Bool(true)), + )), + Box::new(Constant::Integer(11)), + )), + }; + + let actual_program: Program = Program::unflat(&bytes).unwrap(); + + assert_eq!(actual_program, expected_program) } #[test] fn flat_decode_integer() { - let flat_encoded = vec![ + let bytes = vec![ 0b00001011, 0b00010110, 0b00100001, 0b01001000, 0b00000101, 0b10000001, ]; @@ -612,7 +747,7 @@ mod test { term: Term::Constant(Constant::Integer(11)), }; - let actual_program: Program = Program::unflat(&flat_encoded).unwrap(); + let actual_program: Program = Program::unflat(&bytes).unwrap(); assert_eq!(actual_program, expected_program) }