cfx_executor/executive/
executed.rs

1// Copyright 2019 Conflux Foundation. All rights reserved.
2// Conflux is free software and distributed under GNU General Public License.
3// See http://www.gnu.org/licenses/
4
5use crate::{executive_observer::ExecutiveObserver, substate::Substate};
6use cfx_bytes::Bytes;
7use cfx_types::{AddressWithSpace, U256};
8use cfx_vm_types::Spec;
9use primitives::{
10    receipt::{SortedStorageChanges, StorageChange},
11    LogEntry, TransactionWithSignature,
12};
13use typemap::ShareDebugMap;
14
15use super::{
16    fresh_executive::CostInfo,
17    pre_checked_executive::{ExecutiveReturn, RefundInfo},
18};
19
20#[derive(Debug)]
21pub struct Executed {
22    /// Transaction base gas: 21000 (for tx) or 53000 (for contract creation) +
23    /// calldata gas
24    pub base_gas: u64,
25
26    /// Gas used during execution of transaction.
27    pub gas_used: U256,
28
29    /// Fee that need to be paid by execution of this transaction.
30    pub fee: U256,
31
32    /// Fee burnt by CIP-1559
33    pub burnt_fee: Option<U256>,
34
35    /// Gas charged during execution of transaction.
36    pub gas_charged: U256,
37
38    /// If the gas fee is born by designated sponsor.
39    pub gas_sponsor_paid: bool,
40
41    /// Vector of logs generated by transaction.
42    pub logs: Vec<LogEntry>,
43
44    /// If the storage cost is born by designated sponsor.
45    pub storage_sponsor_paid: bool,
46
47    /// Any accounts that occupy some storage.
48    pub storage_collateralized: Vec<StorageChange>,
49
50    /// Any accounts that release some storage.
51    pub storage_released: Vec<StorageChange>,
52
53    /// Addresses of contracts created during execution of transaction.
54    /// Ordered from earliest creation.
55    ///
56    /// eg. sender creates contract A and A in constructor creates contract B
57    ///
58    /// B creation ends first, and it will be the first element of the vector.
59    ///
60    /// Note: if the contract init code return with empty output, the contract
61    /// address is still included here, even if it is not considered as a
62    /// contract. This is a strange behaviour from Parity's code and not become
63    /// a part of the protocol.
64    pub contracts_created: Vec<AddressWithSpace>,
65
66    /// Transaction output.
67    pub output: Bytes,
68
69    /// Extension output of executed
70    pub ext_result: ExecutedExt,
71}
72
73pub type ExecutedExt = ShareDebugMap;
74
75impl Executed {
76    pub(super) fn not_enough_balance_fee_charged(
77        tx: &TransactionWithSignature, actual_gas_cost: &U256, cost: CostInfo,
78        ext_result: ExecutedExt, spec: &Spec,
79    ) -> Self {
80        let gas_charged = if cost.gas_price == U256::zero() {
81            U256::zero()
82        } else {
83            actual_gas_cost / cost.gas_price
84        };
85        let mut gas_sponsor_paid = cost.gas_sponsored;
86        let mut storage_sponsor_paid = cost.storage_sponsored;
87        if !spec.cip78b {
88            gas_sponsor_paid = false;
89            storage_sponsor_paid = false;
90        }
91        if spec.cip145_fix {
92            gas_sponsor_paid = false;
93        }
94
95        let burnt_fee = spec.cip1559.then(|| {
96            let target_burnt = tx.gas().saturating_mul(cost.burnt_gas_price);
97            U256::min(*actual_gas_cost, target_burnt)
98        });
99
100        Self {
101            gas_used: *tx.gas(),
102            gas_charged,
103            fee: *actual_gas_cost,
104            burnt_fee,
105            gas_sponsor_paid,
106            logs: vec![],
107            contracts_created: vec![],
108            storage_sponsor_paid,
109            storage_collateralized: Vec::new(),
110            storage_released: Vec::new(),
111            output: Default::default(),
112            base_gas: cost.base_gas,
113            ext_result,
114        }
115    }
116
117    pub(super) fn execution_error_fully_charged(
118        tx: &TransactionWithSignature, cost: CostInfo, ext_result: ExecutedExt,
119        spec: &Spec,
120    ) -> Self {
121        let mut storage_sponsor_paid = cost.storage_sponsored;
122        let mut gas_sponsor_paid = cost.gas_sponsored;
123
124        if !spec.cip78b {
125            gas_sponsor_paid = false;
126            storage_sponsor_paid = false;
127        }
128        if spec.cip145 && !spec.cip145_fix {
129            gas_sponsor_paid = false;
130        }
131
132        let fee = tx.gas().saturating_mul(cost.gas_price);
133
134        let burnt_fee = spec
135            .cip1559
136            .then(|| tx.gas().saturating_mul(cost.burnt_gas_price));
137
138        Self {
139            gas_used: *tx.gas(),
140            gas_charged: *tx.gas(),
141            fee,
142            burnt_fee,
143            gas_sponsor_paid,
144            logs: vec![],
145            contracts_created: vec![],
146            storage_sponsor_paid,
147            storage_collateralized: Vec::new(),
148            storage_released: Vec::new(),
149            output: Default::default(),
150            base_gas: cost.base_gas,
151            ext_result,
152        }
153    }
154
155    pub(super) fn from_executive_return(
156        r: &ExecutiveReturn, refund_info: RefundInfo, cost: CostInfo,
157        substate: Substate, ext_result: ExecutedExt, spec: &Spec,
158    ) -> Self {
159        let output = r.return_data.to_vec();
160
161        let SortedStorageChanges {
162            storage_collateralized,
163            storage_released,
164        } = if r.apply_state {
165            substate.compute_storage_changes()
166        } else {
167            Default::default()
168        };
169
170        let RefundInfo {
171            gas_used,
172            gas_charged,
173            fees_value: fee,
174            burnt_fees_value: burnt_fee,
175            ..
176        } = refund_info;
177        let mut storage_sponsor_paid = if spec.cip78a {
178            cost.storage_sponsored
179        } else {
180            cost.storage_sponsor_eligible
181        };
182
183        let mut gas_sponsor_paid = cost.gas_sponsored;
184        if !r.apply_state && !spec.cip78a {
185            gas_sponsor_paid = false;
186            storage_sponsor_paid = false;
187        }
188
189        Executed {
190            gas_used,
191            gas_charged,
192            fee,
193            burnt_fee,
194            gas_sponsor_paid,
195            logs: substate.logs.to_vec(),
196            contracts_created: substate.contracts_created().to_vec(),
197            storage_sponsor_paid,
198            storage_collateralized,
199            storage_released,
200            output,
201            base_gas: cost.base_gas,
202            ext_result,
203        }
204    }
205}
206
207pub fn make_ext_result<O: ExecutiveObserver>(observer: O) -> ShareDebugMap {
208    let mut ext_result = ShareDebugMap::custom();
209    observer.drain_trace(&mut ext_result);
210    ext_result
211}