use alloc::{format, string::String, vec, vec::Vec};
use miden_core::{
EventName, Felt, WORD_SIZE, Word,
crypto::merkle::{EmptySubtreeRoots, SMT_DEPTH, Smt},
};
use miden_processor::{AdviceMutation, EventError, ProcessState};
pub const SMT_PEEK_EVENT_NAME: EventName = EventName::new("stdlib::collections::smt::smt_peek");
pub fn handle_smt_peek(process: &ProcessState) -> Result<Vec<AdviceMutation>, EventError> {
let empty_leaf = EmptySubtreeRoots::entry(SMT_DEPTH, SMT_DEPTH);
let key = process.get_stack_word_be(1);
let root = process.get_stack_word_be(5);
let node = process
.advice_provider()
.get_tree_node(root, Felt::new(SMT_DEPTH as u64), key[3])
.map_err(|err| SmtPeekError::AdviceProviderError {
message: format!("Failed to get tree node: {}", err),
})?;
if node == *empty_leaf {
let mutation = AdviceMutation::extend_stack(Smt::EMPTY_VALUE.into_iter().rev());
Ok(vec![mutation])
} else {
let leaf_preimage = get_smt_leaf_preimage(process, node)?;
for (key_in_leaf, value_in_leaf) in leaf_preimage {
if key == key_in_leaf {
let mutation = AdviceMutation::extend_stack(value_in_leaf.into_iter().rev());
return Ok(vec![mutation]);
}
}
let mutation = AdviceMutation::extend_stack(Smt::EMPTY_VALUE.into_iter().rev());
Ok(vec![mutation])
}
}
fn get_smt_leaf_preimage(
process: &ProcessState,
node: Word,
) -> Result<Vec<(Word, Word)>, SmtPeekError> {
let kv_pairs = process
.advice_provider()
.get_mapped_values(&node)
.ok_or(SmtPeekError::SmtNodeNotFound { node })?;
if kv_pairs.len() % (WORD_SIZE * 2) != 0 {
return Err(SmtPeekError::InvalidSmtNodePreimage { node, preimage_len: kv_pairs.len() });
}
Ok(kv_pairs
.chunks_exact(WORD_SIZE * 2)
.map(|kv_chunk| {
let key = [kv_chunk[0], kv_chunk[1], kv_chunk[2], kv_chunk[3]];
let value = [kv_chunk[4], kv_chunk[5], kv_chunk[6], kv_chunk[7]];
(key.into(), value.into())
})
.collect())
}
#[derive(Debug, thiserror::Error)]
pub enum SmtPeekError {
#[error("advice provider error: {message}")]
AdviceProviderError { message: String },
#[error("SMT node not found: {node:?}")]
SmtNodeNotFound { node: Word },
#[error("invalid SMT node preimage length for node {node:?}: got {preimage_len}, expected multiple of {}", WORD_SIZE * 2)]
InvalidSmtNodePreimage { node: Word, preimage_len: usize },
}