use crate::Process;
use super::*;
impl<N: Network> Translation<N> {
pub fn prepare(
&self,
transitions: &[Transition<N>],
call_graph: &HashMap<N::TransitionID, Vec<N::TransitionID>>,
) -> Result<Vec<(ProvingKey<N>, Vec<(TranslationAssignment<N>, u16)>)>> {
let mut batched_assignments: HashMap<
(ProgramID<N>, Identifier<N>),
(ProvingKey<N>, Vec<(TranslationAssignment<N>, u16)>),
> = HashMap::new();
let mut translation_index: u16 = 0;
let mut caller_id_to_next_task: HashMap<N::TransitionID, usize> =
self.translation_tasks.keys().map(|transition_id| (*transition_id, 0)).collect();
let reverse_call_graph = Process::<N>::reverse_call_graph(call_graph);
let mut consume_translation_task = |caller_id: N::TransitionID| -> Result<()> {
let translation_tasks = self
.translation_tasks
.get(&caller_id)
.ok_or_else(|| anyhow!("Translation tasks not found for (caller) transition ID {caller_id}"))?;
let next_task = caller_id_to_next_task.get_mut(&caller_id).unwrap();
let (assignment, proving_key) = translation_tasks.get(*next_task).ok_or_else(
|| anyhow!(
"Translation task not found for (caller) transition ID {}: queried task with index {} but only {} are available",
caller_id,
*next_task,
translation_tasks.len()
)
)?;
*next_task += 1;
let (_, assignments) = batched_assignments
.entry((assignment.program_id, assignment.record_name))
.or_insert_with(|| (proving_key.clone(), Vec::new()));
assignments.push((assignment.clone(), translation_index));
translation_index += 1;
Ok(())
};
for transition in transitions {
let transition_id = transition.id();
for input in transition.inputs() {
if input.dynamic_id().is_some() {
let caller_transition_id = reverse_call_graph
.get(transition_id)
.ok_or_else(|| anyhow!("Caller transition ID not found for transition ID {transition_id}"))?;
consume_translation_task(*caller_transition_id)?;
}
}
for output in transition.outputs() {
if output.dynamic_id().is_some() {
let caller_transition_id = reverse_call_graph
.get(transition_id)
.ok_or_else(|| anyhow!("Caller transition ID not found for transition ID {transition_id}"))?;
consume_translation_task(*caller_transition_id)?;
}
}
}
for (transition_id, next_task) in caller_id_to_next_task.iter() {
ensure!(
*next_task == self.translation_tasks.get(transition_id).unwrap().len(),
"Not all (caller) translation tasks have been consumed for transition ID {}: there are {}, but only {} have been consumed",
transition_id,
self.translation_tasks.get(transition_id).unwrap().len(),
*next_task
);
}
Ok(batched_assignments.into_values().collect())
}
#[cfg(feature = "async")]
pub async fn prepare_async(
&self,
transitions: &[Transition<N>],
call_graph: &HashMap<N::TransitionID, Vec<N::TransitionID>>,
) -> Result<Vec<(ProvingKey<N>, Vec<(TranslationAssignment<N>, u16)>)>> {
self.prepare(transitions, call_graph)
}
}