diff --git a/executor/wasm/src/lib.rs b/executor/wasm/src/lib.rs index ff2148165c..708a1f0785 100644 --- a/executor/wasm/src/lib.rs +++ b/executor/wasm/src/lib.rs @@ -318,8 +318,6 @@ impl ExecutorV2 { execution_stack, } = execute_request; - let (entity_addr, source_purse) = get_purse_for_entity(&mut tracking_copy, caller_key)?; - let (wasm_bytes, export_name) = { if let ExecutionKind::SessionBytes(wasm_bytes) = &execution_kind { (wasm_bytes.clone(), DEFAULT_WASM_ENTRY_POINT) @@ -472,6 +470,8 @@ impl ExecutorV2 { .take_bytes(); if transferred_value != 0 { + let (entity_addr, source_purse) = + get_purse_for_entity(&mut tracking_copy, caller_key)?; // TODO: consult w/ Michal re: charge timing let gas_usage = GasUsage::new_from_limit(gas_limit); @@ -551,6 +551,8 @@ impl ExecutorV2 { })? { Some(StoredValue::ByteCode(bytecode)) => { if transferred_value != 0 { + let (entity_addr, source_purse) = + get_purse_for_entity(&mut tracking_copy, caller_key)?; // TODO: consult w/ Michal re: charge timing let gas_usage = GasUsage::new_from_limit(gas_limit); diff --git a/executor/wasm/tests/integration.rs b/executor/wasm/tests/integration.rs index 427f71929d..e983ddb50a 100644 --- a/executor/wasm/tests/integration.rs +++ b/executor/wasm/tests/integration.rs @@ -1722,7 +1722,9 @@ fn escrow() { } #[test] -fn should_not_fail_without_account() { +fn should_fail_without_account() { + // When transferred value is provided we fetch the underlying account, if global state doesn't + // hold it the execution should fail let chainspec_config = ChainspecConfig::from_chainspec_path(&*CHAINSPEC_SYMLINK) .expect("must get chainspec config"); let executor = make_executor(&chainspec_config); @@ -1749,6 +1751,7 @@ fn should_not_fail_without_account() { .with_state_hash(Digest::from_raw([0; 32])) .with_block_height(1) .with_parent_block_hash(BlockHash::new(Digest::from_raw([0; 32]))) + .with_transferred_value(1555) .build() .expect("should build"); @@ -2414,6 +2417,75 @@ fn calling_session_should_produce_entry_point_called_and_ret() { assert_eq!(ep_calls_and_rets, vec![call, session_return]); } +#[test] +fn calling_session_should_not_perform_an_install() { + let chainspec_config = ChainspecConfig::from_chainspec_path(&*CHAINSPEC_SYMLINK) + .expect("must get chainspec config"); + + let mut executor = make_executor(&chainspec_config); + let (global_state, mut state_root_hash, _tempdir) = make_global_state_with_genesis(); + let address_generator = make_address_generator(); + + let vm2_returner = read_wasm("vm2_returner.wasm"); + + let install_request = base_install_request_builder(&chainspec_config) + .with_wasm_bytes(vm2_returner.wasm) + .with_bundle_data(vm2_returner.meta.expect("should have bundle")) + .with_shared_address_generator(Arc::clone(&address_generator)) + .with_transferred_value(0) + .with_entry_point("new".to_string()) + .build() + .expect("should build"); + + let create_result = run_create_contract( + &mut executor, + &global_state, + state_root_hash, + install_request, + ); + state_root_hash = global_state + .commit_effects(state_root_hash, create_result.effects().clone()) + .expect("Should commit"); + let vm2_returner_caller = read_wasm("vm2_returner_caller.wasm"); + let input: Bytes = create_result + .smart_contract_addr() + .to_bytes() + .unwrap() + .into(); + let execute_request = base_execute_builder(&chainspec_config) + .with_state_hash(state_root_hash) + .with_initiator(*DEFAULT_ACCOUNT_HASH) + .with_caller_key(Key::Account(*DEFAULT_ACCOUNT_HASH)) + .with_gas_limit(DEFAULT_GAS_LIMIT) + .with_transaction_hash(TRANSACTION_HASH) + .with_execution_kind(ExecutionKind::SessionBytes(vm2_returner_caller.wasm)) + .with_transferred_value(0) + .with_shared_address_generator(Arc::clone(&address_generator)) + .with_block_height(1) + .with_parent_block_hash(BlockHash::new(Digest::from_raw([0; 32]))) + .with_runtime_native_config(make_runtime_config(&chainspec_config)) + .with_input(input) + .build() + .expect("should build"); + let result = expect_successful_execution( + &mut executor, + &global_state, + state_root_hash, + execute_request, + ); + + let transforms = result.effects().transforms(); + assert!(!transforms.iter().any(|transform: &TransformV2| { + matches!( + transform.kind(), + TransformKindV2::Write(StoredValue::ContractPackage(_)) + ) || matches!( + transform.kind(), + TransformKindV2::Write(StoredValue::SmartContract(_)) + ) + })); +} + fn get_contract_package_and_wasms( state_hash: Digest, global_state: &LmdbGlobalState, diff --git a/node/src/components/contract_runtime/operations/wasm_v2_request.rs b/node/src/components/contract_runtime/operations/wasm_v2_request.rs index 05fcd6de31..d5975d9582 100644 --- a/node/src/components/contract_runtime/operations/wasm_v2_request.rs +++ b/node/src/components/contract_runtime/operations/wasm_v2_request.rs @@ -148,6 +148,8 @@ pub(crate) enum InvalidRequest { ExpectedTransferredValue, #[error("Expected V2 runtime")] ExpectedV2Runtime, + #[error("Invalida input")] + InvalidaInput, } impl WasmV2Request { @@ -272,20 +274,28 @@ impl WasmV2Request { seed, bundle_data, }, - is_install_upgrade: _, // TODO: Handle this - } => match entry_point { - TransactionEntryPoint::Call => Target::Session { - module_bytes: module_bytes.clone().take_inner().into(), - }, - TransactionEntryPoint::Custom(entry_point) => Target::Install { - module_bytes: module_bytes.clone().take_inner().into(), - entry_point: entry_point.to_string(), - transferred_value, - seed, - bundle_data: bundle_data.map(|bytes| bytes.take_inner().into()), - }, - _ => todo!(), - }, + is_install_upgrade, + } => { + if is_install_upgrade { + let entry_point_name = match entry_point { + TransactionEntryPoint::Custom(entry_point) => entry_point, + // For vm2 session install/upgrade we expect a constructor name + // to be specified verbatim in the TransactionEntryPoint::Custom variant + _ => return Err(InvalidRequest::InvalidaInput), + }; + Target::Install { + module_bytes: module_bytes.clone().take_inner().into(), + entry_point: entry_point_name, + transferred_value, + seed, + bundle_data: bundle_data.map(|bytes| bytes.take_inner().into()), + } + } else { + Target::Session { + module_bytes: module_bytes.clone().take_inner().into(), + } + } + } }; info!(%transaction_hash, "executing v1 contract"); diff --git a/smart_contracts/contracts/vm2/vm2-returner-caller/src/lib.rs b/smart_contracts/contracts/vm2/vm2-returner-caller/src/lib.rs index 642ec410dc..6907f488fe 100644 --- a/smart_contracts/contracts/vm2/vm2-returner-caller/src/lib.rs +++ b/smart_contracts/contracts/vm2/vm2-returner-caller/src/lib.rs @@ -6,7 +6,6 @@ pub mod exports { #[casper(export)] pub fn call(address: Address) { let _ = casper::print(&format!("trying to call address {:?}", address)); - casper::casper_call(&address, 0, "do_return", &[]) .1 .unwrap(); diff --git a/smart_contracts/vm2/sdk/src/casper.rs b/smart_contracts/vm2/sdk/src/casper.rs index f9a21ee3ac..e0d1b2c537 100644 --- a/smart_contracts/vm2/sdk/src/casper.rs +++ b/smart_contracts/vm2/sdk/src/casper.rs @@ -223,7 +223,8 @@ pub(crate) fn call_result_from_code(result_code: u32) -> Result<(), CallError> { if result_code == HOST_ERROR_SUCCESS { Ok(()) } else { - Err(CallError::try_from(result_code).expect("Unexpected error code")) + Err(CallError::try_from(result_code) + .unwrap_or_else(|_| panic!("Unexpected error code: {}", result_code))) } } diff --git a/smart_contracts/vm2/sdk/src/types.rs b/smart_contracts/vm2/sdk/src/types.rs index 6b261adbf9..f17526aff8 100644 --- a/smart_contracts/vm2/sdk/src/types.rs +++ b/smart_contracts/vm2/sdk/src/types.rs @@ -224,6 +224,7 @@ impl TryFrom for CallError { type Error = (); fn try_from(value: u32) -> Result { + #[allow(unreachable_patterns)] match value { CALLEE_ROLLED_BACK => Ok(Self::CalleeRolledBack), CALLEE_TRAPPED => Ok(Self::CalleeTrapped), @@ -235,6 +236,10 @@ impl TryFrom for CallError { CALLEE_ENTITY_NOT_FOUND => Ok(Self::EntityNotFound), CALLEE_LOCKED_PACKAGE => Ok(Self::LockedPackage), CALLEE_REVERT_ERROR => Ok(Self::CalleeReverted), + CALLEE_NO_ACTIVE_CONTRACT => Ok(Self::NoActiveContract), + CALLEE_CODE_NOT_FOUND => Ok(Self::CodeNotFound), + CALLEE_ENTITY_NOT_FOUND => Ok(Self::EntityNotFound), + CALLEE_LOCKED_PACKAGE => Ok(Self::LockedPackage), _ => Err(()), } }