executor_types/
processed_vm_output.rs

1// Copyright (c) The Diem Core Contributors
2// SPDX-License-Identifier: Apache-2.0
3
4// Copyright 2021 Conflux Foundation. All rights reserved.
5// Conflux is free software and distributed under GNU General Public License.
6// See http://www.gnu.org/licenses/
7
8#![forbid(unsafe_code)]
9
10use crate::{ExecutedTrees, StateComputeResult};
11use diem_crypto::{hash::EventAccumulatorHasher, HashValue};
12use diem_types::{
13    block_info::PivotBlockDecision,
14    contract_event::ContractEvent,
15    epoch_state::EpochState,
16    proof::accumulator::InMemoryAccumulator,
17    term_state::PosState,
18    transaction::{TransactionStatus, Version},
19};
20use std::sync::Arc;
21
22/// The entire set of data associated with a transaction. In addition to the
23/// output generated by VM which includes the write set and events, this also
24/// has the in-memory trees.
25#[derive(Clone, Debug)]
26pub struct TransactionData {
27    /// The list of events emitted during this transaction.
28    events: Vec<ContractEvent>,
29
30    /// The execution status set by the VM.
31    status: TransactionStatus,
32
33    /// The in-memory Merkle Accumulator that has all events emitted by this
34    /// transaction.
35    event_tree: Arc<InMemoryAccumulator<EventAccumulatorHasher>>,
36
37    /// The amount of gas used.
38    gas_used: u64,
39
40    /// The transaction info hash if the VM status output was keep, None
41    /// otherwise
42    txn_info_hash: Option<HashValue>,
43}
44
45impl TransactionData {
46    pub fn new(
47        events: Vec<ContractEvent>, status: TransactionStatus,
48        event_tree: Arc<InMemoryAccumulator<EventAccumulatorHasher>>,
49        gas_used: u64, txn_info_hash: Option<HashValue>,
50    ) -> Self {
51        TransactionData {
52            events,
53            status,
54            event_tree,
55            gas_used,
56            txn_info_hash,
57        }
58    }
59
60    pub fn events(&self) -> &[ContractEvent] { &self.events }
61
62    pub fn status(&self) -> &TransactionStatus { &self.status }
63
64    pub fn event_root_hash(&self) -> HashValue { self.event_tree.root_hash() }
65
66    pub fn gas_used(&self) -> u64 { self.gas_used }
67
68    pub fn txn_info_hash(&self) -> Option<HashValue> { self.txn_info_hash }
69}
70
71/// The output of Processing the vm output of a series of transactions to the
72/// parent in-memory state merkle tree and accumulator.
73#[derive(Debug, Clone)]
74pub struct ProcessedVMOutput {
75    /// The entire set of data associated with each transaction.
76    transaction_data: Vec<TransactionData>,
77
78    /// The in-memory Merkle Accumulator after appending all the transactions
79    /// in this set.
80    executed_trees: ExecutedTrees,
81
82    /// If set, this is the new epoch info that should be changed to if this
83    /// block is committed.
84    epoch_state: Option<EpochState>,
85
86    /// If set, this is the selected pivot block in current transaction.
87    pivot_block: Option<PivotBlockDecision>,
88}
89
90impl ProcessedVMOutput {
91    pub fn new(
92        transaction_data: Vec<TransactionData>, executed_trees: ExecutedTrees,
93        epoch_state: Option<EpochState>,
94        pivot_block: Option<PivotBlockDecision>,
95    ) -> Self {
96        ProcessedVMOutput {
97            transaction_data,
98            executed_trees,
99            epoch_state,
100            pivot_block,
101        }
102    }
103
104    pub fn transaction_data(&self) -> &[TransactionData] {
105        &self.transaction_data
106    }
107
108    pub fn executed_trees(&self) -> &ExecutedTrees { &self.executed_trees }
109
110    pub fn accu_root(&self) -> HashValue { self.executed_trees().state_id() }
111
112    pub fn version(&self) -> Option<Version> { self.executed_trees().version() }
113
114    pub fn epoch_state(&self) -> &Option<EpochState> { &self.epoch_state }
115
116    pub fn pivot_block(&self) -> &Option<PivotBlockDecision> {
117        &self.pivot_block
118    }
119
120    pub fn has_reconfiguration(&self) -> bool { self.epoch_state.is_some() }
121
122    pub fn compute_result(
123        &self, parent_frozen_subtree_roots: Vec<HashValue>,
124        parent_num_leaves: u64,
125    ) -> StateComputeResult {
126        let txn_accu = self.executed_trees().txn_accumulator();
127        // Now that we have the root hash and execution status we can send the
128        // response to consensus.
129        // TODO: The VM will support a special transaction to set the validators
130        // for the next epoch that is part of a block execution.
131        StateComputeResult::new(
132            if parent_num_leaves == 0 {
133                self.accu_root()
134            } else {
135                Default::default()
136            },
137            txn_accu.frozen_subtree_roots().clone(),
138            txn_accu.num_leaves(),
139            parent_frozen_subtree_roots,
140            parent_num_leaves,
141            self.epoch_state.clone(),
142            self.transaction_data()
143                .iter()
144                .map(|txn_data| txn_data.status())
145                .cloned()
146                .collect(),
147            self.transaction_data()
148                .iter()
149                .filter_map(|x| x.txn_info_hash())
150                .collect(),
151            self.pivot_block().clone(),
152        )
153    }
154
155    pub fn replace_pos_state(&mut self, new_pos_state: PosState) {
156        self.executed_trees.pos_state = new_pos_state;
157    }
158
159    pub fn set_pos_state_skipped(&mut self) {
160        self.executed_trees.set_pos_state_skipped(true);
161    }
162}