1pub mod install;
2pub(crate) mod system;
3
4use std::{
5 collections::{BTreeSet, VecDeque},
6 sync::Arc,
7};
8
9use bytes::Bytes;
10use casper_execution_engine::{
11 engine_state::{BlockInfo, Error as EngineError, ExecutableItem, ExecutionEngineV1},
12 execution::ExecError,
13};
14use casper_executor_wasm_common::{
15 chain_utils,
16 error::{CallError, TrapCode},
17 flags::ReturnFlags,
18};
19use casper_executor_wasm_host::context::Context;
20use casper_executor_wasm_interface::{
21 executor::{
22 ExecuteError, ExecuteRequest, ExecuteRequestBuilder, ExecuteResult,
23 ExecuteWithProviderError, ExecuteWithProviderResult, ExecutionKind, Executor,
24 },
25 ConfigBuilder, GasUsage, VMError, WasmInstance,
26};
27use casper_executor_wasmer_backend::WasmerEngine;
28use casper_storage::{
29 global_state::{
30 error::Error as GlobalStateError,
31 state::{CommitProvider, StateProvider},
32 GlobalStateReader,
33 },
34 TrackingCopy,
35};
36use casper_types::{
37 account::AccountHash,
38 addressable_entity::{ActionThresholds, AssociatedKeys},
39 bytesrepr, AddressableEntity, ByteCode, ByteCodeAddr, ByteCodeHash, ByteCodeKind,
40 ContractRuntimeTag, Digest, EntityAddr, EntityKind, Gas, Groups, InitiatorAddr, Key,
41 MessageLimits, Package, PackageHash, PackageStatus, Phase, ProtocolVersion, StorageCosts,
42 StoredValue, TransactionInvocationTarget, URef, WasmV2Config, U512,
43};
44use install::{InstallContractError, InstallContractRequest, InstallContractResult};
45use parking_lot::RwLock;
46use system::{MintArgs, MintTransferArgs};
47use tracing::{error, warn};
48
49const DEFAULT_WASM_ENTRY_POINT: &str = "call";
50
51const DEFAULT_MINT_TRANSFER_GAS_COST: u64 = 1; #[derive(Copy, Clone, Debug)]
54pub enum ExecutorKind {
55 Compiled,
59}
60
61#[derive(Copy, Clone, Debug)]
62pub struct ExecutorConfig {
63 memory_limit: u32,
64 executor_kind: ExecutorKind,
65 wasm_config: WasmV2Config,
66 storage_costs: StorageCosts,
67 message_limits: MessageLimits,
68}
69
70impl ExecutorConfigBuilder {
71 pub fn new() -> ExecutorConfigBuilder {
72 ExecutorConfigBuilder::default()
73 }
74}
75
76#[derive(Default)]
77pub struct ExecutorConfigBuilder {
78 memory_limit: Option<u32>,
79 executor_kind: Option<ExecutorKind>,
80 wasm_config: Option<WasmV2Config>,
81 storage_costs: Option<StorageCosts>,
82 message_limits: Option<MessageLimits>,
83}
84
85impl ExecutorConfigBuilder {
86 pub fn with_memory_limit(mut self, memory_limit: u32) -> Self {
88 self.memory_limit = Some(memory_limit);
89 self
90 }
91
92 pub fn with_executor_kind(mut self, executor_kind: ExecutorKind) -> Self {
94 self.executor_kind = Some(executor_kind);
95 self
96 }
97
98 pub fn with_wasm_config(mut self, wasm_config: WasmV2Config) -> Self {
100 self.wasm_config = Some(wasm_config);
101 self
102 }
103
104 pub fn with_storage_costs(mut self, storage_costs: StorageCosts) -> Self {
106 self.storage_costs = Some(storage_costs);
107 self
108 }
109
110 pub fn with_message_limits(mut self, message_limits: MessageLimits) -> Self {
112 self.message_limits = Some(message_limits);
113 self
114 }
115
116 pub fn build(self) -> Result<ExecutorConfig, &'static str> {
118 let memory_limit = self.memory_limit.ok_or("Memory limit is not set")?;
119 let executor_kind = self.executor_kind.ok_or("Executor kind is not set")?;
120 let wasm_config = self.wasm_config.ok_or("Wasm config is not set")?;
121 let storage_costs = self.storage_costs.ok_or("Storage costs are not set")?;
122 let message_limits = self.message_limits.ok_or("Message limits are not set")?;
123
124 Ok(ExecutorConfig {
125 memory_limit,
126 executor_kind,
127 wasm_config,
128 storage_costs,
129 message_limits,
130 })
131 }
132}
133
134#[derive(Clone)]
135pub struct ExecutorV2 {
136 config: ExecutorConfig,
137 compiled_wasm_engine: Arc<WasmerEngine>,
138 execution_stack: Arc<RwLock<VecDeque<ExecutionKind>>>,
139 execution_engine_v1: Arc<ExecutionEngineV1>,
140}
141
142impl ExecutorV2 {
143 pub fn install_contract<R>(
144 &self,
145 state_root_hash: Digest,
146 state_provider: &R,
147 install_request: InstallContractRequest,
148 ) -> Result<InstallContractResult, InstallContractError>
149 where
150 R: StateProvider + CommitProvider,
151 <R as StateProvider>::Reader: 'static,
152 {
153 let mut tracking_copy = match state_provider.checkout(state_root_hash) {
154 Ok(Some(tracking_copy)) => {
155 TrackingCopy::new(tracking_copy, 1, state_provider.enable_entity())
156 }
157 Ok(None) => {
158 return Err(InstallContractError::GlobalState(
159 GlobalStateError::RootNotFound,
160 ))
161 }
162 Err(error) => return Err(error.into()),
163 };
164
165 let InstallContractRequest {
166 initiator,
167 gas_limit,
168 wasm_bytes,
169 entry_point,
170 input,
171 transferred_value,
172 address_generator,
173 transaction_hash,
174 chain_name,
175 block_time,
176 seed,
177 state_hash,
178 parent_block_hash,
179 block_height,
180 } = install_request;
181
182 let bytecode_hash = chain_utils::compute_wasm_bytecode_hash(&wasm_bytes);
183
184 let caller_key = Key::Account(initiator);
185 let _source_purse = get_purse_for_entity(&mut tracking_copy, caller_key);
186
187 let smart_contract_addr: [u8; 32] = chain_utils::compute_predictable_address(
189 chain_name.as_bytes(),
190 initiator.value(),
191 bytecode_hash,
192 seed,
193 );
194
195 let mut smart_contract = Package::new(
196 Default::default(),
197 Default::default(),
198 Groups::default(),
199 PackageStatus::Unlocked,
200 );
201
202 let protocol_version = ProtocolVersion::V2_0_0;
203 let protocol_version_major = protocol_version.value().major;
204
205 let next_version = smart_contract.next_entity_version_for(protocol_version_major);
206
207 let entity_version_key = smart_contract.insert_entity_version(
208 protocol_version_major,
209 EntityAddr::SmartContract(smart_contract_addr),
210 );
211 debug_assert_eq!(entity_version_key.entity_version(), next_version);
212
213 let smart_contract_addr = chain_utils::compute_predictable_address(
214 chain_name.as_bytes(),
215 initiator.value(),
216 bytecode_hash,
217 seed,
218 );
219
220 tracking_copy.write(
221 Key::SmartContract(smart_contract_addr),
222 StoredValue::SmartContract(smart_contract),
223 );
224
225 let bytecode = ByteCode::new(ByteCodeKind::V2CasperWasm, wasm_bytes.clone().into());
228 let bytecode_addr = ByteCodeAddr::V2CasperWasm(bytecode_hash);
229
230 tracking_copy.write(
231 Key::ByteCode(bytecode_addr),
232 StoredValue::ByteCode(bytecode),
233 );
234
235 let addressable_entity_key =
237 Key::AddressableEntity(EntityAddr::SmartContract(smart_contract_addr));
238
239 let main_purse: URef = match system::mint_mint(
241 &mut tracking_copy,
242 transaction_hash,
243 Arc::clone(&address_generator),
244 MintArgs {
245 initial_balance: U512::zero(),
246 },
247 ) {
248 Ok(uref) => uref,
249 Err(mint_error) => {
250 error!(?mint_error, "Failed to create a purse");
251 return Err(InstallContractError::SystemContract(
252 CallError::CalleeTrapped(TrapCode::UnreachableCodeReached),
253 ));
254 }
255 };
256
257 let addressable_entity = AddressableEntity::new(
258 PackageHash::new(smart_contract_addr),
259 ByteCodeHash::new(bytecode_hash),
260 ProtocolVersion::V2_0_0,
261 main_purse,
262 AssociatedKeys::default(),
263 ActionThresholds::default(),
264 EntityKind::SmartContract(ContractRuntimeTag::VmCasperV2),
265 );
266
267 tracking_copy.write(
268 addressable_entity_key,
269 StoredValue::AddressableEntity(addressable_entity),
270 );
271
272 let ctor_gas_usage = match entry_point {
273 Some(entry_point_name) => {
274 let input = input.unwrap_or_default();
275 let execute_request = ExecuteRequestBuilder::default()
276 .with_initiator(initiator)
277 .with_caller_key(caller_key)
278 .with_target(ExecutionKind::Stored {
279 address: smart_contract_addr,
280 entry_point: entry_point_name,
281 })
282 .with_gas_limit(gas_limit)
283 .with_input(input)
284 .with_transferred_value(transferred_value)
285 .with_transaction_hash(transaction_hash)
286 .with_shared_address_generator(address_generator)
287 .with_chain_name(chain_name)
288 .with_block_time(block_time)
289 .with_state_hash(state_hash)
290 .with_parent_block_hash(parent_block_hash)
291 .with_block_height(block_height)
292 .build()
293 .expect("should build");
294
295 let forked_tc = tracking_copy.fork2();
296
297 match Self::execute_with_tracking_copy(self, forked_tc, execute_request) {
298 Ok(ExecuteResult {
299 host_error,
300 output,
301 gas_usage,
302 effects,
303 cache,
304 messages,
305 }) => {
306 if let Some(host_error) = host_error {
307 return Err(InstallContractError::Constructor { host_error });
308 }
309
310 tracking_copy.apply_changes(effects, cache, messages);
311
312 if let Some(output) = output {
313 warn!(?output, "unexpected output from constructor");
314 }
315
316 gas_usage
317 }
318 Err(execute_error) => {
319 error!(%execute_error, "unable to execute constructor");
320 return Err(InstallContractError::Execute(execute_error));
321 }
322 }
323 }
324 None => {
325 GasUsage::new(gas_limit, gas_limit)
328 }
329 };
330
331 let effects = tracking_copy.effects();
332
333 match state_provider.commit_effects(state_root_hash, effects.clone()) {
334 Ok(post_state_hash) => Ok(InstallContractResult {
335 smart_contract_addr,
336 gas_usage: ctor_gas_usage,
337 effects,
338 post_state_hash,
339 }),
340 Err(error) => Err(InstallContractError::GlobalState(error)),
341 }
342 }
343
344 fn execute_with_tracking_copy<R: GlobalStateReader + 'static>(
345 &self,
346 mut tracking_copy: TrackingCopy<R>,
347 execute_request: ExecuteRequest,
348 ) -> Result<ExecuteResult, ExecuteError> {
349 let ExecuteRequest {
350 initiator,
351 caller_key,
352 gas_limit,
353 execution_kind,
354 input,
355 transferred_value,
356 transaction_hash,
357 address_generator,
358 chain_name,
359 block_time,
360 state_hash,
361 parent_block_hash,
362 block_height,
363 } = execute_request;
364
365 let source_purse = get_purse_for_entity(&mut tracking_copy, caller_key);
368
369 let (wasm_bytes, export_name) = match &execution_kind {
370 ExecutionKind::SessionBytes(wasm_bytes) => {
371 (wasm_bytes.clone(), DEFAULT_WASM_ENTRY_POINT)
373 }
374 ExecutionKind::Stored {
375 address: smart_contract_addr,
376 entry_point,
377 } => {
378 let smart_contract_key = Key::SmartContract(*smart_contract_addr);
379 let legacy_key = Key::Hash(*smart_contract_addr);
380
381 let mut contract = tracking_copy
382 .read_first(&[&legacy_key, &smart_contract_key])
383 .expect("should read contract");
384
385 if let Some(StoredValue::SmartContract(smart_contract_package)) = &contract {
386 let contract_hash = smart_contract_package
387 .versions()
388 .latest()
389 .expect("should have last entry");
390 let entity_addr = EntityAddr::SmartContract(contract_hash.value());
391 let latest_version_key = Key::AddressableEntity(entity_addr);
392 assert_eq!(&entity_addr.value(), smart_contract_addr);
393 let new_contract = tracking_copy
394 .read(&latest_version_key)
395 .expect("should read latest version");
396 contract = new_contract;
397 };
398
399 match contract {
400 Some(StoredValue::AddressableEntity(addressable_entity)) => {
401 let wasm_key = match addressable_entity.kind() {
402 EntityKind::System(_) => todo!(),
403 EntityKind::Account(_) => todo!(),
404 EntityKind::SmartContract(ContractRuntimeTag::VmCasperV1) => {
405 let block_info = BlockInfo::new(
409 state_hash,
410 block_time,
411 parent_block_hash,
412 block_height,
413 self.execution_engine_v1.config().protocol_version(),
414 );
415
416 let entity_addr = EntityAddr::SmartContract(*smart_contract_addr);
417
418 return self.execute_legacy_wasm_byte_code(
419 initiator,
420 &entity_addr,
421 entry_point.clone(),
422 &input,
423 &mut tracking_copy,
424 block_info,
425 transaction_hash,
426 gas_limit,
427 );
428 }
429 EntityKind::SmartContract(ContractRuntimeTag::VmCasperV2) => {
430 Key::ByteCode(ByteCodeAddr::V2CasperWasm(
431 addressable_entity.byte_code_addr(),
432 ))
433 }
434 };
435
436 let wasm_bytes = tracking_copy
440 .read(&wasm_key)
441 .expect("should read wasm")
442 .expect("should have wasm bytes")
443 .into_byte_code()
444 .expect("should be byte code")
445 .take_bytes();
446
447 if transferred_value != 0 {
448 let args = {
449 let maybe_to = None;
450 let source = source_purse;
451 let target = addressable_entity.main_purse();
452 let amount = transferred_value;
453 let id = None;
454 MintTransferArgs {
455 maybe_to,
456 source,
457 target,
458 amount: amount.into(),
459 id,
460 }
461 };
462
463 match system::mint_transfer(
464 &mut tracking_copy,
465 transaction_hash,
466 Arc::clone(&address_generator),
467 args,
468 ) {
469 Ok(()) => {
470 }
472 Err(error) => {
473 return Ok(ExecuteResult {
474 host_error: Some(error),
475 output: None,
476 gas_usage: GasUsage::new(
477 gas_limit,
478 gas_limit - DEFAULT_MINT_TRANSFER_GAS_COST,
479 ),
480 effects: tracking_copy.effects(),
481 cache: tracking_copy.cache(),
482 messages: tracking_copy.messages(),
483 });
484 }
485 }
486 }
487
488 (Bytes::from(wasm_bytes), entry_point.as_str())
489 }
490 Some(StoredValue::Contract(_legacy_contract)) => {
491 let block_info = BlockInfo::new(
492 state_hash,
493 block_time,
494 parent_block_hash,
495 block_height,
496 self.execution_engine_v1.config().protocol_version(),
497 );
498
499 let entity_addr = EntityAddr::SmartContract(*smart_contract_addr);
500
501 return self.execute_legacy_wasm_byte_code(
502 initiator,
503 &entity_addr,
504 entry_point.clone(),
505 &input,
506 &mut tracking_copy,
507 block_info,
508 transaction_hash,
509 gas_limit,
510 );
511 }
512 Some(stored_value) => {
513 todo!(
514 "Unexpected {stored_value:?} under key {:?}",
515 &execution_kind
516 );
517 }
518 None => {
519 error!(
520 smart_contract_addr = base16::encode_lower(&smart_contract_addr),
521 ?execution_kind,
522 "No contract code found",
523 );
524 return Err(ExecuteError::CodeNotFound(*smart_contract_addr));
525 }
526 }
527 }
528 };
529
530 let vm = Arc::clone(&self.compiled_wasm_engine);
531
532 let mut initial_tracking_copy = tracking_copy.fork2();
533
534 let callee_key = match &execution_kind {
536 ExecutionKind::Stored {
537 address: smart_contract_addr,
538 ..
539 } => Key::SmartContract(*smart_contract_addr),
540 ExecutionKind::SessionBytes(_wasm_bytes) => Key::Account(initiator),
541 };
542
543 let context = Context {
544 initiator,
545 config: self.config.wasm_config,
546 storage_costs: self.config.storage_costs,
547 caller: caller_key,
548 callee: callee_key,
549 transferred_value,
550 tracking_copy,
551 executor: self.clone(),
552 address_generator: Arc::clone(&address_generator),
553 transaction_hash,
554 chain_name,
555 input,
556 block_time,
557 message_limits: self.config.message_limits,
558 };
559
560 let wasm_instance_config = ConfigBuilder::new()
561 .with_gas_limit(gas_limit)
562 .with_memory_limit(self.config.memory_limit)
563 .build();
564
565 let mut instance = vm.instantiate(wasm_bytes, context, wasm_instance_config)?;
566
567 self.push_execution_stack(execution_kind.clone());
568 let (vm_result, gas_usage) = instance.call_export(export_name);
569
570 let top_execution_kind = self
571 .pop_execution_stack()
572 .expect("should have execution kind"); debug_assert_eq!(&top_execution_kind, &execution_kind);
574
575 let context = instance.teardown();
576
577 let Context {
578 tracking_copy: final_tracking_copy,
579 ..
580 } = context;
581
582 match vm_result {
583 Ok(()) => Ok(ExecuteResult {
584 host_error: None,
585 output: None,
586 gas_usage,
587 effects: final_tracking_copy.effects(),
588 cache: final_tracking_copy.cache(),
589 messages: final_tracking_copy.messages(),
590 }),
591 Err(VMError::Return { flags, data }) => {
592 let host_error = if flags.contains(ReturnFlags::REVERT) {
593 Some(CallError::CalleeReverted)
595 } else {
596 initial_tracking_copy.apply_changes(
598 final_tracking_copy.effects(),
599 final_tracking_copy.cache(),
600 final_tracking_copy.messages(),
601 );
602
603 None
604 };
605
606 Ok(ExecuteResult {
607 host_error,
608 output: data,
609 gas_usage,
610 effects: initial_tracking_copy.effects(),
611 cache: initial_tracking_copy.cache(),
612 messages: initial_tracking_copy.messages(),
613 })
614 }
615 Err(VMError::OutOfGas) => Ok(ExecuteResult {
616 host_error: Some(CallError::CalleeGasDepleted),
617 output: None,
618 gas_usage,
619 effects: final_tracking_copy.effects(),
620 cache: final_tracking_copy.cache(),
621 messages: final_tracking_copy.messages(),
622 }),
623 Err(VMError::Trap(trap_code)) => Ok(ExecuteResult {
624 host_error: Some(CallError::CalleeTrapped(trap_code)),
625 output: None,
626 gas_usage,
627 effects: initial_tracking_copy.effects(),
628 cache: initial_tracking_copy.cache(),
629 messages: initial_tracking_copy.messages(),
630 }),
631 Err(VMError::Export(export_error)) => {
632 error!(?export_error, "export error");
633 Ok(ExecuteResult {
634 host_error: Some(CallError::NotCallable),
635 output: None,
636 gas_usage,
637 effects: initial_tracking_copy.effects(),
638 cache: initial_tracking_copy.cache(),
639 messages: initial_tracking_copy.messages(),
640 })
641 }
642 Err(VMError::Execute(execute_error)) => {
643 let effects = initial_tracking_copy.effects();
644 let cache = initial_tracking_copy.cache();
645 let messages = initial_tracking_copy.messages();
646 error!(
647 ?execute_error,
648 ?gas_usage,
649 ?effects,
650 ?cache,
651 ?messages,
652 "host error"
653 );
654 Err(execute_error)
655 }
656 Err(VMError::Internal(internal_error)) => {
657 error!(?internal_error, "internal host error");
658 Err(ExecuteError::InternalHost(internal_error))
659 }
660 }
661 }
662
663 #[allow(clippy::too_many_arguments)]
664 fn execute_legacy_wasm_byte_code<R>(
665 &self,
666 initiator: AccountHash,
667 entity_addr: &EntityAddr,
668 entry_point: String,
669 input: &Bytes,
670 tracking_copy: &mut TrackingCopy<R>,
671 block_info: BlockInfo,
672 transaction_hash: casper_types::TransactionHash,
673 gas_limit: u64,
674 ) -> Result<ExecuteResult, ExecuteError>
675 where
676 R: GlobalStateReader + 'static,
677 {
678 let authorization_keys = BTreeSet::from_iter([initiator]);
679 let initiator_addr = InitiatorAddr::AccountHash(initiator);
680 let executable_item =
681 ExecutableItem::Invocation(TransactionInvocationTarget::ByHash(entity_addr.value()));
682 let entry_point = entry_point.clone();
683 let args = bytesrepr::deserialize_from_slice(input).expect("should deserialize");
684 let phase = Phase::Session;
685
686 let wasm_v1_result = {
687 let forked_tc = tracking_copy.fork2();
688 self.execution_engine_v1.execute_with_tracking_copy(
689 forked_tc,
690 block_info,
691 transaction_hash,
692 Gas::from(gas_limit),
693 initiator_addr,
694 executable_item,
695 entry_point,
696 args,
697 authorization_keys,
698 phase,
699 )
700 };
701
702 let effects = wasm_v1_result.effects();
703 let messages = wasm_v1_result.messages();
704
705 match wasm_v1_result.cache() {
706 Some(cache) => {
707 tracking_copy.apply_changes(effects.clone(), cache.clone(), messages.clone());
708 }
709 None => {
710 debug_assert!(
711 effects.is_empty(),
712 "effects should be empty if there is no cache"
713 );
714 }
715 }
716
717 let gas_consumed = wasm_v1_result
718 .consumed()
719 .value()
720 .try_into()
721 .expect("Should convert consumed gas to u64");
722
723 let mut output = wasm_v1_result
724 .ret()
725 .map(|ret| bytesrepr::serialize(ret).unwrap())
726 .map(Bytes::from);
727
728 let host_error = match wasm_v1_result.error() {
729 Some(EngineError::Exec(ExecError::GasLimit)) => Some(CallError::CalleeGasDepleted),
730 Some(EngineError::Exec(ExecError::Revert(revert_code))) => {
731 assert!(output.is_none(), "output should be None"); let revert_code: u32 = (*revert_code).into();
733 output = Some(revert_code.to_le_bytes().to_vec().into()); Some(CallError::CalleeReverted)
735 }
736 Some(_) => Some(CallError::CalleeTrapped(TrapCode::UnreachableCodeReached)),
737 None => None,
738 };
739
740 let remaining_points = gas_limit.checked_sub(gas_consumed).unwrap();
749
750 let fork2 = tracking_copy.fork2();
751 Ok(ExecuteResult {
752 host_error,
753 output,
754 gas_usage: GasUsage::new(gas_limit, remaining_points),
755 effects: fork2.effects(),
756 cache: fork2.cache(),
757 messages: fork2.messages(),
758 })
759 }
760
761 pub fn execute_with_provider<R>(
762 &self,
763 state_root_hash: Digest,
764 state_provider: &R,
765 execute_request: ExecuteRequest,
766 ) -> Result<ExecuteWithProviderResult, ExecuteWithProviderError>
767 where
768 R: StateProvider + CommitProvider,
769 <R as StateProvider>::Reader: 'static,
770 {
771 let tracking_copy = match state_provider.checkout(state_root_hash) {
772 Ok(Some(tracking_copy)) => tracking_copy,
773 Ok(None) => {
774 return Err(ExecuteWithProviderError::GlobalState(
775 GlobalStateError::RootNotFound,
776 ))
777 }
778 Err(global_state_error) => return Err(global_state_error.into()),
779 };
780
781 let tracking_copy = TrackingCopy::new(tracking_copy, 1, state_provider.enable_entity());
782
783 match self.execute_with_tracking_copy(tracking_copy, execute_request) {
784 Ok(ExecuteResult {
785 host_error,
786 output,
787 gas_usage,
788 effects,
789 cache: _,
790 messages,
791 }) => match state_provider.commit_effects(state_root_hash, effects.clone()) {
792 Ok(post_state_hash) => Ok(ExecuteWithProviderResult::new(
793 host_error,
794 output,
795 gas_usage,
796 effects,
797 post_state_hash,
798 messages,
799 )),
800 Err(error) => Err(error.into()),
801 },
802 Err(error) => Err(ExecuteWithProviderError::Execute(error)),
803 }
804 }
805}
806
807impl ExecutorV2 {
808 pub fn new(config: ExecutorConfig, execution_engine_v1: Arc<ExecutionEngineV1>) -> Self {
810 let wasm_engine = match config.executor_kind {
811 ExecutorKind::Compiled => WasmerEngine::new(),
812 };
813 ExecutorV2 {
814 config,
815 compiled_wasm_engine: Arc::new(wasm_engine),
816 execution_stack: Default::default(),
817 execution_engine_v1,
818 }
819 }
820
821 pub(crate) fn push_execution_stack(&self, execution_kind: ExecutionKind) {
823 let mut execution_stack = self.execution_stack.write();
824 execution_stack.push_back(execution_kind);
825 }
826
827 pub(crate) fn pop_execution_stack(&self) -> Option<ExecutionKind> {
829 let mut execution_stack = self.execution_stack.write();
830 execution_stack.pop_back()
831 }
832}
833
834impl Executor for ExecutorV2 {
835 fn execute<R: GlobalStateReader + 'static>(
843 &self,
844 tracking_copy: TrackingCopy<R>,
845 execute_request: ExecuteRequest,
846 ) -> Result<ExecuteResult, ExecuteError> {
847 self.execute_with_tracking_copy(tracking_copy, execute_request)
848 }
849}
850
851fn get_purse_for_entity<R: GlobalStateReader>(
852 tracking_copy: &mut TrackingCopy<R>,
853 entity_key: Key,
854) -> casper_types::URef {
855 let stored_value = tracking_copy
856 .read(&entity_key)
857 .expect("should read account")
858 .expect("should have account");
859 match stored_value {
860 StoredValue::CLValue(addressable_entity_key) => {
861 let key = addressable_entity_key
862 .into_t::<Key>()
863 .expect("should be key");
864 let stored_value = tracking_copy
865 .read(&key)
866 .expect("should read account")
867 .expect("should have account");
868
869 let addressable_entity = stored_value
870 .into_addressable_entity()
871 .expect("should be addressable entity");
872
873 addressable_entity.main_purse()
874 }
875 StoredValue::Account(account) => account.main_purse(),
876 StoredValue::SmartContract(smart_contract_package) => {
877 let contract_hash = smart_contract_package
878 .versions()
879 .latest()
880 .expect("should have last entry");
881 let entity_addr = EntityAddr::SmartContract(contract_hash.value());
882 let latest_version_key = Key::AddressableEntity(entity_addr);
883 let new_contract = tracking_copy
884 .read(&latest_version_key)
885 .expect("should read latest version");
886 let addressable_entity = new_contract
887 .expect("should have addressable entity")
888 .into_addressable_entity()
889 .expect("should be addressable entity");
890 addressable_entity.main_purse()
891 }
892 other => panic!("should be account or contract received {other:?}"),
893 }
894}