1#![forbid(unsafe_code)]
9
10use std::{cmp::max, sync::Arc};
11
12use anyhow::Result;
13use serde::{Deserialize, Serialize};
14
15use diem_crypto::{hash::TransactionAccumulatorHasher, HashValue};
16use diem_types::{
17 block_info::PivotBlockDecision,
18 epoch_state::EpochState,
19 ledger_info::LedgerInfoWithSignatures,
20 proof::{accumulator::InMemoryAccumulator, AccumulatorExtensionProof},
21 term_state::PosState,
22 transaction::{Transaction, TransactionStatus, Version},
23 validator_config::ConsensusSignature,
24};
25pub use error::Error;
26use storage_interface::TreeState;
27
28pub use self::processed_vm_output::{ProcessedVMOutput, TransactionData};
29
30mod error;
31mod processed_vm_output;
32
33pub trait BlockExecutor: Send {
34 fn committed_block_id(&self) -> Result<HashValue, Error>;
36
37 fn execute_block(
39 &self, block: (HashValue, Vec<Transaction>),
40 parent_block_id: HashValue, catch_up_mode: bool,
41 ) -> Result<StateComputeResult, Error>;
42
43 fn commit_blocks(
54 &self, block_ids: Vec<HashValue>,
55 ledger_info_with_sigs: LedgerInfoWithSignatures,
56 ) -> Result<Vec<Transaction>, Error>;
57}
58
59#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
69pub struct StateComputeResult {
70 root_hash: HashValue,
73 frozen_subtree_roots: Vec<HashValue>,
76
77 parent_frozen_subtree_roots: Vec<HashValue>,
79
80 num_leaves: u64,
84
85 parent_num_leaves: u64,
87
88 epoch_state: Option<EpochState>,
91 compute_status: Vec<TransactionStatus>,
95
96 transaction_info_hashes: Vec<HashValue>,
98
99 signature: Option<ConsensusSignature>,
101
102 pivot_decision: Option<PivotBlockDecision>,
104}
105
106impl StateComputeResult {
107 pub fn new(
108 root_hash: HashValue, frozen_subtree_roots: Vec<HashValue>,
109 num_leaves: u64, parent_frozen_subtree_roots: Vec<HashValue>,
110 parent_num_leaves: u64, epoch_state: Option<EpochState>,
111 compute_status: Vec<TransactionStatus>,
112 transaction_info_hashes: Vec<HashValue>,
113 pivot_decision: Option<PivotBlockDecision>,
114 ) -> Self {
115 Self {
116 root_hash,
117 frozen_subtree_roots,
118 num_leaves,
119 parent_frozen_subtree_roots,
120 parent_num_leaves,
121 epoch_state,
122 compute_status,
123 transaction_info_hashes,
124 signature: None,
125 pivot_decision,
126 }
127 }
128}
129
130impl StateComputeResult {
131 pub fn version(&self) -> Version {
132 max(self.num_leaves, 1)
133 .checked_sub(1)
134 .expect("Integer overflow occurred")
135 }
136
137 pub fn root_hash(&self) -> HashValue { self.root_hash }
138
139 pub fn compute_status(&self) -> &Vec<TransactionStatus> {
140 &self.compute_status
141 }
142
143 pub fn epoch_state(&self) -> &Option<EpochState> { &self.epoch_state }
144
145 pub fn extension_proof(
146 &self,
147 ) -> AccumulatorExtensionProof<TransactionAccumulatorHasher> {
148 AccumulatorExtensionProof::<TransactionAccumulatorHasher>::new(
149 self.parent_frozen_subtree_roots.clone(),
150 self.parent_num_leaves(),
151 self.transaction_info_hashes().clone(),
152 )
153 }
154
155 pub fn transaction_info_hashes(&self) -> &Vec<HashValue> {
156 &self.transaction_info_hashes
157 }
158
159 pub fn num_leaves(&self) -> u64 { self.num_leaves }
160
161 pub fn frozen_subtree_roots(&self) -> &Vec<HashValue> {
162 &self.frozen_subtree_roots
163 }
164
165 pub fn parent_num_leaves(&self) -> u64 { self.parent_num_leaves }
166
167 pub fn parent_frozen_subtree_roots(&self) -> &Vec<HashValue> {
168 &self.parent_frozen_subtree_roots
169 }
170
171 pub fn pivot_decision(&self) -> &Option<PivotBlockDecision> {
172 &self.pivot_decision
173 }
174
175 pub fn has_reconfiguration(&self) -> bool { self.epoch_state.is_some() }
176
177 pub fn signature(&self) -> &Option<ConsensusSignature> { &self.signature }
178
179 pub fn set_signature(&mut self, sig: ConsensusSignature) {
180 self.signature = Some(sig);
181 }
182}
183
184#[derive(Clone, Debug)]
188pub struct ExecutedTrees {
189 transaction_accumulator:
191 Arc<InMemoryAccumulator<TransactionAccumulatorHasher>>,
192
193 pos_state: PosState,
194}
195
196impl From<TreeState> for ExecutedTrees {
197 fn from(tree_state: TreeState) -> Self {
198 ExecutedTrees::new(
199 tree_state.ledger_frozen_subtree_hashes,
200 tree_state.num_transactions,
201 PosState::new_empty(),
202 )
203 }
204}
205
206impl ExecutedTrees {
207 pub fn new_with_pos_state(
208 tree_state: TreeState, pos_state: PosState,
209 ) -> Self {
210 ExecutedTrees::new(
211 tree_state.ledger_frozen_subtree_hashes,
212 tree_state.num_transactions,
213 pos_state,
214 )
215 }
216
217 pub fn new_copy(
218 transaction_accumulator: Arc<
219 InMemoryAccumulator<TransactionAccumulatorHasher>,
220 >,
221 pos_state: PosState,
222 ) -> Self {
223 Self {
224 transaction_accumulator,
225 pos_state,
226 }
227 }
228
229 pub fn pos_state(&self) -> &PosState { &self.pos_state }
230
231 pub fn txn_accumulator(
232 &self,
233 ) -> &Arc<InMemoryAccumulator<TransactionAccumulatorHasher>> {
234 &self.transaction_accumulator
235 }
236
237 pub fn version(&self) -> Option<Version> {
238 let num_elements = self.txn_accumulator().num_leaves() as u64;
239 num_elements.checked_sub(1)
240 }
241
242 pub fn state_id(&self) -> HashValue { self.txn_accumulator().root_hash() }
243
244 pub fn new(
245 frozen_subtrees_in_accumulator: Vec<HashValue>,
246 num_leaves_in_accumulator: u64, pos_state: PosState,
247 ) -> ExecutedTrees {
248 ExecutedTrees {
249 transaction_accumulator: Arc::new(
250 InMemoryAccumulator::new(
251 frozen_subtrees_in_accumulator,
252 num_leaves_in_accumulator,
253 )
254 .expect("The startup info read from storage should be valid."),
255 ),
256 pos_state,
257 }
258 }
259
260 pub fn new_empty() -> ExecutedTrees {
261 Self::new(vec![], 0, PosState::new_empty())
262 }
263
264 pub fn set_pos_state_skipped(&mut self, skipped: bool) {
265 self.pos_state.set_skipped(skipped)
266 }
267}