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    account_address::AccountAddress,
14    account_state_blob::AccountStateBlob,
15    block_info::PivotBlockDecision,
16    contract_event::ContractEvent,
17    epoch_state::EpochState,
18    proof::accumulator::InMemoryAccumulator,
19    term_state::PosState,
20    transaction::{TransactionStatus, Version},
21};
22use std::{collections::HashMap, sync::Arc};
23
24/// The entire set of data associated with a transaction. In addition to the
25/// output generated by VM which includes the write set and events, this also
26/// has the in-memory trees.
27#[derive(Clone, Debug)]
28pub struct TransactionData {
29    /// Each entry in this map represents the new blob value of an account
30    /// touched by this transaction. The blob is obtained by deserializing
31    /// the previous blob into a BTreeMap, applying relevant portion of
32    /// write set on the map and serializing the updated map into a
33    /// new blob.
34    account_blobs: HashMap<AccountAddress, AccountStateBlob>,
35
36    /// The list of events emitted during this transaction.
37    events: Vec<ContractEvent>,
38
39    /// The execution status set by the VM.
40    status: TransactionStatus,
41
42    /// Root hash of the state tree.
43    state_root_hash: HashValue,
44
45    /// The in-memory Merkle Accumulator that has all events emitted by this
46    /// transaction.
47    event_tree: Arc<InMemoryAccumulator<EventAccumulatorHasher>>,
48
49    /// The amount of gas used.
50    gas_used: u64,
51
52    /// The transaction info hash if the VM status output was keep, None
53    /// otherwise
54    txn_info_hash: Option<HashValue>,
55}
56
57impl TransactionData {
58    pub fn new(
59        account_blobs: HashMap<AccountAddress, AccountStateBlob>,
60        events: Vec<ContractEvent>, status: TransactionStatus,
61        state_root_hash: HashValue,
62        event_tree: Arc<InMemoryAccumulator<EventAccumulatorHasher>>,
63        gas_used: u64, txn_info_hash: Option<HashValue>,
64    ) -> Self {
65        TransactionData {
66            account_blobs,
67            events,
68            status,
69            state_root_hash,
70            event_tree,
71            gas_used,
72            txn_info_hash,
73        }
74    }
75
76    pub fn account_blobs(&self) -> &HashMap<AccountAddress, AccountStateBlob> {
77        &self.account_blobs
78    }
79
80    pub fn events(&self) -> &[ContractEvent] { &self.events }
81
82    pub fn status(&self) -> &TransactionStatus { &self.status }
83
84    pub fn state_root_hash(&self) -> HashValue { self.state_root_hash }
85
86    pub fn event_root_hash(&self) -> HashValue { self.event_tree.root_hash() }
87
88    pub fn gas_used(&self) -> u64 { self.gas_used }
89
90    pub fn txn_info_hash(&self) -> Option<HashValue> { self.txn_info_hash }
91}
92
93/// The output of Processing the vm output of a series of transactions to the
94/// parent in-memory state merkle tree and accumulator.
95#[derive(Debug, Clone)]
96pub struct ProcessedVMOutput {
97    /// The entire set of data associated with each transaction.
98    transaction_data: Vec<TransactionData>,
99
100    /// The in-memory Merkle Accumulator and state Sparse Merkle Tree after
101    /// appending all the transactions in this set.
102    executed_trees: ExecutedTrees,
103
104    /// If set, this is the new epoch info that should be changed to if this
105    /// block is committed.
106    epoch_state: Option<EpochState>,
107
108    /// If set, this is the selected pivot block in current transaction.
109    pivot_block: Option<PivotBlockDecision>,
110}
111
112impl ProcessedVMOutput {
113    pub fn new(
114        transaction_data: Vec<TransactionData>, executed_trees: ExecutedTrees,
115        epoch_state: Option<EpochState>,
116        pivot_block: Option<PivotBlockDecision>,
117    ) -> Self {
118        ProcessedVMOutput {
119            transaction_data,
120            executed_trees,
121            epoch_state,
122            pivot_block,
123        }
124    }
125
126    pub fn transaction_data(&self) -> &[TransactionData] {
127        &self.transaction_data
128    }
129
130    pub fn executed_trees(&self) -> &ExecutedTrees { &self.executed_trees }
131
132    pub fn accu_root(&self) -> HashValue { self.executed_trees().state_id() }
133
134    pub fn version(&self) -> Option<Version> { self.executed_trees().version() }
135
136    pub fn epoch_state(&self) -> &Option<EpochState> { &self.epoch_state }
137
138    pub fn pivot_block(&self) -> &Option<PivotBlockDecision> {
139        &self.pivot_block
140    }
141
142    pub fn has_reconfiguration(&self) -> bool { self.epoch_state.is_some() }
143
144    pub fn compute_result(
145        &self, parent_frozen_subtree_roots: Vec<HashValue>,
146        parent_num_leaves: u64,
147    ) -> StateComputeResult {
148        let txn_accu = self.executed_trees().txn_accumulator();
149        // Now that we have the root hash and execution status we can send the
150        // response to consensus.
151        // TODO: The VM will support a special transaction to set the validators
152        // for the next epoch that is part of a block execution.
153        StateComputeResult::new(
154            if parent_num_leaves == 0 {
155                self.accu_root()
156            } else {
157                Default::default()
158            },
159            txn_accu.frozen_subtree_roots().clone(),
160            txn_accu.num_leaves(),
161            parent_frozen_subtree_roots,
162            parent_num_leaves,
163            self.epoch_state.clone(),
164            self.transaction_data()
165                .iter()
166                .map(|txn_data| txn_data.status())
167                .cloned()
168                .collect(),
169            self.transaction_data()
170                .iter()
171                .filter_map(|x| x.txn_info_hash())
172                .collect(),
173            self.pivot_block().clone(),
174        )
175    }
176
177    pub fn replace_pos_state(&mut self, new_pos_state: PosState) {
178        self.executed_trees.pos_state = new_pos_state;
179    }
180
181    pub fn set_pos_state_skipped(&mut self) {
182        self.executed_trees.set_pos_state_skipped(true);
183    }
184}