casper_execution_engine/engine_state/
mod.rs

1//!  This module contains all the execution related code.
2pub mod engine_config;
3mod error;
4pub(crate) mod execution_kind;
5mod wasm_v1;
6
7use std::{cell::RefCell, collections::BTreeSet, rc::Rc};
8
9use casper_types::{
10    account::AccountHash, Gas, InitiatorAddr, Key, Phase, RuntimeArgs, StoredValue, TransactionHash,
11};
12
13use casper_storage::{
14    global_state::{
15        error::Error as GlobalStateError,
16        state::{StateProvider, StateReader},
17    },
18    tracking_copy::{TrackingCopyEntityExt, TrackingCopyError},
19    TrackingCopy,
20};
21
22use crate::{execution::Executor, runtime::RuntimeStack};
23pub use engine_config::{
24    EngineConfig, EngineConfigBuilder, DEFAULT_MAX_QUERY_DEPTH,
25    DEFAULT_MAX_RUNTIME_CALL_STACK_HEIGHT,
26};
27pub use error::Error;
28use execution_kind::ExecutionKind;
29pub use wasm_v1::{
30    BlockInfo, ExecutableItem, InvalidRequest, SessionDataDeploy, SessionDataV1, SessionInputData,
31    WasmV1Request, WasmV1Result,
32};
33
34/// Gas/motes conversion rate of wasmless transfer cost is always 1 regardless of what user wants to
35/// pay.
36pub const WASMLESS_TRANSFER_FIXED_GAS_PRICE: u8 = 1;
37
38/// The public api of the v1 execution engine, as of protocol version 2.0.0
39#[derive(Debug, Clone, Default)]
40pub struct ExecutionEngineV1 {
41    config: EngineConfig,
42}
43
44impl ExecutionEngineV1 {
45    /// Creates new execution engine.
46    pub fn new(config: EngineConfig) -> ExecutionEngineV1 {
47        ExecutionEngineV1 { config }
48    }
49
50    /// Returns engine config.
51    pub fn config(&self) -> &EngineConfig {
52        &self.config
53    }
54
55    /// Executes wasm, and that's all. Does not commit or handle payment or anything else.
56    pub fn execute(
57        &self,
58        state_provider: &impl StateProvider,
59        wasm_v1_request: WasmV1Request,
60    ) -> WasmV1Result {
61        let WasmV1Request {
62            block_info,
63            transaction_hash,
64            gas_limit,
65            initiator_addr,
66            executable_item,
67            entry_point,
68            args,
69            authorization_keys,
70            phase,
71        } = wasm_v1_request;
72        // NOTE to core engineers: it is intended for the EE to ONLY execute wasm targeting the
73        // casper v1 virtual machine. it should not handle native behavior, database / global state
74        // interaction, payment processing, or anything other than its single function.
75        // A good deal of effort has been put into removing all such behaviors; please do not
76        // come along and start adding it back.
77
78        let account_hash = initiator_addr.account_hash();
79        let protocol_version = self.config.protocol_version();
80        let state_hash = block_info.state_hash;
81        let tc = match state_provider.tracking_copy(state_hash) {
82            Ok(Some(tracking_copy)) => Rc::new(RefCell::new(tracking_copy)),
83            Ok(None) => return WasmV1Result::root_not_found(gas_limit, state_hash),
84            Err(gse) => {
85                return WasmV1Result::precondition_failure(
86                    gas_limit,
87                    Error::TrackingCopy(TrackingCopyError::Storage(gse)),
88                )
89            }
90        };
91        let (runtime_footprint, entity_addr) = {
92            match tc.borrow_mut().authorized_runtime_footprint_by_account(
93                protocol_version,
94                account_hash,
95                &authorization_keys,
96                &self.config().administrative_accounts,
97            ) {
98                Ok((runtime_footprint, entity_hash)) => (runtime_footprint, entity_hash),
99                Err(tce) => {
100                    return WasmV1Result::precondition_failure(gas_limit, Error::TrackingCopy(tce))
101                }
102            }
103        };
104        let mut named_keys = runtime_footprint.named_keys().clone();
105        let execution_kind = match ExecutionKind::new(&named_keys, &executable_item, entry_point) {
106            Ok(execution_kind) => execution_kind,
107            Err(ese) => return WasmV1Result::precondition_failure(gas_limit, ese),
108        };
109        let access_rights = runtime_footprint.extract_access_rights(entity_addr.value());
110        Executor::new(self.config().clone()).exec(
111            execution_kind,
112            args,
113            entity_addr,
114            Rc::new(RefCell::new(runtime_footprint)),
115            &mut named_keys,
116            access_rights,
117            authorization_keys,
118            account_hash,
119            block_info,
120            transaction_hash,
121            gas_limit,
122            Rc::clone(&tc),
123            phase,
124            RuntimeStack::from_account_hash(
125                account_hash,
126                self.config.max_runtime_call_stack_height() as usize,
127            ),
128        )
129    }
130
131    /// Executes wasm, and that's all. Does not commit or handle payment or anything else.
132    #[allow(clippy::too_many_arguments)]
133    pub fn execute_with_tracking_copy<R>(
134        &self,
135        tracking_copy: TrackingCopy<R>,
136        block_info: BlockInfo,
137        transaction_hash: TransactionHash,
138        gas_limit: Gas,
139        initiator_addr: InitiatorAddr,
140        executable_item: ExecutableItem,
141        entry_point: String,
142        args: RuntimeArgs,
143        authorization_keys: BTreeSet<AccountHash>,
144        phase: Phase,
145    ) -> WasmV1Result
146    where
147        R: StateReader<Key, StoredValue, Error = GlobalStateError>,
148    {
149        // NOTE to core engineers: it is intended for the EE to ONLY execute wasm targeting the
150        // casper v1 virtual machine. it should not handle native behavior, database / global state
151        // interaction, payment processing, or anything other than its single function.
152        // A good deal of effort has been put into removing all such behaviors; please do not
153        // come along and start adding it back.
154
155        let account_hash = initiator_addr.account_hash();
156        let protocol_version = self.config.protocol_version();
157        let tc = Rc::new(RefCell::new(tracking_copy));
158        let (runtime_footprint, entity_addr) = {
159            match tc.borrow_mut().authorized_runtime_footprint_by_account(
160                protocol_version,
161                account_hash,
162                &authorization_keys,
163                &self.config().administrative_accounts,
164            ) {
165                Ok((addressable_entity, entity_hash)) => (addressable_entity, entity_hash),
166                Err(tce) => {
167                    return WasmV1Result::precondition_failure(gas_limit, Error::TrackingCopy(tce))
168                }
169            }
170        };
171        let mut named_keys = runtime_footprint.named_keys().clone();
172        let execution_kind = match ExecutionKind::new(&named_keys, &executable_item, entry_point) {
173            Ok(execution_kind) => execution_kind,
174            Err(ese) => return WasmV1Result::precondition_failure(gas_limit, ese),
175        };
176        let access_rights = runtime_footprint.extract_access_rights(entity_addr.value());
177        Executor::new(self.config().clone()).exec(
178            execution_kind,
179            args,
180            entity_addr,
181            Rc::new(RefCell::new(runtime_footprint)),
182            &mut named_keys,
183            access_rights,
184            authorization_keys,
185            account_hash,
186            block_info,
187            transaction_hash,
188            gas_limit,
189            Rc::clone(&tc),
190            phase,
191            RuntimeStack::from_account_hash(
192                account_hash,
193                self.config.max_runtime_call_stack_height() as usize,
194            ),
195        )
196    }
197}