mavryk_smart_rollup_encoding/
inbox.rs1use crate::michelson::Michelson;
15use crate::public_key_hash::PublicKeyHash;
16use crate::smart_rollup::SmartRollupAddress;
17use crate::timestamp::Timestamp;
18use crypto::hash::{BlockHash, ContractKt1Hash};
19use mavryk_data_encoding::enc;
20use mavryk_data_encoding::enc::BinWriter;
21use mavryk_data_encoding::encoding::HasEncoding;
22use mavryk_data_encoding::nom::NomReader;
23use nom::bytes::complete::tag;
24use nom::combinator::{map, rest};
25use nom::sequence::pair;
26use nom::sequence::preceded;
27use nom::Finish;
28use std::fmt::Display;
29
30#[derive(Debug, PartialEq, Eq, NomReader, HasEncoding, BinWriter)]
31enum InboxMessageRepr<Expr: Michelson> {
32 #[encoding(tag = 0)]
33 Internal(InternalInboxMessage<Expr>),
34 #[encoding(tag = 1)]
35 External,
36}
37
38#[derive(Debug, PartialEq, Eq)]
40pub enum InboxMessage<'a, Expr: Michelson> {
41 Internal(InternalInboxMessage<Expr>),
43 External(&'a [u8]),
49}
50
51impl<'a, Expr: Michelson> InboxMessage<'a, Expr> {
52 pub fn parse(input: &'a [u8]) -> mavryk_data_encoding::nom::NomResult<Self> {
60 let (remaining, repr): (&'a [u8], _) = InboxMessageRepr::nom_read(input)?;
61
62 match repr {
63 InboxMessageRepr::Internal(i) => Ok((remaining, InboxMessage::Internal(i))),
64 InboxMessageRepr::External => map(rest, InboxMessage::External)(remaining),
65 }
66 }
67
68 pub fn serialize(self, output: &mut Vec<u8>) -> mavryk_data_encoding::enc::BinResult {
72 match self {
73 InboxMessage::Internal(m) => {
74 InboxMessageRepr::Internal(m).bin_write(output)?;
75 }
76 InboxMessage::External(m) => {
77 InboxMessageRepr::<Expr>::External.bin_write(output)?;
78 output.extend_from_slice(m);
79 }
80 }
81 Ok(())
82 }
83}
84
85#[derive(Debug, PartialEq, Eq, NomReader, HasEncoding, BinWriter)]
86pub struct Transfer<Expr: Michelson> {
88 pub payload: Expr,
90 pub sender: ContractKt1Hash,
92 pub source: PublicKeyHash,
94 pub destination: SmartRollupAddress,
96}
97
98impl<E: Michelson> Display for Transfer<E> {
99 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
100 write!(
101 f,
102 "Transfer {{sender: {}, source: {}, dest: {}}}",
103 self.sender, self.source, self.destination
104 )
105 }
106}
107
108#[derive(Debug, PartialEq, Eq, NomReader, HasEncoding, BinWriter, Clone)]
110pub struct InfoPerLevel {
111 pub predecessor_timestamp: Timestamp,
113 pub predecessor: BlockHash,
115}
116
117impl Display for InfoPerLevel {
118 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
119 write!(
120 f,
121 "InfoPerLevel {{predecessor_timestamp: {}, predecessor: {}}}",
122 self.predecessor_timestamp, self.predecessor
123 )
124 }
125}
126
127#[derive(Debug, PartialEq, Eq, NomReader, HasEncoding, BinWriter)]
129pub enum InternalInboxMessage<Expr: Michelson> {
130 Transfer(Transfer<Expr>),
132 StartOfLevel,
134 EndOfLevel,
136 InfoPerLevel(InfoPerLevel),
138}
139
140impl<Expr: Michelson> Display for InternalInboxMessage<Expr> {
141 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
142 match self {
143 Self::Transfer(tr) => write!(f, "{}", tr),
144 Self::StartOfLevel => write!(f, "StartOfLevel"),
145 Self::EndOfLevel => write!(f, "EndOfLevel"),
146 Self::InfoPerLevel(ipl) => write!(f, "{}", ipl),
147 }
148 }
149}
150
151#[derive(Debug, Eq)]
162pub enum ExternalMessageFrame<T: AsRef<[u8]>> {
163 Targetted {
165 address: SmartRollupAddress,
167 contents: T,
169 },
170}
171
172impl<T: AsRef<[u8]>> ExternalMessageFrame<T> {
173 const TARGETTED_TAG: u8 = 0;
174}
175
176impl<'a> ExternalMessageFrame<&'a [u8]> {
177 pub fn parse(input: &'a [u8]) -> Result<Self, mavryk_data_encoding::nom::NomError> {
185 let (_remaining, message) = map(
186 preceded(
187 tag([Self::TARGETTED_TAG]),
188 pair(SmartRollupAddress::nom_read, rest),
189 ),
190 |(address, contents)| Self::Targetted { address, contents },
191 )(input)
192 .finish()?;
193
194 Ok(message)
195 }
196}
197
198impl<T: AsRef<[u8]>, U: AsRef<[u8]>> core::cmp::PartialEq<ExternalMessageFrame<U>>
199 for ExternalMessageFrame<T>
200{
201 fn eq(&self, other: &ExternalMessageFrame<U>) -> bool {
202 match (self, other) {
203 (
204 Self::Targetted {
205 address: a1,
206 contents: c1,
207 },
208 ExternalMessageFrame::Targetted {
209 address: a2,
210 contents: c2,
211 },
212 ) => a1 == a2 && c1.as_ref() == c2.as_ref(),
213 }
214 }
215}
216
217impl<T: AsRef<[u8]>> BinWriter for ExternalMessageFrame<T> {
218 fn bin_write(&self, output: &mut Vec<u8>) -> enc::BinResult {
219 match self {
220 Self::Targetted { address, contents } => {
221 enc::put_byte(&Self::TARGETTED_TAG, output);
222 address.bin_write(output)?;
223 enc::put_bytes(contents.as_ref(), output);
224 }
225 }
226
227 Ok(())
228 }
229}
230
231#[cfg(test)]
232mod test {
233 use super::ExternalMessageFrame;
234 use super::InboxMessage;
235 use super::InternalInboxMessage;
236 use crate::michelson::Michelson;
237 use crate::michelson::MichelsonUnit;
238 use crate::smart_rollup::SmartRollupAddress;
239 use mavryk_data_encoding::enc::BinWriter;
240
241 #[test]
242 fn test_encode_decode_sol() {
243 let expected_bytes = vec![
245 0, 1, ];
249
250 let inbox_message = InboxMessage::Internal(InternalInboxMessage::StartOfLevel);
251
252 test_encode_decode::<MichelsonUnit>(expected_bytes, inbox_message)
253 }
254
255 #[test]
256 fn test_encode_decode_eol() {
257 let expected_bytes = vec![
259 0, 2, ];
263
264 let inbox_message = InboxMessage::Internal(InternalInboxMessage::EndOfLevel);
265
266 test_encode_decode::<MichelsonUnit>(expected_bytes, inbox_message)
267 }
268
269 #[test]
270 fn test_encode_decode_external_inbox_message() {
271 let assert_enc = |message: Vec<u8>| {
272 let inbox_message =
273 InboxMessage::<MichelsonUnit>::External(message.as_slice());
274
275 assert_encode_decode_inbox_message(inbox_message);
276 };
277
278 assert_enc(vec![]);
279 assert_enc(vec![b'A']);
280 assert_enc("0123456789".as_bytes().to_vec());
281 assert_enc(vec![b'B'; 256]);
282 assert_enc(vec![b'\n'; 1234567]);
283 assert_enc(vec![5; 1234567]);
284 }
285
286 fn assert_encode_decode_inbox_message<Expr: Michelson>(message: InboxMessage<Expr>) {
287 let mut encoded = Vec::new();
288 message
289 .serialize(&mut encoded)
290 .expect("encoding should work");
291
292 let decoded = InboxMessage::<Expr>::parse(encoded.as_slice())
293 .expect("Deserialization failed")
294 .1;
295
296 let mut encoded_twice = Vec::new();
297 decoded
298 .serialize(&mut encoded_twice)
299 .expect("encoding should work");
300
301 assert_eq!(encoded, encoded_twice);
302 }
303
304 fn test_encode_decode<Expr: Michelson>(
305 expected_bytes: Vec<u8>,
306 inbox_message: InboxMessage<Expr>,
307 ) {
308 let mut bin = Vec::new();
310 inbox_message
311 .serialize(&mut bin)
312 .expect("encoding should work");
313
314 assert_eq!(expected_bytes, bin, "error in serialization");
315
316 let (input_remaining, _parsed_message) =
318 InboxMessage::<Expr>::parse(bin.as_slice())
319 .expect("deserialization should work");
320
321 assert!(input_remaining.is_empty());
322 }
323
324 #[test]
325 fn test_encode_decode_external_framing_targetted() {
326 let contents = "Hello, world! (But only in one rollup)";
327 let address =
328 SmartRollupAddress::from_b58check("sr163Lv22CdE8QagCwf48PWDTquk6isQwv57")
329 .unwrap();
330
331 let framed = ExternalMessageFrame::Targetted { address, contents };
332
333 let mut output = Vec::new();
334 framed.bin_write(&mut output).unwrap();
335
336 let parsed = ExternalMessageFrame::parse(&output).unwrap();
337
338 assert_eq!(framed, parsed);
339 }
340}