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 contract_event::ContractEvent,
19 epoch_state::EpochState,
20 ledger_info::LedgerInfoWithSignatures,
21 proof::{accumulator::InMemoryAccumulator, AccumulatorExtensionProof},
22 term_state::PosState,
23 transaction::{Transaction, TransactionStatus, Version},
24 validator_config::ConsensusSignature,
25};
26pub use error::Error;
27use storage_interface::TreeState;
28
29pub use self::processed_vm_output::{ProcessedVMOutput, TransactionData};
30
31mod error;
32mod processed_vm_output;
33
34pub trait BlockExecutor: Send {
35 fn committed_block_id(&self) -> Result<HashValue, Error>;
37
38 fn execute_block(
40 &self, block: (HashValue, Vec<Transaction>),
41 parent_block_id: HashValue, catch_up_mode: bool,
42 ) -> Result<StateComputeResult, Error>;
43
44 fn commit_blocks(
59 &self, block_ids: Vec<HashValue>,
60 ledger_info_with_sigs: LedgerInfoWithSignatures,
61 ) -> Result<(Vec<Transaction>, Vec<ContractEvent>), Error>;
62}
63
64#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
74pub struct StateComputeResult {
75 root_hash: HashValue,
78 frozen_subtree_roots: Vec<HashValue>,
81
82 parent_frozen_subtree_roots: Vec<HashValue>,
84
85 num_leaves: u64,
89
90 parent_num_leaves: u64,
92
93 epoch_state: Option<EpochState>,
96 compute_status: Vec<TransactionStatus>,
100
101 transaction_info_hashes: Vec<HashValue>,
103
104 signature: Option<ConsensusSignature>,
106
107 pivot_decision: Option<PivotBlockDecision>,
109}
110
111impl StateComputeResult {
112 pub fn new(
113 root_hash: HashValue, frozen_subtree_roots: Vec<HashValue>,
114 num_leaves: u64, parent_frozen_subtree_roots: Vec<HashValue>,
115 parent_num_leaves: u64, epoch_state: Option<EpochState>,
116 compute_status: Vec<TransactionStatus>,
117 transaction_info_hashes: Vec<HashValue>,
118 pivot_decision: Option<PivotBlockDecision>,
119 ) -> Self {
120 Self {
121 root_hash,
122 frozen_subtree_roots,
123 num_leaves,
124 parent_frozen_subtree_roots,
125 parent_num_leaves,
126 epoch_state,
127 compute_status,
128 transaction_info_hashes,
129 signature: None,
130 pivot_decision,
131 }
132 }
133}
134
135impl StateComputeResult {
136 pub fn version(&self) -> Version {
137 max(self.num_leaves, 1)
138 .checked_sub(1)
139 .expect("Integer overflow occurred")
140 }
141
142 pub fn root_hash(&self) -> HashValue { self.root_hash }
143
144 pub fn compute_status(&self) -> &Vec<TransactionStatus> {
145 &self.compute_status
146 }
147
148 pub fn epoch_state(&self) -> &Option<EpochState> { &self.epoch_state }
149
150 pub fn extension_proof(
151 &self,
152 ) -> AccumulatorExtensionProof<TransactionAccumulatorHasher> {
153 AccumulatorExtensionProof::<TransactionAccumulatorHasher>::new(
154 self.parent_frozen_subtree_roots.clone(),
155 self.parent_num_leaves(),
156 self.transaction_info_hashes().clone(),
157 )
158 }
159
160 pub fn transaction_info_hashes(&self) -> &Vec<HashValue> {
161 &self.transaction_info_hashes
162 }
163
164 pub fn num_leaves(&self) -> u64 { self.num_leaves }
165
166 pub fn frozen_subtree_roots(&self) -> &Vec<HashValue> {
167 &self.frozen_subtree_roots
168 }
169
170 pub fn parent_num_leaves(&self) -> u64 { self.parent_num_leaves }
171
172 pub fn parent_frozen_subtree_roots(&self) -> &Vec<HashValue> {
173 &self.parent_frozen_subtree_roots
174 }
175
176 pub fn pivot_decision(&self) -> &Option<PivotBlockDecision> {
177 &self.pivot_decision
178 }
179
180 pub fn has_reconfiguration(&self) -> bool { self.epoch_state.is_some() }
181
182 pub fn signature(&self) -> &Option<ConsensusSignature> { &self.signature }
183
184 pub fn set_signature(&mut self, sig: ConsensusSignature) {
185 self.signature = Some(sig);
186 }
187}
188
189#[derive(Clone, Debug)]
193pub struct ExecutedTrees {
194 transaction_accumulator:
196 Arc<InMemoryAccumulator<TransactionAccumulatorHasher>>,
197
198 pos_state: PosState,
199}
200
201impl From<TreeState> for ExecutedTrees {
202 fn from(tree_state: TreeState) -> Self {
203 ExecutedTrees::new(
204 tree_state.ledger_frozen_subtree_hashes,
205 tree_state.num_transactions,
206 PosState::new_empty(),
207 )
208 }
209}
210
211impl ExecutedTrees {
212 pub fn new_with_pos_state(
213 tree_state: TreeState, pos_state: PosState,
214 ) -> Self {
215 ExecutedTrees::new(
216 tree_state.ledger_frozen_subtree_hashes,
217 tree_state.num_transactions,
218 pos_state,
219 )
220 }
221
222 pub fn new_copy(
223 transaction_accumulator: Arc<
224 InMemoryAccumulator<TransactionAccumulatorHasher>,
225 >,
226 pos_state: PosState,
227 ) -> Self {
228 Self {
229 transaction_accumulator,
230 pos_state,
231 }
232 }
233
234 pub fn pos_state(&self) -> &PosState { &self.pos_state }
235
236 pub fn txn_accumulator(
237 &self,
238 ) -> &Arc<InMemoryAccumulator<TransactionAccumulatorHasher>> {
239 &self.transaction_accumulator
240 }
241
242 pub fn version(&self) -> Option<Version> {
243 let num_elements = self.txn_accumulator().num_leaves() as u64;
244 num_elements.checked_sub(1)
245 }
246
247 pub fn state_id(&self) -> HashValue { self.txn_accumulator().root_hash() }
248
249 pub fn new(
250 frozen_subtrees_in_accumulator: Vec<HashValue>,
251 num_leaves_in_accumulator: u64, pos_state: PosState,
252 ) -> ExecutedTrees {
253 ExecutedTrees {
254 transaction_accumulator: Arc::new(
255 InMemoryAccumulator::new(
256 frozen_subtrees_in_accumulator,
257 num_leaves_in_accumulator,
258 )
259 .expect("The startup info read from storage should be valid."),
260 ),
261 pos_state,
262 }
263 }
264
265 pub fn new_empty() -> ExecutedTrees {
266 Self::new(vec![], 0, PosState::new_empty())
267 }
268
269 pub fn set_pos_state_skipped(&mut self, skipped: bool) {
270 self.pos_state.set_skipped(skipped)
271 }
272}