use crate::{Adb, Layer, State};
use battleware_types::{
execution::{Output, Seed, Transaction, Value},
Identity, NAMESPACE,
};
use commonware_cryptography::{ed25519::PublicKey, sha256::Digest, Sha256};
#[cfg(feature = "parallel")]
use commonware_runtime::ThreadPool;
use commonware_runtime::{Clock, Metrics, Spawner, Storage};
use commonware_storage::{adb::keyless, mmr::hasher::Standard, translator::Translator};
use std::collections::BTreeMap;
pub struct StateTransitionResult {
pub state_root: Digest,
pub state_start_op: u64,
pub state_end_op: u64,
pub events_root: Digest,
pub events_start_op: u64,
pub events_end_op: u64,
pub processed_nonces: BTreeMap<PublicKey, u64>,
}
pub async fn execute_state_transition<S: Spawner + Storage + Clock + Metrics, T: Translator>(
state: &mut Adb<S, T>,
events: &mut keyless::Keyless<S, Output, Sha256>,
identity: Identity,
height: u64,
seed: Seed,
transactions: Vec<Transaction>,
#[cfg(feature = "parallel")] pool: ThreadPool,
) -> StateTransitionResult {
let (state_height, mut state_start_op) = state
.get_metadata()
.await
.unwrap()
.and_then(|(_, v)| match v {
Some(Value::Commit { height, start }) => Some((height, start)),
_ => None,
})
.unwrap_or((0, 0));
assert!(
height == state_height || height == state_height + 1,
"state transition must be for next block or tip"
);
let (events_height, mut events_start_op) = events
.get_metadata()
.await
.unwrap()
.and_then(|(_, v)| match v {
Some(Output::Commit { height, start }) => Some((height, start)),
_ => None,
})
.unwrap_or((0, 0));
let mut processed_nonces = BTreeMap::new();
if height == state_height + 1 {
state_start_op = state.op_count();
let mut layer = Layer::new(state, identity, NAMESPACE, seed);
let (outputs, nonces) = layer
.execute(
#[cfg(feature = "parallel")]
pool,
transactions,
)
.await;
processed_nonces.extend(nonces);
if height == events_height + 1 {
events_start_op = events.op_count();
for output in outputs.into_iter() {
events.append(output).await.unwrap();
}
events
.commit(Some(Output::Commit {
height,
start: events_start_op,
}))
.await
.unwrap();
}
state.apply(layer.commit()).await;
state
.commit(Some(Value::Commit {
height,
start: state_start_op,
}))
.await
.unwrap();
}
let mut mmr_hasher = Standard::<Sha256>::new();
let state_root = state.root(&mut mmr_hasher);
let state_end_op = state.op_count();
let events_root = events.root(&mut mmr_hasher);
let events_end_op = events.op_count();
StateTransitionResult {
state_root,
state_start_op,
state_end_op,
events_root,
events_start_op,
events_end_op,
processed_nonces,
}
}