|
1 | 1 | use simplicity::bit_machine::{ExecTracker, FrameIter, NodeOutput, PruneTracker, SetTracker}; |
2 | 2 | use simplicity::jet::{Elements, Jet}; |
3 | 3 | use simplicity::node::Inner; |
4 | | -use simplicity::{Ihr, RedeemNode, Value as SimValue, ValueRef}; |
| 4 | +use simplicity::{Ihr, RedeemNode, Value as SimValue}; |
5 | 5 |
|
| 6 | +use crate::array::Unfolder; |
6 | 7 | use crate::debug::{DebugSymbols, TrackedCallName}; |
7 | 8 | use crate::either::Either; |
8 | 9 | use crate::jet::{source_type, target_type}; |
@@ -338,43 +339,20 @@ fn parse_jet_arguments(jet: Elements, input_frame: &mut FrameIter) -> Result<Vec |
338 | 339 | let arguments_blob = SimValue::from_padded_bits(input_frame, &jet.source_ty().to_final()) |
339 | 340 | .expect("input from bit machine is always well-formed"); |
340 | 341 |
|
341 | | - let mut args = Vec::with_capacity(source_types.len()); |
342 | | - collect_product_elements(&arguments_blob.as_ref(), source_types.len(), &mut args)?; |
| 342 | + let args = Unfolder::new(arguments_blob.as_ref(), source_types.len()) |
| 343 | + .unfold(|v| v.as_product()) |
| 344 | + .ok_or("expected product type while collecting arguments")?; |
343 | 345 |
|
344 | 346 | Ok(args |
345 | 347 | .into_iter() |
346 | 348 | .zip(source_types.iter()) |
347 | 349 | .map(|(arg, aliased_type)| { |
348 | | - Value::reconstruct(&arg.into(), &resolve_jet_type(aliased_type)) |
| 350 | + Value::reconstruct(&arg.to_value().into(), &resolve_jet_type(aliased_type)) |
349 | 351 | .expect("compiled program produces correctly structured values") |
350 | 352 | }) |
351 | 353 | .collect()) |
352 | 354 | } |
353 | 355 |
|
354 | | -/// Recursively collects elements from a nested product type. |
355 | | -/// |
356 | | -/// Given a value of type `(A, (B, (C, ...)))`, extracts `[A, B, C, ...]`. |
357 | | -fn collect_product_elements( |
358 | | - node: &ValueRef, |
359 | | - count: usize, |
360 | | - elements: &mut Vec<SimValue>, |
361 | | -) -> Result<(), String> { |
362 | | - match count { |
363 | | - 0 => Ok(()), |
364 | | - 1 => { |
365 | | - elements.push(node.to_value()); |
366 | | - Ok(()) |
367 | | - } |
368 | | - _ => { |
369 | | - let (left, right) = node |
370 | | - .as_product() |
371 | | - .ok_or("expected product type while collecting arguments")?; |
372 | | - elements.push(left.to_value()); |
373 | | - collect_product_elements(&right, count - 1, elements) |
374 | | - } |
375 | | - } |
376 | | -} |
377 | | - |
378 | 356 | /// Resolves an aliased type to its concrete form. |
379 | 357 | fn resolve_jet_type(aliased_type: &AliasedType) -> ResolvedType { |
380 | 358 | aliased_type |
@@ -572,4 +550,94 @@ mod tests { |
572 | 550 | ); |
573 | 551 | assert_eq!(jets.get("eq_64").unwrap().1, Some("true".to_string())); |
574 | 552 | } |
| 553 | + |
| 554 | + const TEST_FULL_MULTIPLY_JETS: &str = r#" |
| 555 | + fn main() { |
| 556 | + let r8: u16 = jet::full_multiply_8(200, 201, 202, 203); |
| 557 | + let r16: u32 = jet::full_multiply_16(20000, 20001, 20002, 20003); |
| 558 | + let r32: u64 = jet::full_multiply_32(2000000000, 2000000001, 2000000002, 2000000003); |
| 559 | + let r64: u128 = jet::full_multiply_64(2000000000, 2000000001, 2000000002, 2000000003); |
| 560 | +
|
| 561 | + assert!(jet::eq_16(r8, 40605)); |
| 562 | + assert!(jet::eq_32(r16, 400060005)); |
| 563 | + assert!(jet::eq_64(r32, 4000000006000000005)); |
| 564 | +
|
| 565 | + // TODO: Currently no eq_128 jet, this must be revised in future. Placeholder to match on 'unwrap().1`. |
| 566 | + let _keep: u128 = r64; |
| 567 | + } |
| 568 | + "#; |
| 569 | + |
| 570 | + #[test] |
| 571 | + fn test_full_multiply_jet_trace_regression() { |
| 572 | + // FullMultiply -> (a * b + c + d) |
| 573 | + |
| 574 | + let env = create_test_env(); |
| 575 | + |
| 576 | + let program = TemplateProgram::new(TEST_FULL_MULTIPLY_JETS).unwrap(); |
| 577 | + let program = program.instantiate(Arguments::default(), true).unwrap(); |
| 578 | + let satisfied = program.satisfy(WitnessValues::default()).unwrap(); |
| 579 | + |
| 580 | + let (mut tracker, _, jet_store) = create_test_tracker(&satisfied.debug_symbols); |
| 581 | + |
| 582 | + let _ = satisfied.redeem().prune_with_tracker(&env, &mut tracker); |
| 583 | + |
| 584 | + let jets = jet_store.borrow(); |
| 585 | + |
| 586 | + assert_eq!( |
| 587 | + jets.get("full_multiply_8").unwrap().0, |
| 588 | + Some(vec![ |
| 589 | + "200".to_string(), |
| 590 | + "201".to_string(), |
| 591 | + "202".to_string(), |
| 592 | + "203".to_string(), |
| 593 | + ]) |
| 594 | + ); |
| 595 | + assert_eq!( |
| 596 | + jets.get("full_multiply_8").unwrap().1, |
| 597 | + Some("40605".to_string()) |
| 598 | + ); |
| 599 | + |
| 600 | + assert_eq!( |
| 601 | + jets.get("full_multiply_16").unwrap().0, |
| 602 | + Some(vec![ |
| 603 | + "20000".to_string(), |
| 604 | + "20001".to_string(), |
| 605 | + "20002".to_string(), |
| 606 | + "20003".to_string(), |
| 607 | + ]) |
| 608 | + ); |
| 609 | + assert_eq!( |
| 610 | + jets.get("full_multiply_16").unwrap().1, |
| 611 | + Some("400060005".to_string()) |
| 612 | + ); |
| 613 | + |
| 614 | + assert_eq!( |
| 615 | + jets.get("full_multiply_32").unwrap().0, |
| 616 | + Some(vec![ |
| 617 | + "2000000000".to_string(), |
| 618 | + "2000000001".to_string(), |
| 619 | + "2000000002".to_string(), |
| 620 | + "2000000003".to_string(), |
| 621 | + ]) |
| 622 | + ); |
| 623 | + assert_eq!( |
| 624 | + jets.get("full_multiply_32").unwrap().1, |
| 625 | + Some("4000000006000000005".to_string()) |
| 626 | + ); |
| 627 | + |
| 628 | + assert_eq!( |
| 629 | + jets.get("full_multiply_64").unwrap().0, |
| 630 | + Some(vec![ |
| 631 | + "2000000000".to_string(), |
| 632 | + "2000000001".to_string(), |
| 633 | + "2000000002".to_string(), |
| 634 | + "2000000003".to_string(), |
| 635 | + ]) |
| 636 | + ); |
| 637 | + assert_eq!( |
| 638 | + jets.get("full_multiply_64").unwrap().1, |
| 639 | + // Check: u128 defaults to hex in fmt::Display for UIntValue |
| 640 | + Some("0x00000000000000003782dad00330bc05".to_string()) // u128 => 4000000006000000005 |
| 641 | + ); |
| 642 | + } |
575 | 643 | } |
0 commit comments