casper_node/components/
contract_runtime.rs

1//! Contract Runtime component.
2
3mod config;
4mod error;
5mod event;
6mod exec_queue;
7mod metrics;
8mod operations;
9mod rewards;
10#[cfg(test)]
11mod tests;
12mod types;
13mod utils;
14
15use std::{
16    cmp::Ordering,
17    collections::BTreeMap,
18    convert::TryInto,
19    fmt::{self, Debug, Formatter},
20    path::Path,
21    sync::{Arc, Mutex},
22    time::Instant,
23};
24
25use casper_executor_wasm::{ExecutorConfigBuilder, ExecutorKind, ExecutorV2};
26use datasize::DataSize;
27use lmdb::DatabaseFlags;
28use prometheus::Registry;
29use tracing::{debug, error, info, trace};
30
31use casper_execution_engine::engine_state::{EngineConfigBuilder, ExecutionEngineV1};
32use casper_storage::{
33    data_access_layer::{
34        AddressableEntityRequest, AddressableEntityResult, BlockStore, DataAccessLayer,
35        EntryPointExistsRequest, ExecutionResultsChecksumRequest, FlushRequest, FlushResult,
36        GenesisRequest, GenesisResult, TrieRequest,
37    },
38    global_state::{
39        state::{lmdb::LmdbGlobalState, CommitProvider, StateProvider},
40        transaction_source::lmdb::LmdbEnvironment,
41        trie_store::lmdb::LmdbTrieStore,
42    },
43    system::genesis::GenesisError,
44    tracking_copy::TrackingCopyError,
45};
46use casper_types::{
47    account::AccountHash, ActivationPoint, Chainspec, ChainspecRawBytes, ChainspecRegistry,
48    EntityAddr, EraId, Key, PublicKey,
49};
50
51use crate::{
52    components::{fetcher::FetchResponse, Component, ComponentState},
53    contract_runtime::{types::EraPrice, utils::handle_protocol_upgrade},
54    effect::{
55        announcements::{
56            ContractRuntimeAnnouncement, FatalAnnouncement, MetaBlockAnnouncement,
57            UnexecutedBlockAnnouncement,
58        },
59        incoming::{TrieDemand, TrieRequest as TrieRequestMessage, TrieRequestIncoming},
60        requests::{ContractRuntimeRequest, NetworkRequest, StorageRequest},
61        EffectBuilder, EffectExt, Effects,
62    },
63    fatal,
64    protocol::Message,
65    types::{
66        BlockPayload, ExecutableBlock, FinalizedBlock, InternalEraReport, MetaBlockState,
67        TrieOrChunk, TrieOrChunkId,
68    },
69    NodeRng,
70};
71pub(crate) use config::Config;
72pub(crate) use error::{BlockExecutionError, ConfigError, ContractRuntimeError, StateResultError};
73pub(crate) use event::Event;
74use exec_queue::{ExecQueue, QueueItem};
75use metrics::Metrics;
76#[cfg(test)]
77pub(crate) use operations::compute_execution_results_checksum;
78pub use operations::execute_finalized_block;
79use operations::speculatively_execute;
80pub(crate) use types::{
81    BlockAndExecutionArtifacts, ExecutionArtifact, ExecutionPreState, SpeculativeExecutionResult,
82    StepOutcome,
83};
84use utils::{exec_or_requeue, run_intensive_task};
85
86const COMPONENT_NAME: &str = "contract_runtime";
87
88pub(crate) const APPROVALS_CHECKSUM_NAME: &str = "approvals_checksum";
89pub(crate) const EXECUTION_RESULTS_CHECKSUM_NAME: &str = "execution_results_checksum";
90
91/// The contract runtime components.
92#[derive(DataSize)]
93pub(crate) struct ContractRuntime {
94    state: ComponentState,
95    execution_pre_state: Arc<Mutex<ExecutionPreState>>,
96    #[data_size(skip)]
97    execution_engine_v1: Arc<ExecutionEngineV1>,
98    #[data_size(skip)]
99    execution_engine_v2: ExecutorV2,
100    metrics: Arc<Metrics>,
101    /// Finalized blocks waiting for their pre-state hash to start executing.
102    exec_queue: ExecQueue,
103    /// The chainspec.
104    chainspec: Arc<Chainspec>,
105    #[data_size(skip)]
106    data_access_layer: Arc<DataAccessLayer<LmdbGlobalState>>,
107    current_gas_price: EraPrice,
108}
109
110impl Debug for ContractRuntime {
111    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
112        f.debug_struct("ContractRuntime").finish()
113    }
114}
115
116impl ContractRuntime {
117    pub(crate) fn new(
118        storage_dir: &Path,
119        contract_runtime_config: &Config,
120        chainspec: Arc<Chainspec>,
121        registry: &Registry,
122    ) -> Result<Self, ConfigError> {
123        let execution_pre_state = Arc::new(Mutex::new(ExecutionPreState::default()));
124
125        let current_gas_price = match chainspec.protocol_config.activation_point {
126            ActivationPoint::EraId(era_id) => {
127                EraPrice::new(era_id, chainspec.vacancy_config.min_gas_price)
128            }
129            ActivationPoint::Genesis(_) => {
130                EraPrice::new(EraId::new(0), chainspec.vacancy_config.min_gas_price)
131            }
132        };
133        let enable_addressable_entity = chainspec.core_config.enable_addressable_entity;
134        let engine_config = EngineConfigBuilder::new()
135            .with_max_query_depth(contract_runtime_config.max_query_depth_or_default())
136            .with_max_associated_keys(chainspec.core_config.max_associated_keys)
137            .with_max_runtime_call_stack_height(chainspec.core_config.max_runtime_call_stack_height)
138            .with_minimum_delegation_amount(chainspec.core_config.minimum_delegation_amount)
139            .with_maximum_delegation_amount(chainspec.core_config.maximum_delegation_amount)
140            .with_strict_argument_checking(chainspec.core_config.strict_argument_checking)
141            .with_vesting_schedule_period_millis(
142                chainspec.core_config.vesting_schedule_period.millis(),
143            )
144            .with_max_delegators_per_validator(chainspec.core_config.max_delegators_per_validator)
145            .with_wasm_config(chainspec.wasm_config)
146            .with_system_config(chainspec.system_costs_config)
147            .with_administrative_accounts(chainspec.core_config.administrators.clone())
148            .with_allow_auction_bids(chainspec.core_config.allow_auction_bids)
149            .with_allow_unrestricted_transfers(chainspec.core_config.allow_unrestricted_transfers)
150            .with_refund_handling(chainspec.core_config.refund_handling)
151            .with_fee_handling(chainspec.core_config.fee_handling)
152            .with_enable_entity(enable_addressable_entity)
153            .with_trap_on_ambiguous_entity_version(
154                chainspec.core_config.trap_on_ambiguous_entity_version,
155            )
156            .with_protocol_version(chainspec.protocol_version())
157            .with_storage_costs(chainspec.storage_costs)
158            .with_minimum_bid_amount(chainspec.core_config.minimum_bid_amount)
159            .build();
160
161        let data_access_layer = Arc::new(
162            Self::new_data_access_layer(
163                storage_dir,
164                contract_runtime_config,
165                enable_addressable_entity,
166            )
167            .map_err(ConfigError::GlobalState)?,
168        );
169
170        let execution_engine_v1 = Arc::new(ExecutionEngineV1::new(engine_config));
171
172        let executor_v2 = {
173            let executor_config = ExecutorConfigBuilder::default()
174                .with_memory_limit(chainspec.wasm_config.v2().max_memory())
175                .with_executor_kind(ExecutorKind::Compiled)
176                .with_wasm_config(*chainspec.wasm_config.v2())
177                .with_storage_costs(chainspec.storage_costs)
178                .with_message_limits(chainspec.wasm_config.messages_limits())
179                .build()
180                .expect("Should build");
181            ExecutorV2::new(executor_config, Arc::clone(&execution_engine_v1))
182        };
183
184        let metrics = Arc::new(Metrics::new(registry)?);
185
186        Ok(ContractRuntime {
187            state: ComponentState::Initialized,
188            execution_pre_state,
189            execution_engine_v1,
190            execution_engine_v2: executor_v2,
191            metrics,
192            exec_queue: Default::default(),
193            chainspec,
194            data_access_layer,
195            current_gas_price,
196        })
197    }
198
199    pub(crate) fn set_initial_state(&mut self, sequential_block_state: ExecutionPreState) {
200        let next_block_height = sequential_block_state.next_block_height();
201        let mut execution_pre_state = self.execution_pre_state.lock().unwrap();
202        *execution_pre_state = sequential_block_state;
203
204        let new_len = self
205            .exec_queue
206            .remove_older_then(execution_pre_state.next_block_height());
207        self.metrics.exec_queue_size.set(new_len);
208        debug!(next_block_height, "ContractRuntime: set initial state");
209    }
210
211    fn new_data_access_layer(
212        storage_dir: &Path,
213        contract_runtime_config: &Config,
214        enable_addressable_entity: bool,
215    ) -> Result<DataAccessLayer<LmdbGlobalState>, casper_storage::global_state::error::Error> {
216        let data_access_layer = {
217            let environment = Arc::new(LmdbEnvironment::new(
218                storage_dir,
219                contract_runtime_config.max_global_state_size_or_default(),
220                contract_runtime_config.max_readers_or_default(),
221                contract_runtime_config.manual_sync_enabled_or_default(),
222            )?);
223
224            let trie_store = Arc::new(LmdbTrieStore::new(
225                &environment,
226                None,
227                DatabaseFlags::empty(),
228            )?);
229
230            let block_store = BlockStore::new();
231
232            let max_query_depth = contract_runtime_config.max_query_depth_or_default();
233            let global_state = LmdbGlobalState::empty(
234                environment,
235                trie_store,
236                max_query_depth,
237                enable_addressable_entity,
238            )?;
239
240            DataAccessLayer {
241                state: global_state,
242                block_store,
243                max_query_depth,
244                enable_addressable_entity,
245            }
246        };
247        Ok(data_access_layer)
248    }
249
250    /// How many blocks are backed up in the queue
251    pub(crate) fn queue_depth(&self) -> usize {
252        self.exec_queue.len()
253    }
254
255    /// Commits a genesis request.
256    pub(crate) fn commit_genesis(
257        &self,
258        chainspec: &Chainspec,
259        chainspec_raw_bytes: &ChainspecRawBytes,
260    ) -> GenesisResult {
261        debug!("commit_genesis");
262        let start = Instant::now();
263        let protocol_version = chainspec.protocol_config.version;
264        let chainspec_hash = chainspec.hash();
265        let genesis_config = chainspec.into();
266        let account_bytes = match chainspec_raw_bytes.maybe_genesis_accounts_bytes() {
267            Some(bytes) => bytes,
268            None => {
269                error!("failed to provide genesis account bytes in commit genesis");
270                return GenesisResult::Failure(GenesisError::MissingGenesisAccounts);
271            }
272        };
273
274        let chainspec_registry = ChainspecRegistry::new_with_genesis(
275            chainspec_raw_bytes.chainspec_bytes(),
276            account_bytes,
277        );
278
279        let genesis_request = GenesisRequest::new(
280            chainspec_hash,
281            protocol_version,
282            genesis_config,
283            chainspec_registry,
284        );
285
286        let data_access_layer = Arc::clone(&self.data_access_layer);
287        let result = data_access_layer.genesis(genesis_request);
288        self.metrics
289            .commit_genesis
290            .observe(start.elapsed().as_secs_f64());
291        debug!(?result, "upgrade result");
292        if result.is_success() {
293            let flush_req = FlushRequest::new();
294            if let FlushResult::Failure(err) = data_access_layer.flush(flush_req) {
295                return GenesisResult::Failure(GenesisError::TrackingCopy(
296                    TrackingCopyError::Storage(err),
297                ));
298            }
299        }
300        result
301    }
302
303    /// Handles a contract runtime request.
304    fn handle_contract_runtime_request<REv>(
305        &mut self,
306        effect_builder: EffectBuilder<REv>,
307        _rng: &mut NodeRng,
308        request: ContractRuntimeRequest,
309    ) -> Effects<Event>
310    where
311        REv: From<ContractRuntimeRequest>
312            + From<ContractRuntimeAnnouncement>
313            + From<StorageRequest>
314            + From<MetaBlockAnnouncement>
315            + From<UnexecutedBlockAnnouncement>
316            + From<FatalAnnouncement>
317            + Send,
318    {
319        match request {
320            ContractRuntimeRequest::Query {
321                request: query_request,
322                responder,
323            } => {
324                trace!(?query_request, "query");
325                let metrics = Arc::clone(&self.metrics);
326                let data_access_layer = Arc::clone(&self.data_access_layer);
327                async move {
328                    let start = Instant::now();
329                    let result = data_access_layer.query(query_request);
330                    metrics.run_query.observe(start.elapsed().as_secs_f64());
331                    trace!(?result, "query result");
332                    responder.respond(result).await
333                }
334                .ignore()
335            }
336            ContractRuntimeRequest::QueryByPrefix {
337                request: query_request,
338                responder,
339            } => {
340                trace!(?query_request, "query by prefix");
341                let metrics = Arc::clone(&self.metrics);
342                let data_access_layer = Arc::clone(&self.data_access_layer);
343                async move {
344                    let start = Instant::now();
345
346                    let result = data_access_layer.prefixed_values(query_request);
347                    metrics.run_query.observe(start.elapsed().as_secs_f64());
348                    trace!(?result, "query by prefix result");
349                    responder.respond(result).await
350                }
351                .ignore()
352            }
353            ContractRuntimeRequest::GetBalance {
354                request: balance_request,
355                responder,
356            } => {
357                trace!(?balance_request, "balance");
358                let metrics = Arc::clone(&self.metrics);
359                let data_access_layer = Arc::clone(&self.data_access_layer);
360                async move {
361                    let start = Instant::now();
362                    let result = data_access_layer.balance(balance_request);
363                    metrics.get_balance.observe(start.elapsed().as_secs_f64());
364                    trace!(?result, "balance result");
365                    responder.respond(result).await
366                }
367                .ignore()
368            }
369            ContractRuntimeRequest::GetEraValidators {
370                request: era_validators_request,
371                responder,
372            } => {
373                trace!(?era_validators_request, "get era validators request");
374                let metrics = Arc::clone(&self.metrics);
375                let data_access_layer = Arc::clone(&self.data_access_layer);
376                async move {
377                    let start = Instant::now();
378                    let result = data_access_layer.era_validators(era_validators_request);
379                    metrics
380                        .get_era_validators
381                        .observe(start.elapsed().as_secs_f64());
382                    trace!(?result, "era validators result");
383                    responder.respond(result).await
384                }
385                .ignore()
386            }
387            ContractRuntimeRequest::GetSeigniorageRecipients { request, responder } => {
388                trace!(?request, "get seigniorage recipients request");
389                let metrics = Arc::clone(&self.metrics);
390                let data_access_layer = Arc::clone(&self.data_access_layer);
391                async move {
392                    let start = Instant::now();
393                    let result = data_access_layer.seigniorage_recipients(request);
394                    metrics
395                        .get_seigniorage_recipients
396                        .observe(start.elapsed().as_secs_f64());
397                    trace!(?result, "seigniorage recipients result");
398                    responder.respond(result).await
399                }
400                .ignore()
401            }
402            ContractRuntimeRequest::GetExecutionResultsChecksum {
403                state_root_hash,
404                responder,
405            } => {
406                trace!(?state_root_hash, "get execution results checksum request");
407                let metrics = Arc::clone(&self.metrics);
408                let data_access_layer = Arc::clone(&self.data_access_layer);
409                async move {
410                    let start = Instant::now();
411                    let request = ExecutionResultsChecksumRequest::new(state_root_hash);
412                    let result = data_access_layer.execution_result_checksum(request);
413                    metrics
414                        .execution_results_checksum
415                        .observe(start.elapsed().as_secs_f64());
416                    trace!(?result, "execution result checksum");
417                    responder.respond(result).await
418                }
419                .ignore()
420            }
421            ContractRuntimeRequest::GetAddressableEntity {
422                state_root_hash,
423                entity_addr,
424                responder,
425            } => {
426                trace!(?state_root_hash, "get addressable entity");
427                let metrics = Arc::clone(&self.metrics);
428                let data_access_layer = Arc::clone(&self.data_access_layer);
429                async move {
430                    let start = Instant::now();
431                    let entity_key = match entity_addr {
432                        EntityAddr::SmartContract(_) | EntityAddr::System(_) => Key::AddressableEntity(entity_addr),
433                        EntityAddr::Account(account) => Key::Account(AccountHash::new(account)),
434                    };
435                    let request = AddressableEntityRequest::new(state_root_hash, entity_key);
436                    let result = data_access_layer.addressable_entity(request);
437                    let result = match &result {
438                        AddressableEntityResult::ValueNotFound(msg) => {
439                            if entity_addr.is_contract() {
440                                trace!(%msg, "can not read addressable entity by Key::AddressableEntity or Key::Account, will try by Key::Hash");
441                                let entity_key = Key::Hash(entity_addr.value());
442                                let request = AddressableEntityRequest::new(state_root_hash, entity_key);
443                                data_access_layer.addressable_entity(request)
444                            }
445                            else {
446                                result
447                            }
448                        },
449                        AddressableEntityResult::RootNotFound |
450                        AddressableEntityResult::Success { .. } |
451                        AddressableEntityResult::Failure(_) => result,
452                    };
453
454                    metrics
455                        .addressable_entity
456                        .observe(start.elapsed().as_secs_f64());
457                    trace!(?result, "get addressable entity");
458                    responder.respond(result).await
459                }
460                .ignore()
461            }
462            ContractRuntimeRequest::GetEntryPointExists {
463                state_root_hash,
464                contract_hash,
465                entry_point_name,
466                responder,
467            } => {
468                trace!(?state_root_hash, "get entry point");
469                let metrics = Arc::clone(&self.metrics);
470                let data_access_layer = Arc::clone(&self.data_access_layer);
471                async move {
472                    let start = Instant::now();
473                    let request = EntryPointExistsRequest::new(
474                        state_root_hash,
475                        entry_point_name,
476                        contract_hash,
477                    );
478                    let result = data_access_layer.entry_point_exists(request);
479                    metrics.entry_points.observe(start.elapsed().as_secs_f64());
480                    trace!(?result, "get addressable entity");
481                    responder.respond(result).await
482                }
483                .ignore()
484            }
485            ContractRuntimeRequest::GetTaggedValues {
486                request: tagged_values_request,
487                responder,
488            } => {
489                trace!(?tagged_values_request, "tagged values request");
490                let metrics = Arc::clone(&self.metrics);
491                let data_access_layer = Arc::clone(&self.data_access_layer);
492                async move {
493                    let start = Instant::now();
494                    let result = data_access_layer.tagged_values(tagged_values_request);
495                    metrics
496                        .get_all_values
497                        .observe(start.elapsed().as_secs_f64());
498                    trace!(?result, "get all values result");
499                    responder.respond(result).await
500                }
501                .ignore()
502            }
503            // trie related events
504            ContractRuntimeRequest::GetTrie {
505                request: trie_request,
506                responder,
507            } => {
508                trace!(?trie_request, "trie request");
509                let metrics = Arc::clone(&self.metrics);
510                let data_access_layer = Arc::clone(&self.data_access_layer);
511                async move {
512                    let start = Instant::now();
513                    let result = data_access_layer.trie(trie_request);
514                    metrics.get_trie.observe(start.elapsed().as_secs_f64());
515                    trace!(?result, "trie response");
516                    responder.respond(result).await
517                }
518                .ignore()
519            }
520            ContractRuntimeRequest::PutTrie {
521                request: put_trie_request,
522                responder,
523            } => {
524                trace!(?put_trie_request, "put trie request");
525                let metrics = Arc::clone(&self.metrics);
526                let data_access_layer = Arc::clone(&self.data_access_layer);
527                async move {
528                    let start = Instant::now();
529                    let result = data_access_layer.put_trie(put_trie_request);
530                    let flush_req = FlushRequest::new();
531                    // PERF: consider flushing periodically.
532                    if let FlushResult::Failure(gse) = data_access_layer.flush(flush_req) {
533                        fatal!(effect_builder, "error flushing data environment {:?}", gse).await;
534                    }
535                    metrics.put_trie.observe(start.elapsed().as_secs_f64());
536                    trace!(?result, "put trie response");
537                    responder.respond(result).await
538                }
539                .ignore()
540            }
541            ContractRuntimeRequest::UpdatePreState { new_pre_state } => {
542                let next_block_height = new_pre_state.next_block_height();
543                self.set_initial_state(new_pre_state);
544                let current_price = self.current_gas_price.gas_price();
545                async move {
546                    let block_header = match effect_builder
547                        .get_highest_complete_block_header_from_storage()
548                        .await
549                    {
550                        Some(header)
551                            if header.is_switch_block()
552                                && (header.height() + 1 == next_block_height) =>
553                        {
554                            header
555                        }
556                        Some(_) => {
557                            return fatal!(
558                                effect_builder,
559                                "Latest complete block is not a switch block to update state"
560                            )
561                            .await;
562                        }
563                        None => {
564                            return fatal!(
565                                effect_builder,
566                                "No complete block header found to update post upgrade state"
567                            )
568                            .await;
569                        }
570                    };
571
572                    let payload = BlockPayload::new(
573                        BTreeMap::new(),
574                        vec![],
575                        Default::default(),
576                        false,
577                        current_price,
578                    );
579
580                    let finalized_block = FinalizedBlock::new(
581                        payload,
582                        Some(InternalEraReport::default()),
583                        block_header.timestamp(),
584                        block_header.next_block_era_id(),
585                        next_block_height,
586                        PublicKey::System,
587                    );
588
589                    info!("Enqueuing block for execution post state refresh");
590
591                    effect_builder
592                        .enqueue_block_for_execution(
593                            ExecutableBlock::from_finalized_block_and_transactions(
594                                finalized_block,
595                                vec![],
596                            ),
597                            MetaBlockState::new_not_to_be_gossiped(),
598                        )
599                        .await;
600                }
601                .ignore()
602            }
603            ContractRuntimeRequest::DoProtocolUpgrade {
604                protocol_upgrade_config,
605                next_block_height,
606                parent_hash,
607                parent_seed,
608            } => {
609                let mut effects = Effects::new();
610                let data_access_layer = Arc::clone(&self.data_access_layer);
611                let metrics = Arc::clone(&self.metrics);
612                effects.extend(
613                    handle_protocol_upgrade(
614                        effect_builder,
615                        data_access_layer,
616                        metrics,
617                        protocol_upgrade_config,
618                        next_block_height,
619                        parent_hash,
620                        parent_seed,
621                    )
622                    .ignore(),
623                );
624                effects
625            }
626            ContractRuntimeRequest::EnqueueBlockForExecution {
627                executable_block,
628                key_block_height_for_activation_point,
629                meta_block_state,
630            } => {
631                let mut effects = Effects::new();
632                let mut exec_queue = self.exec_queue.clone();
633                let finalized_block_height = executable_block.height;
634                let era_id = executable_block.era_id;
635                let current_pre_state = self.execution_pre_state.lock().unwrap();
636                let next_block_height = current_pre_state.next_block_height();
637                match finalized_block_height.cmp(&next_block_height) {
638                    // An old block: it won't be executed:
639                    Ordering::Less => {
640                        debug!(
641                            %era_id,
642                            "ContractRuntime: finalized block({}) precedes expected next block({})",
643                            finalized_block_height,
644                            next_block_height,
645                        );
646                        effects.extend(
647                            effect_builder
648                                .announce_unexecuted_block(finalized_block_height)
649                                .ignore(),
650                        );
651                    }
652                    // This is a future block, we store it into exec_queue, to be executed later:
653                    Ordering::Greater => {
654                        debug!(
655                            %era_id,
656                            "ContractRuntime: enqueuing({}) waiting for({})",
657                            finalized_block_height, next_block_height
658                        );
659                        info!(
660                            "ContractRuntime: enqueuing finalized block({}) with {} transactions \
661                            for execution",
662                            finalized_block_height,
663                            executable_block.transactions.len()
664                        );
665                        exec_queue.insert(
666                            finalized_block_height,
667                            QueueItem {
668                                executable_block,
669                                meta_block_state,
670                            },
671                        );
672                    }
673                    // This is the next block to be executed, we do it right away:
674                    Ordering::Equal => {
675                        info!(
676                            "ContractRuntime: execute finalized block({}) with {} transactions",
677                            finalized_block_height,
678                            executable_block.transactions.len()
679                        );
680                        let data_access_layer = Arc::clone(&self.data_access_layer);
681                        let execution_engine_v1 = Arc::clone(&self.execution_engine_v1);
682                        let execution_engine_v2 = self.execution_engine_v2.clone();
683                        let chainspec = Arc::clone(&self.chainspec);
684                        let metrics = Arc::clone(&self.metrics);
685                        let shared_pre_state = Arc::clone(&self.execution_pre_state);
686                        effects.extend(
687                            exec_or_requeue(
688                                data_access_layer,
689                                execution_engine_v1,
690                                execution_engine_v2,
691                                chainspec,
692                                metrics,
693                                exec_queue,
694                                shared_pre_state,
695                                current_pre_state.clone(),
696                                effect_builder,
697                                executable_block,
698                                key_block_height_for_activation_point,
699                                meta_block_state,
700                            )
701                            .ignore(),
702                        )
703                    }
704                }
705                self.metrics
706                    .exec_queue_size
707                    .set(self.exec_queue.len().try_into().unwrap_or(i64::MIN));
708                effects
709            }
710            ContractRuntimeRequest::SpeculativelyExecute {
711                block_header,
712                transaction,
713                responder,
714            } => {
715                let chainspec = Arc::clone(&self.chainspec);
716                let data_access_layer = Arc::clone(&self.data_access_layer);
717                let execution_engine_v1 = Arc::clone(&self.execution_engine_v1);
718                async move {
719                    let result = run_intensive_task(move || {
720                        speculatively_execute(
721                            data_access_layer.as_ref(),
722                            chainspec.as_ref(),
723                            execution_engine_v1.as_ref(),
724                            *block_header,
725                            *transaction,
726                        )
727                    })
728                    .await;
729                    responder.respond(result).await
730                }
731                .ignore()
732            }
733            ContractRuntimeRequest::GetEraGasPrice { era_id, responder } => responder
734                .respond(self.current_gas_price.maybe_gas_price_for_era_id(era_id))
735                .ignore(),
736            ContractRuntimeRequest::UpdateRuntimePrice(era_id, new_gas_price) => {
737                self.current_gas_price = EraPrice::new(era_id, new_gas_price);
738                Effects::new()
739            }
740        }
741    }
742
743    /// Handles an incoming request to get a trie.
744    fn handle_trie_request<REv>(
745        &self,
746        effect_builder: EffectBuilder<REv>,
747        TrieRequestIncoming { sender, message }: TrieRequestIncoming,
748    ) -> Effects<Event>
749    where
750        REv: From<NetworkRequest<Message>> + Send,
751    {
752        let TrieRequestMessage(ref serialized_id) = *message;
753        let fetch_response = match self.fetch_trie_local(serialized_id) {
754            Ok(fetch_response) => fetch_response,
755            Err(error) => {
756                debug!("failed to get trie: {}", error);
757                return Effects::new();
758            }
759        };
760
761        match Message::new_get_response(&fetch_response) {
762            Ok(message) => effect_builder.send_message(sender, message).ignore(),
763            Err(error) => {
764                error!("failed to create get-response: {}", error);
765                Effects::new()
766            }
767        }
768    }
769
770    /// Handles an incoming demand for a trie.
771    fn handle_trie_demand(
772        &self,
773        TrieDemand {
774            request_msg,
775            auto_closing_responder,
776            ..
777        }: TrieDemand,
778    ) -> Effects<Event> {
779        let TrieRequestMessage(ref serialized_id) = *request_msg;
780        let fetch_response = match self.fetch_trie_local(serialized_id) {
781            Ok(fetch_response) => fetch_response,
782            Err(error) => {
783                // Something is wrong in our trie store, but be courteous and still send a reply.
784                debug!("failed to get trie: {}", error);
785                return auto_closing_responder.respond_none().ignore();
786            }
787        };
788
789        match Message::new_get_response(&fetch_response) {
790            Ok(message) => auto_closing_responder.respond(message).ignore(),
791            Err(error) => {
792                // This should never happen, but if it does, we let the peer know we cannot help.
793                error!("failed to create get-response: {}", error);
794                auto_closing_responder.respond_none().ignore()
795            }
796        }
797    }
798
799    /// Reads the trie (or chunk of a trie) under the given key and index.
800    fn fetch_trie_local(
801        &self,
802        serialized_id: &[u8],
803    ) -> Result<FetchResponse<TrieOrChunk, TrieOrChunkId>, ContractRuntimeError> {
804        trace!(?serialized_id, "get_trie");
805        let trie_or_chunk_id: TrieOrChunkId = bincode::deserialize(serialized_id)?;
806        let data_access_layer = Arc::clone(&self.data_access_layer);
807        let maybe_trie = {
808            let start = Instant::now();
809            let TrieOrChunkId(chunk_index, trie_key) = trie_or_chunk_id;
810            let req = TrieRequest::new(trie_key, Some(chunk_index));
811            let maybe_raw = data_access_layer
812                .trie(req)
813                .into_raw()
814                .map_err(ContractRuntimeError::FailedToRetrieveTrieById)?;
815            let ret = match maybe_raw {
816                Some(raw) => Some(TrieOrChunk::new(raw.into(), chunk_index)?),
817                None => None,
818            };
819            self.metrics.get_trie.observe(start.elapsed().as_secs_f64());
820            ret
821        };
822        Ok(FetchResponse::from_opt(trie_or_chunk_id, maybe_trie))
823    }
824
825    /// Returns data_access_layer, for testing only.
826    #[cfg(test)]
827    pub(crate) fn data_access_layer(&self) -> Arc<DataAccessLayer<LmdbGlobalState>> {
828        Arc::clone(&self.data_access_layer)
829    }
830
831    #[cfg(test)]
832    pub(crate) fn current_era_price(&self) -> EraPrice {
833        self.current_gas_price
834    }
835}
836
837impl<REv> Component<REv> for ContractRuntime
838where
839    REv: From<ContractRuntimeRequest>
840        + From<ContractRuntimeAnnouncement>
841        + From<NetworkRequest<Message>>
842        + From<StorageRequest>
843        + From<MetaBlockAnnouncement>
844        + From<UnexecutedBlockAnnouncement>
845        + From<FatalAnnouncement>
846        + Send,
847{
848    type Event = Event;
849
850    fn name(&self) -> &str {
851        COMPONENT_NAME
852    }
853
854    fn handle_event(
855        &mut self,
856        effect_builder: EffectBuilder<REv>,
857        rng: &mut NodeRng,
858        event: Event,
859    ) -> Effects<Self::Event> {
860        match event {
861            Event::ContractRuntimeRequest(request) => {
862                self.handle_contract_runtime_request(effect_builder, rng, request)
863            }
864            Event::TrieRequestIncoming(request) => {
865                self.handle_trie_request(effect_builder, request)
866            }
867            Event::TrieDemand(demand) => self.handle_trie_demand(demand),
868        }
869    }
870}