use miden_assembly::{Assembler, DefaultSourceManager};
use miden_core::{Felt, Word, crypto::merkle::InnerNodeInfo};
use super::*;
fn word(values: [u32; 4]) -> Word {
Word::from(values.map(Felt::from))
}
#[test]
fn replay_snapshot_round_trips() {
let source_manager = Arc::new(DefaultSourceManager::default());
let program = Assembler::new(source_manager)
.assemble_program("program", "begin push.1 push.2 add drop end")
.map(Arc::<Package>::from)
.expect("failed to assemble test program");
let forest = LoadedMastForest::with_package_debug_info(
program.mast_forest().clone(),
program.debug_info(),
);
let event_log = vec![
vec![AdviceMutation::extend_advice_stack(
[Felt::from(7u32), Felt::from(8u32)].into_iter().collect(),
)],
vec![],
vec![AdviceMutation::extend_merkle_store([InnerNodeInfo {
value: word([1, 2, 3, 4]),
left: word([5, 6, 7, 8]),
right: word([9, 10, 11, 12]),
}])],
];
let snapshot = ReplaySnapshot {
package: program.clone(),
stack_inputs: StackInputs::new(&[Felt::from(42u32), Felt::from(43u32)]).unwrap(),
advice_inputs: AdviceInputs::default()
.with_stack([Felt::from(99u32)].into_iter().collect()),
options: ExecutionOptions::new(Some(100_000), 32, 1024)
.unwrap()
.with_max_advice_size_bytes(256)
.with_max_hash_len_bytes(512)
.with_overlapped_trace_build(false)
.with_max_num_continuations(128)
.with_max_memory_elements(1024)
.with_max_stack_depth(128)
.unwrap(),
mast_forests: vec![forest],
event_log,
};
let restored = ReplaySnapshot::read_from_bytes(&snapshot.to_bytes())
.expect("snapshot failed to deserialize");
assert_eq!(restored.package.commitment(), snapshot.package.commitment());
assert_eq!(restored.stack_inputs, snapshot.stack_inputs);
assert_eq!(restored.advice_inputs, snapshot.advice_inputs);
assert_eq!(restored.options, snapshot.options);
assert_eq!(restored.mast_forests.len(), 1);
assert_eq!(restored.event_log.len(), 3);
assert_eq!(restored.event_log[1].len(), 0, "empty event batch must survive");
match restored.event_log[0].as_slice() {
[AdviceMutation::ExtendStack { stack }] => {
assert_eq!(
stack.iter().copied().collect::<Vec<_>>(),
[Felt::from(7u32), Felt::from(8u32)],
);
}
_ => panic!("unexpected first event batch"),
}
match restored.event_log[2].as_slice() {
[AdviceMutation::ExtendMerkleStore { inner_nodes }] => {
assert_eq!(inner_nodes.len(), 1);
assert_eq!(inner_nodes[0].value, word([1, 2, 3, 4]));
assert_eq!(inner_nodes[0].right, word([9, 10, 11, 12]));
}
_ => panic!("unexpected merkle-store event batch"),
}
}
#[test]
fn replay_snapshot_rejects_bad_magic() {
let err = ReplaySnapshot::read_from_bytes(b"not a snapshot at all really");
assert!(err.is_err(), "expected deserialization to fail on bad magic");
}
#[test]
fn replay_snapshot_rejects_previous_version() {
let mut bytes = SNAPSHOT_MAGIC.to_vec();
bytes.push(SNAPSHOT_VERSION - 1);
let Err(err) = ReplaySnapshot::read_from_bytes(&bytes) else {
panic!("expected deserialization to reject a snapshot from a previous version");
};
assert!(err.to_string().contains("unsupported replay snapshot version"));
}