use std::sync::{Arc, Mutex};
use miden_core::{
Felt, Word,
crypto::merkle::InnerNodeInfo,
serde::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable},
};
use miden_processor::advice::{AdviceMap, AdviceMutation, AdviceStack};
pub fn clone_advice_mutation(mutation: &AdviceMutation) -> AdviceMutation {
match mutation {
AdviceMutation::ExtendStack { stack } => AdviceMutation::ExtendStack {
stack: stack.clone(),
},
AdviceMutation::ExtendMap { other } => AdviceMutation::ExtendMap {
other: other.clone(),
},
AdviceMutation::ExtendMerkleStore { infos } => AdviceMutation::ExtendMerkleStore {
infos: infos.clone(),
},
}
}
pub fn clone_advice_mutations(mutations: &[AdviceMutation]) -> Vec<AdviceMutation> {
mutations.iter().map(clone_advice_mutation).collect()
}
const TAG_EXTEND_STACK: u8 = 0;
const TAG_EXTEND_MAP: u8 = 1;
const TAG_EXTEND_MERKLE_STORE: u8 = 2;
pub fn write_advice_mutation<W: ByteWriter>(mutation: &AdviceMutation, target: &mut W) {
match mutation {
AdviceMutation::ExtendStack { stack } => {
target.write_u8(TAG_EXTEND_STACK);
stack.iter().copied().collect::<Vec<_>>().write_into(target);
}
AdviceMutation::ExtendMap { other } => {
target.write_u8(TAG_EXTEND_MAP);
other.write_into(target);
}
AdviceMutation::ExtendMerkleStore { infos } => {
target.write_u8(TAG_EXTEND_MERKLE_STORE);
target.write_usize(infos.len());
for info in infos {
info.value.write_into(target);
info.left.write_into(target);
info.right.write_into(target);
}
}
}
}
pub fn read_advice_mutation<R: ByteReader>(
source: &mut R,
) -> Result<AdviceMutation, DeserializationError> {
match source.read_u8()? {
TAG_EXTEND_STACK => Ok(AdviceMutation::ExtendStack {
stack: AdviceStack::from(Vec::<Felt>::read_from(source)?),
}),
TAG_EXTEND_MAP => Ok(AdviceMutation::ExtendMap {
other: AdviceMap::read_from(source)?,
}),
TAG_EXTEND_MERKLE_STORE => {
let len = source.read_usize()?;
let mut infos = Vec::with_capacity(len);
for _ in 0..len {
let value = Word::read_from(source)?;
let left = Word::read_from(source)?;
let right = Word::read_from(source)?;
infos.push(InnerNodeInfo { value, left, right });
}
Ok(AdviceMutation::ExtendMerkleStore { infos })
}
other => Err(DeserializationError::InvalidValue(format!(
"unknown AdviceMutation variant tag: {other}"
))),
}
}
pub fn write_event_log<W: ByteWriter>(log: &[Vec<AdviceMutation>], target: &mut W) {
target.write_usize(log.len());
for batch in log {
target.write_usize(batch.len());
for mutation in batch {
write_advice_mutation(mutation, target);
}
}
}
pub fn read_event_log<R: ByteReader>(
source: &mut R,
) -> Result<Vec<Vec<AdviceMutation>>, DeserializationError> {
let batches = source.read_usize()?;
let mut log = Vec::with_capacity(batches);
for _ in 0..batches {
let len = source.read_usize()?;
let mut batch = Vec::with_capacity(len);
for _ in 0..len {
batch.push(read_advice_mutation(source)?);
}
log.push(batch);
}
Ok(log)
}
#[derive(Clone, Default)]
pub struct EventMutationRecorder {
log: Arc<Mutex<Vec<Vec<AdviceMutation>>>>,
}
impl core::fmt::Debug for EventMutationRecorder {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("EventMutationRecorder").field("events", &self.len()).finish()
}
}
impl EventMutationRecorder {
pub fn new() -> Self {
Self::default()
}
pub fn take(&self) -> Vec<Vec<AdviceMutation>> {
core::mem::take(&mut *self.log.lock().expect("event mutation log poisoned"))
}
pub fn snapshot(&self) -> Vec<Vec<AdviceMutation>> {
self.log
.lock()
.expect("event mutation log poisoned")
.iter()
.map(|batch| clone_advice_mutations(batch))
.collect()
}
pub fn len(&self) -> usize {
self.log.lock().expect("event mutation log poisoned").len()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub(crate) fn record(&self, mutations: Vec<AdviceMutation>) {
self.log.lock().expect("event mutation log poisoned").push(mutations);
}
pub(crate) fn clear(&self) {
self.log.lock().expect("event mutation log poisoned").clear();
}
}