use crate::{executive_observer::ExecutiveObserver, substate::Substate};
use cfx_bytes::Bytes;
use cfx_types::{AddressWithSpace, U256};
use cfx_vm_types::Spec;
use primitives::{
receipt::{SortedStorageChanges, StorageChange},
LogEntry, TransactionWithSignature,
};
use typemap::ShareDebugMap;
use super::{
fresh_executive::CostInfo,
pre_checked_executive::{ExecutiveReturn, RefundInfo},
};
#[derive(Debug)]
pub struct Executed {
pub base_gas: u64,
pub gas_used: U256,
pub fee: U256,
pub burnt_fee: Option<U256>,
pub gas_charged: U256,
pub gas_sponsor_paid: bool,
pub logs: Vec<LogEntry>,
pub storage_sponsor_paid: bool,
pub storage_collateralized: Vec<StorageChange>,
pub storage_released: Vec<StorageChange>,
pub contracts_created: Vec<AddressWithSpace>,
pub output: Bytes,
pub ext_result: ExecutedExt,
}
pub type ExecutedExt = ShareDebugMap;
impl Executed {
pub(super) fn not_enough_balance_fee_charged(
tx: &TransactionWithSignature, actual_gas_cost: &U256, cost: CostInfo,
ext_result: ExecutedExt, spec: &Spec,
) -> Self {
let gas_charged = if cost.gas_price == U256::zero() {
U256::zero()
} else {
actual_gas_cost / cost.gas_price
};
let mut gas_sponsor_paid = cost.gas_sponsored;
let mut storage_sponsor_paid = cost.storage_sponsored;
if !spec.cip78b {
gas_sponsor_paid = false;
storage_sponsor_paid = false;
}
let burnt_fee = spec.cip1559.then(|| {
let target_burnt = tx.gas().saturating_mul(cost.burnt_gas_price);
U256::min(*actual_gas_cost, target_burnt)
});
Self {
gas_used: *tx.gas(),
gas_charged,
fee: *actual_gas_cost,
burnt_fee,
gas_sponsor_paid,
logs: vec![],
contracts_created: vec![],
storage_sponsor_paid,
storage_collateralized: Vec::new(),
storage_released: Vec::new(),
output: Default::default(),
base_gas: cost.base_gas,
ext_result,
}
}
pub(super) fn execution_error_fully_charged(
tx: &TransactionWithSignature, cost: CostInfo, ext_result: ExecutedExt,
spec: &Spec,
) -> Self {
let mut storage_sponsor_paid = cost.storage_sponsored;
let mut gas_sponsor_paid = cost.gas_sponsored;
if !spec.cip78b {
gas_sponsor_paid = false;
storage_sponsor_paid = false;
}
if spec.cip145 {
gas_sponsor_paid = false;
}
let fee = tx.gas().saturating_mul(cost.gas_price);
let burnt_fee = spec
.cip1559
.then(|| tx.gas().saturating_mul(cost.burnt_gas_price));
Self {
gas_used: *tx.gas(),
gas_charged: *tx.gas(),
fee,
burnt_fee,
gas_sponsor_paid,
logs: vec![],
contracts_created: vec![],
storage_sponsor_paid,
storage_collateralized: Vec::new(),
storage_released: Vec::new(),
output: Default::default(),
base_gas: cost.base_gas,
ext_result,
}
}
pub(super) fn from_executive_return(
r: &ExecutiveReturn, refund_info: RefundInfo, cost: CostInfo,
substate: Substate, ext_result: ExecutedExt, spec: &Spec,
) -> Self {
let output = r.return_data.to_vec();
let SortedStorageChanges {
storage_collateralized,
storage_released,
} = if r.apply_state {
substate.compute_storage_changes()
} else {
Default::default()
};
let RefundInfo {
gas_used,
gas_charged,
fees_value: fee,
burnt_fees_value: burnt_fee,
..
} = refund_info;
let mut storage_sponsor_paid = if spec.cip78a {
cost.storage_sponsored
} else {
cost.storage_sponsor_eligible
};
let mut gas_sponsor_paid = cost.gas_sponsored;
if !r.apply_state && !spec.cip78b {
gas_sponsor_paid = false;
storage_sponsor_paid = false;
}
Executed {
gas_used,
gas_charged,
fee,
burnt_fee,
gas_sponsor_paid,
logs: substate.logs.to_vec(),
contracts_created: substate.contracts_created.to_vec(),
storage_sponsor_paid,
storage_collateralized,
storage_released,
output,
base_gas: cost.base_gas,
ext_result,
}
}
}
pub fn make_ext_result<O: ExecutiveObserver>(observer: O) -> ShareDebugMap {
let mut ext_result = ShareDebugMap::custom();
observer.drain_trace(&mut ext_result);
ext_result
}