1mod decoder;
2mod error;
3
4pub use decoder::Ctx;
5pub use decoder::Decoder;
6pub use error::FlatDecodeError;
7
8use bumpalo::collections::Vec as BumpVec;
9
10use crate::arena::Arena;
11use crate::binder::Binder;
12use crate::machine::PlutusVersion;
13use crate::typ::Type;
14use crate::{
15 constant::Constant,
16 program::{Program, Version},
17 term::Term,
18};
19
20use super::tag;
21use super::{
22 builtin,
23 tag::{BUILTIN_TAG_WIDTH, CONST_TAG_WIDTH, TERM_TAG_WIDTH},
24};
25
26pub fn decode<'a, V>(
29 arena: &'a Arena,
30 bytes: &[u8],
31 plutus_version: PlutusVersion,
32 protocol_version_major: u32,
33) -> Result<&'a Program<'a, V>, FlatDecodeError>
34where
35 V: Binder<'a>,
36{
37 let (program, _remainder) = decode_inner(arena, bytes, plutus_version, protocol_version_major)?;
38 Ok(program)
39}
40
41pub fn decode_strict<'a, V>(
44 arena: &'a Arena,
45 bytes: &[u8],
46 plutus_version: PlutusVersion,
47 protocol_version: u32,
48) -> Result<&'a Program<'a, V>, FlatDecodeError>
49where
50 V: Binder<'a>,
51{
52 let (program, remainder) = decode_inner(arena, bytes, plutus_version, protocol_version)?;
53 if remainder > 0 {
54 return Err(FlatDecodeError::TrailingBytes(remainder));
55 }
56 Ok(program)
57}
58
59fn decode_inner<'a, V>(
60 arena: &'a Arena,
61 bytes: &[u8],
62 plutus_version: PlutusVersion,
63 protocol_version_major: u32,
64) -> Result<(&'a Program<'a, V>, usize), FlatDecodeError>
65where
66 V: Binder<'a>,
67{
68 let mut decoder = Decoder::new(bytes);
69
70 let major = decoder.word()?;
71 let minor = decoder.word()?;
72 let patch = decoder.word()?;
73
74 let version = Version::new(arena, major, minor, patch);
75
76 let mut ctx = Ctx { arena };
77
78 let term = decode_term(
79 &mut ctx,
80 &mut decoder,
81 (plutus_version, protocol_version_major),
82 )?;
83
84 decoder.filler()?;
85
86 let remainder = decoder.buffer.len() - decoder.pos;
87
88 Ok((Program::new(arena, version, term), remainder))
89}
90
91fn decode_term<'a, V>(
92 ctx: &mut Ctx<'a>,
93 decoder: &mut Decoder<'_>,
94 version_check: (PlutusVersion, u32),
95) -> Result<&'a Term<'a, V>, FlatDecodeError>
96where
97 V: Binder<'a>,
98{
99 let tag = decoder.bits8(TERM_TAG_WIDTH)?;
100
101 match tag {
102 tag::VAR => Ok(Term::var(ctx.arena, V::var_decode(ctx.arena, decoder)?)),
104 tag::DELAY => {
106 let term = decode_term(ctx, decoder, version_check)?;
107
108 Ok(term.delay(ctx.arena))
109 }
110 tag::LAMBDA => {
112 let param = V::parameter_decode(ctx.arena, decoder)?;
113
114 let term = decode_term(ctx, decoder, version_check)?;
115
116 Ok(term.lambda(ctx.arena, param))
117 }
118 tag::APPLY => {
120 let function = decode_term(ctx, decoder, version_check)?;
121 let argument = decode_term(ctx, decoder, version_check)?;
122
123 let term = function.apply(ctx.arena, argument);
124
125 Ok(term)
126 }
127 tag::CONSTANT => {
129 let constant = decode_constant(ctx, decoder)?;
130
131 Ok(Term::constant(ctx.arena, constant))
132 }
133 tag::FORCE => {
135 let term = decode_term(ctx, decoder, version_check)?;
136
137 Ok(term.force(ctx.arena))
138 }
139 tag::ERROR => Ok(Term::error(ctx.arena)),
141 tag::BUILTIN => {
143 let builtin_tag = decoder.bits8(BUILTIN_TAG_WIDTH)?;
144
145 let function = builtin::try_from_tag(ctx.arena, builtin_tag)?;
146
147 let (plutus_version, protocol_version_major) = version_check;
148 if !function.is_available_in(plutus_version, protocol_version_major) {
149 return Err(FlatDecodeError::BuiltinNotAvailable(
150 builtin_tag,
151 format!("{:?}", function),
152 ));
153 }
154
155 let term = Term::builtin(ctx.arena, function);
156
157 Ok(term)
158 }
159 tag::CONSTR => {
161 let tag = decoder.word()?;
162 let fields = decoder.list_with(ctx, |ctx, d| decode_term(ctx, d, version_check))?;
163 let fields = ctx.arena.alloc(fields);
164
165 let term = Term::constr(ctx.arena, tag, fields);
166
167 Ok(term)
168 }
169 tag::CASE => {
171 let constr = decode_term(ctx, decoder, version_check)?;
172 let branches = decoder.list_with(ctx, |ctx, d| decode_term(ctx, d, version_check))?;
173 let branches = ctx.arena.alloc(branches);
174
175 Ok(Term::case(ctx.arena, constr, branches))
176 }
177 _ => Err(FlatDecodeError::UnknownTermConstructor(tag)),
178 }
179}
180
181fn type_from_tags<'a>(
182 ctx: &Ctx<'a>,
183 tags: &[u8],
184) -> Result<(&'a Type<'a>, usize), FlatDecodeError> {
185 match tags {
186 [tag::INTEGER, ..] => Ok((Type::integer(ctx.arena), 1)),
187 [tag::BYTE_STRING, ..] => Ok((Type::byte_string(ctx.arena), 1)),
188 [tag::STRING, ..] => Ok((Type::string(ctx.arena), 1)),
189 [tag::UNIT, ..] => Ok((Type::unit(ctx.arena), 1)),
190 [tag::BOOL, ..] => Ok((Type::bool(ctx.arena), 1)),
191 [tag::DATA, ..] => Ok((Type::data(ctx.arena), 1)),
192 [tag::PROTO_LIST_ONE, tag::PROTO_LIST_TWO, rest @ ..] => {
193 let (sub_typ, consumed) = type_from_tags(ctx, rest)?;
194 Ok((Type::list(ctx.arena, sub_typ), 2 + consumed))
195 }
196 [tag::PROTO_ARRAY_ONE, tag::PROTO_ARRAY_TWO, rest @ ..] => {
197 let (sub_typ, consumed) = type_from_tags(ctx, rest)?;
198 Ok((Type::array(ctx.arena, sub_typ), 2 + consumed))
199 }
200 [tag::PROTO_PAIR_ONE, tag::PROTO_PAIR_TWO, tag::PROTO_PAIR_THREE, rest @ ..] => {
201 let (sub_typ1, consumed1) = type_from_tags(ctx, rest)?;
202 let rest2 = &rest[consumed1..];
203 let (sub_typ2, consumed2) = type_from_tags(ctx, rest2)?;
204
205 Ok((
206 Type::pair(ctx.arena, sub_typ1, sub_typ2),
207 3 + consumed1 + consumed2,
208 ))
209 }
210 [] => Err(FlatDecodeError::MissingTypeTag),
211 x => Err(FlatDecodeError::UnknownTypeTags(x.to_vec())),
212 }
213}
214
215fn decode_constant<'a>(
217 ctx: &mut Ctx<'a>,
218 d: &mut Decoder,
219) -> Result<&'a Constant<'a>, FlatDecodeError> {
220 let tags = decode_constant_tags(ctx, d)?;
221 let (ty, _) = type_from_tags(ctx, tags.as_slice())?;
222
223 match ty {
224 Type::Integer => {
225 let v = d.integer()?;
226 let v = ctx.arena.alloc_integer(v);
227
228 Ok(Constant::integer(ctx.arena, v))
229 }
230 Type::ByteString => {
231 let b = d.bytes(ctx.arena)?;
232 let b = ctx.arena.alloc(b);
233
234 Ok(Constant::byte_string(ctx.arena, b))
235 }
236 Type::Bool => {
237 let v = d.bit()?;
238
239 Ok(Constant::bool(ctx.arena, v))
240 }
241 Type::String => {
242 let s = d.utf8(ctx.arena)?;
243 let s = ctx.arena.alloc(s);
244
245 Ok(Constant::string(ctx.arena, s))
246 }
247 Type::Unit => Ok(Constant::unit(ctx.arena)),
248 Type::List(sub_typ) => {
249 let fields = d.list_with(ctx, |ctx, d| decode_constant_with_type(ctx, d, sub_typ))?;
250 let fields = ctx.arena.alloc(fields);
251
252 Ok(Constant::proto_list(ctx.arena, sub_typ, fields))
253 }
254
255 Type::Array(sub_typ) => {
256 let fields = d.list_with(ctx, |ctx, d| decode_constant_with_type(ctx, d, sub_typ))?;
257 let fields = ctx.arena.alloc(fields);
258 Ok(Constant::proto_array(ctx.arena, sub_typ, fields))
259 }
260 Type::Pair(sub_typ1, sub_typ2) => {
261 let fst = decode_constant_with_type(ctx, d, sub_typ1)?;
262 let snd = decode_constant_with_type(ctx, d, sub_typ2)?;
263
264 Ok(Constant::proto_pair(
265 ctx.arena, sub_typ1, sub_typ2, fst, snd,
266 ))
267 }
268 Type::Data => {
269 let cbor = d.bytes(ctx.arena)?;
270 let data = minicbor::decode_with(&cbor, ctx)?;
271 Ok(Constant::data(ctx.arena, data))
272 }
273 Type::Bls12_381G1Element => Err(FlatDecodeError::BlsTypeNotSupported),
274 Type::Bls12_381G2Element => Err(FlatDecodeError::BlsTypeNotSupported),
275 Type::Bls12_381MlResult => Err(FlatDecodeError::BlsTypeNotSupported),
276 }
277}
278
279fn decode_constant_with_type<'a>(
281 ctx: &mut Ctx<'a>,
282 d: &mut Decoder,
283 ty: &Type<'a>,
284) -> Result<&'a Constant<'a>, FlatDecodeError> {
285 match ty {
286 Type::Integer => {
287 let v = d.integer()?;
288 let v = ctx.arena.alloc_integer(v);
289
290 Ok(Constant::integer(ctx.arena, v))
291 }
292 Type::ByteString => {
293 let b = d.bytes(ctx.arena)?;
294 let b = ctx.arena.alloc(b);
295
296 Ok(Constant::byte_string(ctx.arena, b))
297 }
298 Type::Bool => {
299 let v = d.bit()?;
300
301 Ok(Constant::bool(ctx.arena, v))
302 }
303 Type::String => {
304 let s = d.utf8(ctx.arena)?;
305 let s = ctx.arena.alloc(s);
306
307 Ok(Constant::string(ctx.arena, s))
308 }
309 Type::Unit => Ok(Constant::unit(ctx.arena)),
310 Type::List(sub_typ) => {
311 let fields = d.list_with(ctx, |ctx, d| decode_constant_with_type(ctx, d, sub_typ))?;
312 let fields = ctx.arena.alloc(fields);
313
314 Ok(Constant::proto_list(ctx.arena, sub_typ, fields))
315 }
316 Type::Array(sub_typ) => {
317 let fields = d.list_with(ctx, |ctx, d| decode_constant_with_type(ctx, d, sub_typ))?;
318 let fields = ctx.arena.alloc(fields);
319 Ok(Constant::proto_array(ctx.arena, sub_typ, fields))
320 }
321 Type::Pair(sub_typ1, sub_typ2) => {
322 let fst = decode_constant_with_type(ctx, d, sub_typ1)?;
323 let snd = decode_constant_with_type(ctx, d, sub_typ2)?;
324
325 Ok(Constant::proto_pair(
326 ctx.arena, sub_typ1, sub_typ2, fst, snd,
327 ))
328 }
329 Type::Data => {
330 let cbor = d.bytes(ctx.arena)?;
331 let data = minicbor::decode_with(&cbor, ctx)?;
332
333 Ok(Constant::data(ctx.arena, data))
334 }
335 Type::Bls12_381G1Element => Err(FlatDecodeError::BlsTypeNotSupported),
336 Type::Bls12_381G2Element => Err(FlatDecodeError::BlsTypeNotSupported),
337 Type::Bls12_381MlResult => Err(FlatDecodeError::BlsTypeNotSupported),
338 }
339}
340
341fn decode_constant_tags<'a>(
342 ctx: &mut Ctx<'a>,
343 d: &mut Decoder,
344) -> Result<BumpVec<'a, u8>, FlatDecodeError> {
345 d.list_with(ctx, |_arena, d| decode_constant_tag(d))
346}
347
348fn decode_constant_tag(d: &mut Decoder) -> Result<u8, FlatDecodeError> {
349 d.bits8(CONST_TAG_WIDTH)
350}
351
352#[cfg(test)]
353mod tests {
354 use super::*;
355 use crate::{arena::Arena, binder::DeBruijn};
356 use hex;
357 use num::BigInt;
358
359 #[test]
360 fn decode_program_big_constr_tag() {
361 let bytes = hex::decode("0101003370090011aab9d375498109d8668218809f0001ff0001").unwrap();
374 let arena = Arena::new();
375 let program: Result<&Program<DeBruijn>, _> = decode(&arena, &bytes, PlutusVersion::V3, 9);
376 match program {
377 Ok(program) => {
378 let eval_result = program.eval(&arena);
379 let term = eval_result.term.unwrap();
380 assert_eq!(
381 term,
382 &Term::Constant(&Constant::Integer(&BigInt::from(129)))
383 );
384 }
385 Err(_) => {
386 panic!();
387 }
388 }
389 }
390
391 #[test]
392 fn decode_program_bigint() {
393 let bytes = hex::decode(
410 "0101003370090011bad357426aae78dd526112d8799fc24c033b2e3c9fd0803ce7ffffffff0001",
411 )
412 .unwrap();
413 let arena = Arena::new();
414 let program: Result<&Program<DeBruijn>, _> = decode(&arena, &bytes, PlutusVersion::V3, 9);
415 match program {
416 Ok(program) => {
417 let eval_result = program.eval(&arena);
418 let term = eval_result.term.unwrap();
419 assert_eq!(
420 term,
421 &Term::Constant(&Constant::Integer(&BigInt::from(
422 1_000_000_000_000_000_000_000_000_000i128
423 )))
424 );
425 }
426 Err(e) => {
427 panic!("{}", e);
428 }
429 }
430 }
431
432 #[test]
433 fn decode_program_list() {
434 let bytes = hex::decode("0101003370490021bad357426ae88dd62601049f070eff0001").unwrap();
451 let arena = Arena::new();
452 let program: Result<&Program<DeBruijn>, _> = decode(&arena, &bytes, PlutusVersion::V3, 9);
453 match program {
454 Ok(program) => {
455 let eval_result = program.eval(&arena);
456 let term = eval_result.term.unwrap();
457 assert_eq!(term, &Term::Constant(&Constant::Integer(&BigInt::from(28))));
458 }
459 Err(e) => {
460 panic!("{}", e);
461 }
462 }
463 }
464}