1mod 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#[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 exec_queue: ExecQueue,
103 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 pub(crate) fn queue_depth(&self) -> usize {
252 self.exec_queue.len()
253 }
254
255 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 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 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 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 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 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 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 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 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 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 error!("failed to create get-response: {}", error);
794 auto_closing_responder.respond_none().ignore()
795 }
796 }
797 }
798
799 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 #[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}