battleware_execution/
state_transition.rs1use crate::{Adb, Layer, State};
2use battleware_types::{
3 execution::{Output, Seed, Transaction, Value},
4 Identity, NAMESPACE,
5};
6use commonware_cryptography::{ed25519::PublicKey, sha256::Digest, Sha256};
7#[cfg(feature = "parallel")]
8use commonware_runtime::ThreadPool;
9use commonware_runtime::{Clock, Metrics, Spawner, Storage};
10use commonware_storage::{adb::keyless, mmr::hasher::Standard, translator::Translator};
11use std::collections::BTreeMap;
12
13pub struct StateTransitionResult {
15 pub state_root: Digest,
16 pub state_start_op: u64,
17 pub state_end_op: u64,
18 pub events_root: Digest,
19 pub events_start_op: u64,
20 pub events_end_op: u64,
21 pub processed_nonces: BTreeMap<PublicKey, u64>,
23}
24
25pub async fn execute_state_transition<S: Spawner + Storage + Clock + Metrics, T: Translator>(
34 state: &mut Adb<S, T>,
35 events: &mut keyless::Keyless<S, Output, Sha256>,
36 identity: Identity,
37 height: u64,
38 seed: Seed,
39 transactions: Vec<Transaction>,
40 #[cfg(feature = "parallel")] pool: ThreadPool,
41) -> StateTransitionResult {
42 let (state_height, mut state_start_op) = state
44 .get_metadata()
45 .await
46 .unwrap()
47 .and_then(|(_, v)| match v {
48 Some(Value::Commit { height, start }) => Some((height, start)),
49 _ => None,
50 })
51 .unwrap_or((0, 0));
52 assert!(
53 height == state_height || height == state_height + 1,
54 "state transition must be for next block or tip"
55 );
56
57 let (events_height, mut events_start_op) = events
59 .get_metadata()
60 .await
61 .unwrap()
62 .and_then(|(_, v)| match v {
63 Some(Output::Commit { height, start }) => Some((height, start)),
64 _ => None,
65 })
66 .unwrap_or((0, 0));
67
68 let mut processed_nonces = BTreeMap::new();
70 if height == state_height + 1 {
71 state_start_op = state.op_count();
72 let mut layer = Layer::new(state, identity, NAMESPACE, seed);
73 let (outputs, nonces) = layer
74 .execute(
75 #[cfg(feature = "parallel")]
76 pool,
77 transactions,
78 )
79 .await;
80 processed_nonces.extend(nonces);
81
82 if height == events_height + 1 {
84 events_start_op = events.op_count();
85 for output in outputs.into_iter() {
86 events.append(output).await.unwrap();
87 }
88 events
89 .commit(Some(Output::Commit {
90 height,
91 start: events_start_op,
92 }))
93 .await
94 .unwrap();
95 }
96
97 state.apply(layer.commit()).await;
99 state
100 .commit(Some(Value::Commit {
101 height,
102 start: state_start_op,
103 }))
104 .await
105 .unwrap();
106 }
107
108 let mut mmr_hasher = Standard::<Sha256>::new();
110 let state_root = state.root(&mut mmr_hasher);
111 let state_end_op = state.op_count();
112 let events_root = events.root(&mut mmr_hasher);
113 let events_end_op = events.op_count();
114
115 StateTransitionResult {
116 state_root,
117 state_start_op,
118 state_end_op,
119 events_root,
120 events_start_op,
121 events_end_op,
122 processed_nonces,
123 }
124}