From 51421a8a704af5ad139bbdf7998ecb6aca2cf157 Mon Sep 17 00:00:00 2001 From: Karan Dhareshwar Date: Wed, 10 Sep 2025 14:30:02 -0500 Subject: [PATCH 01/14] Initial WIP --- executor/wasm/src/lib.rs | 8 +- executor/wasm/src/testing.rs | 2 +- executor/wasm_host/src/host.rs | 441 ++++++++++++------ smart_contracts/sdk/src/casper.rs | 7 +- smart_contracts/sdk/src/collections/vector.rs | 9 +- 5 files changed, 321 insertions(+), 146 deletions(-) diff --git a/executor/wasm/src/lib.rs b/executor/wasm/src/lib.rs index afa8b4e9b9..6f32adffec 100644 --- a/executor/wasm/src/lib.rs +++ b/executor/wasm/src/lib.rs @@ -720,7 +720,13 @@ impl ExecutorV2 { ExecutionKind::Stored { address: smart_contract_addr, .. - } => Key::SmartContract(*smart_contract_addr), + } => { + if initial_tracking_copy.enable_addressable_entity() { + Key::AddressableEntity(EntityAddr::SmartContract(*smart_contract_addr)) + } else { + Key::Hash(*smart_contract_addr) + } + } ExecutionKind::SessionBytes(_wasm_bytes) => Key::Account(initiator), ExecutionKind::System(_) => { error!("System executions are not called in this way. This should be unreachable."); diff --git a/executor/wasm/src/testing.rs b/executor/wasm/src/testing.rs index b39aa2fbf7..7700a6cceb 100644 --- a/executor/wasm/src/testing.rs +++ b/executor/wasm/src/testing.rs @@ -283,7 +283,7 @@ pub fn make_global_state_with_genesis() -> (LmdbGlobalState, Digest, TempDir) { Timestamp::now().millis(), casper_types::HoldBalanceHandling::Accrued, 0, - true, + false, StorageCosts::default(), ); let genesis_request: GenesisRequest = GenesisRequest::new( diff --git a/executor/wasm_host/src/host.rs b/executor/wasm_host/src/host.rs index 7b01095a7c..4a1da29d3d 100644 --- a/executor/wasm_host/src/host.rs +++ b/executor/wasm_host/src/host.rs @@ -1,4 +1,4 @@ -use std::{borrow::Cow, num::NonZeroU32, sync::Arc}; +use std::{borrow::Cow, collections::BTreeMap, num::NonZeroU32, sync::Arc}; use bytes::Bytes; use casper_executor_wasm_common::{ @@ -31,10 +31,11 @@ use casper_types::{ contract_messages::{Message, MessageAddr, MessagePayload, MessageTopicSummary}, execution::RetValue, AccessRights, AddressableEntity, BlockGlobalAddr, BlockHash, BlockTime, ByteCode, ByteCodeAddr, - ByteCodeHash, ByteCodeKind, CLType, CLValue, ContractRuntimeTag, Digest, EntityAddr, - EntityEntryPoint, EntityKind, EntryPointAccess, EntryPointAddr, EntryPointPayment, - EntryPointType, EntryPointValue, HashAddr, HashAlgorithm, HostFunctionV2, Key, Package, - PackageHash, ProtocolVersion, Signature, StoredValue, URef, + ByteCodeHash, ByteCodeKind, CLType, CLValue, Contract, ContractRuntimeTag, ContractWasm, + ContractWasmHash, Digest, EntityAddr, EntityEntryPoint, EntityKind, EntryPointAccess, + EntryPointAddr, EntryPointPayment, EntryPointType, EntryPointValue, HashAddr, HashAlgorithm, + HostFunctionV2, Key, NamedKeys, Package, PackageHash, ProtocolVersion, Signature, StoredValue, + URef, }; use either::Either; use num_derive::FromPrimitive; @@ -53,6 +54,7 @@ use blake2::{ use casper_executor_wasm_interface::executor::{ AuctionMethods, ExecuteRequest, MintMethods, SystemMenu, }; +use casper_types::contracts::{ContractHash, ContractPackage, ContractPackageHash, EntryPoints}; use keccak_asm::Digest as KeccakDigest; use sha2::Sha256; @@ -216,42 +218,89 @@ pub fn casper_write( } Keyspace::NamedKey(name) => { // NamedKey points to a URef which holds CLValue::Any bytes - let maybe_existing_uref = caller + let maybe_stored_value = caller .context_mut() .tracking_copy .read(&global_state_key) .map_err(|_| InternalHostError::TrackingCopy)?; - let uref_to_use: URef = - if let Some(StoredValue::NamedKey(existing_named_key)) = maybe_existing_uref { - if let Ok(Key::URef(existing_uref)) = existing_named_key.get_key() { - existing_uref - } else { + let stored_value = match maybe_stored_value { + Some(StoredValue::NamedKey(existing_named_key)) => { + let uref_to_use = + if let Ok(Key::URef(existing_uref)) = existing_named_key.get_key() { + existing_uref + } else { + let mut address_generator = caller.context().address_generator.write(); + address_generator.new_uref(AccessRights::NONE) + }; + + // Point the named key to the URef + let named_key = Key::URef(uref_to_use); + let key_name = name.to_string(); + let Ok(named_key_value) = + NamedKeyValue::from_concrete_values(named_key, key_name) + else { + return Ok(HOST_ERROR_INVALID_DATA); + }; + + StoredValue::NamedKey(named_key_value) + } + Some(StoredValue::Contract(mut contract)) => { + let uref = match contract.named_keys().get(name) { + Some(Key::URef(uref)) => *uref, + Some(_) => return Ok(HOST_ERROR_INVALID_INPUT), + None => { + let mut address_generator = caller.context().address_generator.write(); + address_generator.new_uref(AccessRights::NONE) + } + }; + + // Write payload bytes under the URef as CLValue::Any + let cl_value_any = CLValue::from_components(CLType::Any, value.clone()); + metered_write( + &mut caller, + Key::URef(uref), + StoredValue::CLValue(cl_value_any), + )?; + + let named_keys = { + let mut ret = BTreeMap::new(); + ret.insert(name.to_string(), Key::URef(uref)); + NamedKeys::from(ret) + }; + contract.named_keys_append(named_keys); + + StoredValue::Contract(contract) + } + Some(_) => return Ok(HOST_ERROR_NOT_FOUND), + None => { + let uref = { let mut address_generator = caller.context().address_generator.write(); - address_generator.new_uref(AccessRights::NONE) - } - } else { - let mut address_generator = caller.context().address_generator.write(); - address_generator.new_uref(AccessRights::NONE) - }; + let uref = address_generator.new_uref(AccessRights::NONE); + uref + }; + // Write payload bytes under the URef as CLValue::Any + let cl_value_any = CLValue::from_components(CLType::Any, value.clone()); + metered_write( + &mut caller, + Key::URef(uref), + StoredValue::CLValue(cl_value_any), + )?; + + // Point the named key to the URef + let named_key = Key::URef(uref); + let key_name = name.to_string(); + let Ok(named_key_value) = + NamedKeyValue::from_concrete_values(named_key, key_name) + else { + return Ok(HOST_ERROR_INVALID_DATA); + }; - // Write payload bytes under the URef as CLValue::Any - let cl_value_any = CLValue::from_components(CLType::Any, value.clone()); - metered_write( - &mut caller, - Key::URef(uref_to_use), - StoredValue::CLValue(cl_value_any), - )?; - - // Point the named key to the URef - let named_key = Key::URef(uref_to_use); - let key_name = name.to_string(); - let Ok(named_key_value) = NamedKeyValue::from_concrete_values(named_key, key_name) - else { - return Ok(HOST_ERROR_INVALID_DATA); + StoredValue::NamedKey(named_key_value) + } }; - StoredValue::NamedKey(named_key_value) + stored_value } Keyspace::PaymentInfo(_) => { let entry_point_payment = match value.as_slice() { @@ -429,6 +478,7 @@ pub fn casper_read( cb_alloc: u32, alloc_ctx: u32, ) -> VMResult { + println!("read"); let read_cost = caller.context().config.host_function_costs().read; charge_host_function_call( &mut caller, @@ -487,37 +537,51 @@ pub fn casper_read( let global_state_key = match keyspace_to_global_state_key(caller.context(), keyspace) { Some(global_state_key) => global_state_key, None => { + println!("fooo"); // Unknown keyspace received, return error return Ok(HOST_ERROR_NOT_FOUND); } }; - let global_state_raw_bytes = if let Key::AddressableEntity(entity_addr) = global_state_key { - let named_keys = caller - .context_mut() - .tracking_copy - .get_named_keys(entity_addr) - .map(|named_keys| named_keys.to_bytes()); - match named_keys { - Ok(Ok(named_keys)) => Cow::Owned(named_keys), - Ok(_) | Err(_) => return Ok(HOST_ERROR_INVALID_DATA), + let global_state_read_result = caller.context_mut().tracking_copy.read(&global_state_key); + let global_state_raw_bytes: Cow<[u8]> = match global_state_read_result { + Ok(Some(StoredValue::CLValue(cl_value))) => { + let CLType::Any = cl_value.cl_type() else { + return Err(InternalHostError::TypeConversion)?; + }; + Cow::Owned(cl_value.inner_bytes().to_owned()) } - } else { - let global_state_read_result = caller.context_mut().tracking_copy.read(&global_state_key); - let global_state_raw_bytes: Cow<[u8]> = match global_state_read_result { - Ok(Some(StoredValue::CLValue(cl_value))) => { - let CLType::Any = cl_value.cl_type() else { - return Err(InternalHostError::TypeConversion)?; - }; - Cow::Owned(cl_value.inner_bytes().to_owned()) + Ok(Some(StoredValue::NamedKey(named_key_value))) => { + // Dereference named key to its URef and return the underlying Any bytes + let Ok(Key::URef(uref)) = named_key_value.get_key() else { + return Ok(HOST_ERROR_INVALID_DATA); + }; + + match caller.context_mut().tracking_copy.read(&Key::URef(uref)) { + Ok(Some(StoredValue::CLValue(cl_value))) => { + let CLType::Any = cl_value.cl_type() else { + return Ok(HOST_ERROR_INVALID_DATA); + }; + Cow::Owned(cl_value.inner_bytes().to_owned()) + } + Ok(Some(_)) => { + return Ok(HOST_ERROR_INVALID_DATA); + } + Ok(None) => { + return Ok(HOST_ERROR_NOT_FOUND); + } + Err(_error) => { + return Err(InternalHostError::TrackingCopy.into()); + } } - Ok(Some(StoredValue::NamedKey(named_key_value))) => { - // Dereference named key to its URef and return the underlying Any bytes - let Ok(Key::URef(uref)) = named_key_value.get_key() else { + } + Ok(Some(StoredValue::Contract(contract))) => match keyspace { + Keyspace::NamedKey(name) => { + let Some(Key::URef(uref)) = contract.named_keys().get(name) else { return Ok(HOST_ERROR_INVALID_DATA); }; - match caller.context_mut().tracking_copy.read(&Key::URef(uref)) { + match caller.context_mut().tracking_copy.read(&Key::URef(*uref)) { Ok(Some(StoredValue::CLValue(cl_value))) => { let CLType::Any = cl_value.cl_type() else { return Ok(HOST_ERROR_INVALID_DATA); @@ -535,40 +599,69 @@ pub fn casper_read( } } } - Ok(Some(StoredValue::EntryPoint(EntryPointValue::V1CasperVm(entry_point)))) => { - match entry_point.entry_point_payment() { - EntryPointPayment::Caller => Cow::Borrowed(&[ENTRY_POINT_PAYMENT_CALLER]), - EntryPointPayment::DirectInvocationOnly => { - Cow::Borrowed(&[ENTRY_POINT_PAYMENT_DIRECT_INVOCATION_ONLY]) - } - EntryPointPayment::SelfOnward => { - Cow::Borrowed(&[ENTRY_POINT_PAYMENT_SELF_ONWARD]) - } + Keyspace::AllNamedKeys => match contract.take_named_keys().to_bytes() { + Ok(bytes) => Cow::Owned(bytes), + Err(_) => return Ok(HOST_ERROR_INVALID_INPUT), + }, + Keyspace::PaymentInfo(entry_point_name) => { + match contract.entry_point(entry_point_name) { + Some(_) => Cow::Borrowed(&[ENTRY_POINT_PAYMENT_CALLER]), + None => return Ok(HOST_ERROR_INVALID_INPUT), } } - Ok(Some(stored_value)) => { - // TODO: Backwards compatibility with old EE, although it's not clear if we should - // do it at the storage level. Since new VM has storage isolated - // from the Wasm (i.e. we have Keyspace on the wasm which gets - // converted to a global state `Key`). I think if we were to pursue - // this we'd add a new `Keyspace` enum variant for each old - // VM supported Key types (i.e. URef, Dictionary perhaps) for some period of time, - // then deprecate this. - todo!("Unsupported {stored_value:?}") + _ => { + error!(?keyspace, "unsupported keyspace"); + return Ok(HOST_ERROR_INVALID_INPUT); } - Ok(None) => return Ok(HOST_ERROR_NOT_FOUND), // Entry does not exist - Err(error) => { - // To protect the network against potential non-determinism (i.e. one validator runs - // out of space or just faces I/O issues that other validators may - // not have) we're simply aborting the process, hoping that once the - // node goes back online issues are resolved on the validator side. - // TODO: We should signal this to the contract runtime somehow, and - // let validator nodes skip execution. - error!(?error, "Error while reading from storage; aborting"); - panic!("Error while reading from storage; aborting key={global_state_key:?} error={error:?}") + }, + Ok(Some(StoredValue::AddressableEntity(_))) => { + if let Keyspace::AllNamedKeys = keyspace { + let entity_addr = context_to_entity_addr(&caller.context()); + + let named_keys = caller + .context_mut() + .tracking_copy + .get_named_keys(entity_addr) + .map(|named_keys| named_keys.to_bytes()); + + match named_keys { + Ok(Ok(bytes)) => Cow::Owned(bytes), + Ok(_) | Err(_) => return Ok(HOST_ERROR_INVALID_INPUT), + } + } else { + return Ok(HOST_ERROR_INVALID_INPUT); } - }; - global_state_raw_bytes + } + Ok(Some(StoredValue::EntryPoint(EntryPointValue::V1CasperVm(entry_point)))) => { + match entry_point.entry_point_payment() { + EntryPointPayment::Caller => Cow::Borrowed(&[ENTRY_POINT_PAYMENT_CALLER]), + EntryPointPayment::DirectInvocationOnly => { + Cow::Borrowed(&[ENTRY_POINT_PAYMENT_DIRECT_INVOCATION_ONLY]) + } + EntryPointPayment::SelfOnward => Cow::Borrowed(&[ENTRY_POINT_PAYMENT_SELF_ONWARD]), + } + } + Ok(Some(stored_value)) => { + // TODO: Backwards compatibility with old EE, although it's not clear if we should + // do it at the storage level. Since new VM has storage isolated + // from the Wasm (i.e. we have Keyspace on the wasm which gets + // converted to a global state `Key`). I think if we were to pursue + // this we'd add a new `Keyspace` enum variant for each old + // VM supported Key types (i.e. URef, Dictionary perhaps) for some period of time, + // then deprecate this. + todo!("Unsupported {stored_value:?}") + } + Ok(None) => return Ok(HOST_ERROR_NOT_FOUND), // Entry does not exist + Err(error) => { + // To protect the network against potential non-determinism (i.e. one validator runs + // out of space or just faces I/O issues that other validators may + // not have) we're simply aborting the process, hoping that once the + // node goes back online issues are resolved on the validator side. + // TODO: We should signal this to the contract runtime somehow, and + // let validator nodes skip execution. + error!(?error, "Error while reading from storage; aborting"); + panic!("Error while reading from storage; aborting key={global_state_key:?} error={error:?}") + } }; let out_ptr: u32 = if cb_alloc != 0 { @@ -596,6 +689,7 @@ fn keyspace_to_global_state_key( keyspace: Keyspace<'_>, ) -> Option { let entity_addr = context_to_entity_addr(context); + let ae_enabled = context.tracking_copy.enable_addressable_entity(); match keyspace { Keyspace::State => Some(Key::State(entity_addr)), @@ -618,7 +712,19 @@ fn keyspace_to_global_state_key( EntryPointAddr::new_v1_entry_point_addr(entity_addr, payload).ok()?; Some(Key::EntryPoint(entry_point_addr)) } - Keyspace::AllNamedKeys => Some(Key::AddressableEntity(entity_addr)), + Keyspace::AllNamedKeys => { + if ae_enabled { + Some(Key::AddressableEntity(entity_addr)) + } else { + match entity_addr { + EntityAddr::Account(hash_addr) => { + Some(Key::Account(AccountHash::new(hash_addr))) + } + EntityAddr::SmartContract(hash_addr) => Some(Key::Hash(hash_addr)), + _ => None, + } + } + } } } @@ -627,9 +733,8 @@ fn context_to_entity_addr( ) -> EntityAddr { match context.callee { Key::Account(account_hash) => EntityAddr::new_account(account_hash.value()), - Key::SmartContract(smart_contract_addr) => { - EntityAddr::new_smart_contract(smart_contract_addr) - } + Key::Hash(hash_addr) => EntityAddr::SmartContract(hash_addr), + Key::AddressableEntity(smart_contract_addr) => smart_contract_addr, _ => { // This should never happen, as the caller is always an account or a smart contract. panic!("Unexpected callee variant: {:?}", context.callee) @@ -729,6 +834,7 @@ pub fn casper_create( result_ptr: u32, ) -> VMResult { // In restricted mode, contract creation is not allowed + println!("In create"); if caller.context().sandboxed { return Err(InternalHostError::AttemptWriteInRestricted.into()); } @@ -809,14 +915,13 @@ pub fn casper_create( let bytecode = ByteCode::new(ByteCodeKind::V2CasperWasm, code.clone().into()); let bytecode_addr = ByteCodeAddr::V2CasperWasm(bytecode_hash); - // 1. Store package hash - let mut smart_contract_package = Package::default(); - - let protocol_version = ProtocolVersion::V2_0_0; - let protocol_version_major = protocol_version.value().major; - let callee_addr = context_to_entity_addr(caller.context()).value(); + let package_addr: HashAddr = { + let mut address_generator = caller.context().address_generator.write(); + address_generator.new_uref(AccessRights::NONE).addr() + }; + let smart_contract_addr: HashAddr = chain_utils::compute_predictable_address( caller.context().chain_name.as_bytes(), callee_addr, @@ -824,15 +929,41 @@ pub fn casper_create( seed, ); - smart_contract_package.insert_entity_version( - protocol_version_major, - EntityAddr::SmartContract(smart_contract_addr), - ); + let protocol_version = ProtocolVersion::V2_0_0; + let protocol_version_major = protocol_version.value().major; + + let ae_enabled = caller.context().tracking_copy.enable_addressable_entity(); + + let (smart_contract_package_key, smart_contract_package_as_stored_value) = if ae_enabled { + // 1. Store package hash + let mut smart_contract_package = Package::default(); + + smart_contract_package.insert_entity_version( + protocol_version_major, + EntityAddr::SmartContract(smart_contract_addr), + ); + + ( + Key::SmartContract(package_addr), + StoredValue::SmartContract(smart_contract_package), + ) + } else { + let mut smart_contract_package = ContractPackage::default(); + smart_contract_package.insert_contract_version( + protocol_version_major, + ContractHash::new(smart_contract_addr), + ); + + ( + Key::Hash(package_addr), + StoredValue::ContractPackage(smart_contract_package), + ) + }; if caller .context_mut() .tracking_copy - .read(&Key::SmartContract(smart_contract_addr)) + .read(&smart_contract_package_key) .map_err(|_| VMError::Internal(InternalHostError::TrackingCopy))? .is_some() { @@ -841,54 +972,82 @@ pub fn casper_create( metered_write( &mut caller, - Key::SmartContract(smart_contract_addr), - StoredValue::SmartContract(smart_contract_package), + smart_contract_package_key, + smart_contract_package_as_stored_value, )?; // 2. Store wasm - metered_write( - &mut caller, - Key::ByteCode(bytecode_addr), - StoredValue::ByteCode(bytecode), - )?; - - // 3. Store addressable entity - - let entity_addr = EntityAddr::SmartContract(smart_contract_addr); - let addressable_entity_key = Key::AddressableEntity(entity_addr); - - // TODO: abort(str) as an alternative to trap - let address_generator = Arc::clone(&caller.context().address_generator); - let transaction_hash = caller.context().transaction_hash; - let runtime_native_config = caller.context().runtime_native_config.clone(); - let main_purse: URef = match system::create_purse( - &mut caller.context_mut().tracking_copy, - runtime_native_config, - transaction_hash, - address_generator, - ) { - Ok(uref) => uref, - Err(mint_error) => { - error!(?mint_error, "Failed to create a purse"); - return Ok(CALLEE_TRAPPED); - } + if ae_enabled { + metered_write( + &mut caller, + Key::ByteCode(bytecode_addr), + StoredValue::ByteCode(bytecode), + )? + } else { + metered_write( + &mut caller, + Key::Hash(bytecode_hash), + StoredValue::ContractWasm(ContractWasm::new(bytecode.take_bytes())), + )? }; - let addressable_entity = AddressableEntity::new( - PackageHash::new(smart_contract_addr), - ByteCodeHash::new(bytecode_hash), - ProtocolVersion::V2_0_0, - main_purse, - AssociatedKeys::default(), - ActionThresholds::default(), - EntityKind::SmartContract(ContractRuntimeTag::VmCasperV2), - ); + if ae_enabled { + // 3. Store addressable entity + let entity_addr = EntityAddr::SmartContract(smart_contract_addr); + let addressable_entity_key = Key::AddressableEntity(entity_addr); + + // TODO: abort(str) as an alternative to trap + let address_generator = Arc::clone(&caller.context().address_generator); + let transaction_hash = caller.context().transaction_hash; + let runtime_native_config = caller.context().runtime_native_config.clone(); + let main_purse: URef = match system::create_purse( + &mut caller.context_mut().tracking_copy, + runtime_native_config, + transaction_hash, + address_generator, + ) { + Ok(uref) => uref, + Err(mint_error) => { + error!(?mint_error, "Failed to create a purse"); + return Ok(CALLEE_TRAPPED); + } + }; - metered_write( - &mut caller, - addressable_entity_key, - StoredValue::AddressableEntity(addressable_entity), - )?; + let addressable_entity = AddressableEntity::new( + PackageHash::new(smart_contract_addr), + ByteCodeHash::new(bytecode_hash), + ProtocolVersion::V2_0_0, + main_purse, + AssociatedKeys::default(), + ActionThresholds::default(), + EntityKind::SmartContract(ContractRuntimeTag::VmCasperV2), + ); + + metered_write( + &mut caller, + addressable_entity_key, + StoredValue::AddressableEntity(addressable_entity), + )?; + } else { + println!("writing contract"); + let contract_package_hash = ContractPackageHash::new(smart_contract_addr); + let contract_wasm_hash = ContractWasmHash::new(bytecode_hash); + + let contract = Contract::new( + contract_package_hash, + contract_wasm_hash, + // TODO: Populate this correctly + NamedKeys::default(), + EntryPoints::default(), + ProtocolVersion::V2_0_0, + ); + + metered_write( + &mut caller, + Key::Hash(smart_contract_addr), + StoredValue::Contract(contract), + )?; + } let _initial_state = match constructor_entry_point { Some(entry_point_name) => { @@ -1590,6 +1749,7 @@ pub fn casper_env_info( Key::SmartContract(smart_contract_addr) => { (EntityKindTag::Contract as u32, *smart_contract_addr) } + Key::Hash(hash_addr) => (EntityKindTag::Contract as u32, *hash_addr), other => panic!("Unexpected caller: {other:?}"), }; @@ -1598,6 +1758,7 @@ pub fn casper_env_info( Key::SmartContract(smart_contract_addr) => { (EntityKindTag::Contract as u32, *smart_contract_addr) } + Key::Hash(hash_addr) => (EntityKindTag::Contract as u32, *hash_addr), other => panic!("Unexpected callee: {other:?}"), }; diff --git a/smart_contracts/sdk/src/casper.rs b/smart_contracts/sdk/src/casper.rs index 9cb55bfad8..2eadcc6096 100644 --- a/smart_contracts/sdk/src/casper.rs +++ b/smart_contracts/sdk/src/casper.rs @@ -149,10 +149,15 @@ pub fn read Option>>( ) }; + log!("ret {:?}", ret); + match result_from_code(ret) { Ok(()) => Ok(Some(())), Err(HostResult::NotFound) => Ok(None), - Err(err) => Err(err), + Err(err) => { + log!("casper_system result_code {:?}", err); + Err(err) + } } } diff --git a/smart_contracts/sdk/src/collections/vector.rs b/smart_contracts/sdk/src/collections/vector.rs index f8f17095b9..58f5069827 100644 --- a/smart_contracts/sdk/src/collections/vector.rs +++ b/smart_contracts/sdk/src/collections/vector.rs @@ -1,6 +1,7 @@ use crate::{ abi::{CasperABI, Declaration, Definition, Definitions, StructField}, casper::{self, read_into_vec}, + log, prelude::{cmp::Ordering, marker::PhantomData}, serializers::borsh::{BorshDeserialize, BorshSerialize}, }; @@ -84,9 +85,11 @@ where pub fn get(&self, index: u64) -> Option { let prefix = self.compute_prefix_bytes_for_index(index); let item_keyspace = Keyspace::Context(&prefix); - read_into_vec(item_keyspace) - .unwrap() - .map(|vec| borsh::from_slice(&vec).unwrap()) + log!("Foooo"); + read_into_vec(item_keyspace).unwrap().map(|vec| { + log!("vec {:?}", vec); + borsh::from_slice(&vec).unwrap() + }) } /// Returns an iterator over self, with elements deserialized. From 4b1716d6c38d1ed49d3656dc62eaad81459a92bd Mon Sep 17 00:00:00 2001 From: Karan Dhareshwar Date: Wed, 10 Sep 2025 14:47:36 -0500 Subject: [PATCH 02/14] wip pt. 2 --- executor/wasm/src/lib.rs | 4 ++++ executor/wasm_host/src/host.rs | 3 +++ 2 files changed, 7 insertions(+) diff --git a/executor/wasm/src/lib.rs b/executor/wasm/src/lib.rs index 6f32adffec..5304b97783 100644 --- a/executor/wasm/src/lib.rs +++ b/executor/wasm/src/lib.rs @@ -503,6 +503,8 @@ impl ExecutorV2 { let (entity_addr, source_purse) = get_purse_for_entity(&mut tracking_copy, caller_key)?; + println!("got addr and purse"); + let (wasm_bytes, export_name) = { if let ExecutionKind::SessionBytes(wasm_bytes) = &execution_kind { (wasm_bytes.clone(), DEFAULT_WASM_ENTRY_POINT) @@ -902,8 +904,10 @@ impl ExecutorV2 { let executable_item = ExecutableItem::Invocation(TransactionInvocationTarget::ByHash(entity_addr.value())); let entry_point = entry_point.clone(); + println!("A"); let args = bytesrepr::deserialize_from_slice(input) .map_err(|err| ExecuteError::InternalHost(InternalHostError::Bytesrepr(err)))?; + println!("B"); let phase = Phase::Session; let wasm_v1_result = { diff --git a/executor/wasm_host/src/host.rs b/executor/wasm_host/src/host.rs index 4a1da29d3d..9b744f2b34 100644 --- a/executor/wasm_host/src/host.rs +++ b/executor/wasm_host/src/host.rs @@ -1049,6 +1049,7 @@ pub fn casper_create( )?; } + println!("wrote contract"); let _initial_state = match constructor_entry_point { Some(entry_point_name) => { // Limit the new VM to remaining gas. @@ -1080,6 +1081,8 @@ pub fn casper_create( .build() .map_err(InternalHostError::ExecuteRequestBuildFailure)?; + println!("build req"); + let tracking_copy_for_ctor = caller.context().tracking_copy.fork2(); match caller From 83ac5bad07f80b9067ff4a2194231bbe92a3ce28 Mon Sep 17 00:00:00 2001 From: Karan Dhareshwar Date: Thu, 11 Sep 2025 12:13:59 -0500 Subject: [PATCH 03/14] Fix incorrect routing to vm1 --- executor/wasm/src/lib.rs | 129 ++++++++++++++++++++---- executor/wasm_host/src/host.rs | 63 +++++++----- executor/wasm_interface/src/executor.rs | 4 + 3 files changed, 150 insertions(+), 46 deletions(-) diff --git a/executor/wasm/src/lib.rs b/executor/wasm/src/lib.rs index 5304b97783..4217aa8b18 100644 --- a/executor/wasm/src/lib.rs +++ b/executor/wasm/src/lib.rs @@ -62,6 +62,8 @@ const DEFAULT_WASM_ENTRY_POINT: &str = "call"; const DEFAULT_MINT_TRANSFER_GAS_COST: u64 = 1; // NOTE: Require gas while executing and set this to at least 100_000_000 (or use chainspec) +const NAME_FOR_V2_CONTRACT_MAIN_PURSE: &str = "__v2_main_purse"; + #[derive(Copy, Clone, Debug)] pub enum ExecutorKind { /// Ahead of time compiled Wasm. @@ -526,6 +528,8 @@ impl ExecutorV2 { ExecuteError::InternalHost(InternalHostError::TrackingCopy) })?; + println!("{:?}", contract); + if let Some(StoredValue::SmartContract(smart_contract_package)) = &contract { let enabled_versions = smart_contract_package.enabled_versions(); let maybe_contract_hash = enabled_versions.latest(); @@ -570,6 +574,8 @@ impl ExecutorV2 { let entity_addr = EntityAddr::SmartContract(*smart_contract_addr); + println!("{:?}", input); + return self.execute_vm1_wasm_byte_code( initiator, &entity_addr, @@ -668,27 +674,110 @@ impl ExecutorV2 { (Bytes::from(wasm_bytes), entry_point.as_str()) } - Some(StoredValue::Contract(_vm1_contract)) => { - let block_info = BlockInfo::new( - state_hash, - block_time, - parent_block_hash, - block_height, - self.execution_engine_v1.config().protocol_version(), - ); + Some(StoredValue::Contract(contract)) => { + let byte_code_addr = + ByteCodeAddr::V2CasperWasm(contract.contract_wasm_hash().value()); + + let wasm_key = Key::ByteCode(byte_code_addr); + + match tracking_copy.read(&wasm_key).map_err(|read_err| { + error!("Error when fetching wasm_bytes {wasm_key}. Details {read_err}"); + ExecuteError::InternalHost(InternalHostError::TrackingCopy) + })? { + Some(StoredValue::ByteCode(bytecode)) => { + println!("detected VM2 bytecode record routing to Vm2"); + if transferred_value != 0 { + // TODO: consult w/ Michal re: charge timing + let gas_usage = GasUsage::new(gas_limit, gas_limit); + + let runtime_footprint = match tracking_copy + .runtime_footprint_by_entity_addr(entity_addr) + { + Ok(footprint) => footprint, + Err(_) => { + return Err(ExecuteError::EntityNotFound(caller_key)); + } + }; + + let main_purse = contract + .named_keys() + .get("__v2_main_purse") + .ok_or_else(|| ExecuteError::MainPurseNotFound(vm1_key))? + .into_uref() + .ok_or_else(|| ExecuteError::InvalidKeyForPurse(vm1_key))?; + + match system::transfer( + &mut tracking_copy, + runtime_footprint, + TransferArgs::new( + runtime_native_config.clone(), + transaction_hash, + Arc::clone(&address_generator), + initiator, + caller_key, + gas_usage.remaining_points().into(), + source_purse, + main_purse, + transferred_value.into(), + ), + ) { + Ok(()) => {} + Err(DispatchError::Internal(internal_error)) => { + error!( + ?internal_error, + "Internal error while transferring value to the contract's purse", + ); + return Err(ExecuteError::InternalHost(internal_error)); + } + Err(DispatchError::Call(error)) => { + return Ok(ExecuteResult { + host_error: Some(error), + output: None, + gas_usage: GasUsage::new( + gas_limit, + gas_limit - DEFAULT_MINT_TRANSFER_GAS_COST, + ), + effects: tracking_copy.effects(), + cache: tracking_copy.cache(), + messages: tracking_copy.messages(), + }); + } + Err(error) => { + error!( + ?error, + "Dispatch error while transferring value to the contract's purse", + ); + return Err(ExecuteError::InternalHost( + InternalHostError::DispatchSystemContract, + )); + } + } + } + (Bytes::from(bytecode.take_bytes()), entry_point.as_str()) + } + Some(_) | None => { + let block_info = BlockInfo::new( + state_hash, + block_time, + parent_block_hash, + block_height, + self.execution_engine_v1.config().protocol_version(), + ); - let entity_addr = EntityAddr::SmartContract(*smart_contract_addr); - - return self.execute_vm1_wasm_byte_code( - initiator, - &entity_addr, - entry_point.clone(), - &input, - &mut tracking_copy, - block_info, - transaction_hash, - gas_limit, - ); + let entity_addr = EntityAddr::SmartContract(*smart_contract_addr); + + return self.execute_vm1_wasm_byte_code( + initiator, + &entity_addr, + entry_point.clone(), + &input, + &mut tracking_copy, + block_info, + transaction_hash, + gas_limit, + ); + } + } } Some(stored_value) => { todo!( diff --git a/executor/wasm_host/src/host.rs b/executor/wasm_host/src/host.rs index 9b744f2b34..dc0dac1a06 100644 --- a/executor/wasm_host/src/host.rs +++ b/executor/wasm_host/src/host.rs @@ -58,6 +58,8 @@ use casper_types::contracts::{ContractHash, ContractPackage, ContractPackageHash use keccak_asm::Digest as KeccakDigest; use sha2::Sha256; +const NAME_FOR_V2_CONTRACT_MAIN_PURSE: &str = "__v2_main_purse"; + #[derive(Debug, Copy, Clone, FromPrimitive, PartialEq)] enum EntityKindTag { Account = 0, @@ -977,42 +979,42 @@ pub fn casper_create( )?; // 2. Store wasm - if ae_enabled { - metered_write( - &mut caller, - Key::ByteCode(bytecode_addr), - StoredValue::ByteCode(bytecode), - )? - } else { + if !ae_enabled { metered_write( &mut caller, Key::Hash(bytecode_hash), - StoredValue::ContractWasm(ContractWasm::new(bytecode.take_bytes())), + StoredValue::ContractWasm(ContractWasm::new(bytecode.clone().take_bytes())), )? }; + metered_write( + &mut caller, + Key::ByteCode(bytecode_addr), + StoredValue::ByteCode(bytecode), + )?; + + // TODO: abort(str) as an alternative to trap + let address_generator = Arc::clone(&caller.context().address_generator); + let transaction_hash = caller.context().transaction_hash; + let runtime_native_config = caller.context().runtime_native_config.clone(); + let main_purse: URef = match system::create_purse( + &mut caller.context_mut().tracking_copy, + runtime_native_config, + transaction_hash, + address_generator, + ) { + Ok(uref) => uref, + Err(mint_error) => { + error!(?mint_error, "Failed to create a purse"); + return Ok(CALLEE_TRAPPED); + } + }; + if ae_enabled { // 3. Store addressable entity let entity_addr = EntityAddr::SmartContract(smart_contract_addr); let addressable_entity_key = Key::AddressableEntity(entity_addr); - // TODO: abort(str) as an alternative to trap - let address_generator = Arc::clone(&caller.context().address_generator); - let transaction_hash = caller.context().transaction_hash; - let runtime_native_config = caller.context().runtime_native_config.clone(); - let main_purse: URef = match system::create_purse( - &mut caller.context_mut().tracking_copy, - runtime_native_config, - transaction_hash, - address_generator, - ) { - Ok(uref) => uref, - Err(mint_error) => { - error!(?mint_error, "Failed to create a purse"); - return Ok(CALLEE_TRAPPED); - } - }; - let addressable_entity = AddressableEntity::new( PackageHash::new(smart_contract_addr), ByteCodeHash::new(bytecode_hash), @@ -1033,11 +1035,20 @@ pub fn casper_create( let contract_package_hash = ContractPackageHash::new(smart_contract_addr); let contract_wasm_hash = ContractWasmHash::new(bytecode_hash); + let named_keys = { + let mut ret = NamedKeys::default(); + ret.insert( + NAME_FOR_V2_CONTRACT_MAIN_PURSE.to_string(), + Key::URef(main_purse), + ); + ret + }; + let contract = Contract::new( contract_package_hash, contract_wasm_hash, // TODO: Populate this correctly - NamedKeys::default(), + named_keys, EntryPoints::default(), ProtocolVersion::V2_0_0, ); diff --git a/executor/wasm_interface/src/executor.rs b/executor/wasm_interface/src/executor.rs index 67b57c4a12..5fa11a10cc 100644 --- a/executor/wasm_interface/src/executor.rs +++ b/executor/wasm_interface/src/executor.rs @@ -490,6 +490,10 @@ pub enum ExecuteError { Api(String), #[error("sandboxed system contract call")] SandboxedSystemContractCall, + #[error("unable to find main purse for v2 contract {0}")] + MainPurseNotFound(Key), + #[error("unable to convert key into uref {0}")] + InvalidKeyForPurse(Key), } #[derive(Debug, Error)] From 0608608b6601802bc77a36e7038cdd131e47f89a Mon Sep 17 00:00:00 2001 From: Karan Dhareshwar Date: Thu, 11 Sep 2025 12:16:49 -0500 Subject: [PATCH 04/14] Println cleanup --- executor/wasm/src/lib.rs | 10 +--------- executor/wasm_host/src/host.rs | 8 +------- 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/executor/wasm/src/lib.rs b/executor/wasm/src/lib.rs index 4217aa8b18..598c80b71c 100644 --- a/executor/wasm/src/lib.rs +++ b/executor/wasm/src/lib.rs @@ -505,8 +505,6 @@ impl ExecutorV2 { let (entity_addr, source_purse) = get_purse_for_entity(&mut tracking_copy, caller_key)?; - println!("got addr and purse"); - let (wasm_bytes, export_name) = { if let ExecutionKind::SessionBytes(wasm_bytes) = &execution_kind { (wasm_bytes.clone(), DEFAULT_WASM_ENTRY_POINT) @@ -528,8 +526,6 @@ impl ExecutorV2 { ExecuteError::InternalHost(InternalHostError::TrackingCopy) })?; - println!("{:?}", contract); - if let Some(StoredValue::SmartContract(smart_contract_package)) = &contract { let enabled_versions = smart_contract_package.enabled_versions(); let maybe_contract_hash = enabled_versions.latest(); @@ -574,8 +570,6 @@ impl ExecutorV2 { let entity_addr = EntityAddr::SmartContract(*smart_contract_addr); - println!("{:?}", input); - return self.execute_vm1_wasm_byte_code( initiator, &entity_addr, @@ -685,7 +679,6 @@ impl ExecutorV2 { ExecuteError::InternalHost(InternalHostError::TrackingCopy) })? { Some(StoredValue::ByteCode(bytecode)) => { - println!("detected VM2 bytecode record routing to Vm2"); if transferred_value != 0 { // TODO: consult w/ Michal re: charge timing let gas_usage = GasUsage::new(gas_limit, gas_limit); @@ -993,10 +986,9 @@ impl ExecutorV2 { let executable_item = ExecutableItem::Invocation(TransactionInvocationTarget::ByHash(entity_addr.value())); let entry_point = entry_point.clone(); - println!("A"); let args = bytesrepr::deserialize_from_slice(input) .map_err(|err| ExecuteError::InternalHost(InternalHostError::Bytesrepr(err)))?; - println!("B"); + let phase = Phase::Session; let wasm_v1_result = { diff --git a/executor/wasm_host/src/host.rs b/executor/wasm_host/src/host.rs index dc0dac1a06..9295973565 100644 --- a/executor/wasm_host/src/host.rs +++ b/executor/wasm_host/src/host.rs @@ -480,7 +480,6 @@ pub fn casper_read( cb_alloc: u32, alloc_ctx: u32, ) -> VMResult { - println!("read"); let read_cost = caller.context().config.host_function_costs().read; charge_host_function_call( &mut caller, @@ -539,7 +538,6 @@ pub fn casper_read( let global_state_key = match keyspace_to_global_state_key(caller.context(), keyspace) { Some(global_state_key) => global_state_key, None => { - println!("fooo"); // Unknown keyspace received, return error return Ok(HOST_ERROR_NOT_FOUND); } @@ -836,7 +834,7 @@ pub fn casper_create( result_ptr: u32, ) -> VMResult { // In restricted mode, contract creation is not allowed - println!("In create"); + if caller.context().sandboxed { return Err(InternalHostError::AttemptWriteInRestricted.into()); } @@ -1031,7 +1029,6 @@ pub fn casper_create( StoredValue::AddressableEntity(addressable_entity), )?; } else { - println!("writing contract"); let contract_package_hash = ContractPackageHash::new(smart_contract_addr); let contract_wasm_hash = ContractWasmHash::new(bytecode_hash); @@ -1060,7 +1057,6 @@ pub fn casper_create( )?; } - println!("wrote contract"); let _initial_state = match constructor_entry_point { Some(entry_point_name) => { // Limit the new VM to remaining gas. @@ -1092,8 +1088,6 @@ pub fn casper_create( .build() .map_err(InternalHostError::ExecuteRequestBuildFailure)?; - println!("build req"); - let tracking_copy_for_ctor = caller.context().tracking_copy.fork2(); match caller From 17f67c9988b8a29353e25e37ede12b42a61b2253 Mon Sep 17 00:00:00 2001 From: Karan Dhareshwar Date: Thu, 11 Sep 2025 13:29:17 -0500 Subject: [PATCH 05/14] Harness test passes --- execution_engine/src/runtime/mod.rs | 4 +- executor/wasm/src/lib.rs | 20 ++++++++++ executor/wasm_host/src/host.rs | 15 +++++++- storage/src/system/mint.rs | 5 ++- storage/src/tracking_copy/ext_entity.rs | 25 +++++++++--- types/src/runtime_footprint.rs | 51 ++++++++++++++++++++++++- 6 files changed, 110 insertions(+), 10 deletions(-) diff --git a/execution_engine/src/runtime/mod.rs b/execution_engine/src/runtime/mod.rs index c273383033..8b9a78a4a6 100644 --- a/execution_engine/src/runtime/mod.rs +++ b/execution_engine/src/runtime/mod.rs @@ -1769,7 +1769,7 @@ where let maybe_system_entity_type = self.maybe_system_type(contract_hash); - RuntimeFootprint::new_contract_footprint( + RuntimeFootprint::new_vm1_contract_footprint( ContractHash::new(contract_hash), contract, maybe_system_entity_type, @@ -1869,7 +1869,7 @@ where self.migrate_contract_and_contract_package(hash_addr)?; }; let maybe_system_entity_type = self.maybe_system_type(hash_addr); - RuntimeFootprint::new_contract_footprint( + RuntimeFootprint::new_vm1_contract_footprint( ContractHash::new(hash_addr), contract, maybe_system_entity_type, diff --git a/executor/wasm/src/lib.rs b/executor/wasm/src/lib.rs index 598c80b71c..275c254fc2 100644 --- a/executor/wasm/src/lib.rs +++ b/executor/wasm/src/lib.rs @@ -683,6 +683,8 @@ impl ExecutorV2 { // TODO: consult w/ Michal re: charge timing let gas_usage = GasUsage::new(gas_limit, gas_limit); + println!("{:?}", entity_addr); + let runtime_footprint = match tracking_copy .runtime_footprint_by_entity_addr(entity_addr) { @@ -699,6 +701,8 @@ impl ExecutorV2 { .into_uref() .ok_or_else(|| ExecuteError::InvalidKeyForPurse(vm1_key))?; + println!("{:?}", main_purse); + match system::transfer( &mut tracking_copy, runtime_footprint, @@ -740,6 +744,8 @@ impl ExecutorV2 { ?error, "Dispatch error while transferring value to the contract's purse", ); + + println!("{:?}", error); return Err(ExecuteError::InternalHost( InternalHostError::DispatchSystemContract, )); @@ -1299,6 +1305,20 @@ fn get_purse_for_entity( Ok((entity_addr, addressable_entity.main_purse())) } + StoredValue::Contract(contract) => { + let uref = contract + .named_keys() + .get(NAME_FOR_V2_CONTRACT_MAIN_PURSE) + .ok_or_else(|| ExecuteError::MainPurseNotFound(entity_key))? + .into_uref() + .ok_or_else(|| ExecuteError::InvalidKeyForPurse(entity_key))?; + + let hash_addr = entity_key + .into_hash_addr() + .ok_or_else(|| ExecuteError::EntityNotFound(entity_key))?; + + Ok((EntityAddr::SmartContract(hash_addr), uref)) + } other => Err(ExecuteError::InternalHost( InternalHostError::UnexpectedStoredValueVariant { expected: "AddressableEntity or Account".to_string(), diff --git a/executor/wasm_host/src/host.rs b/executor/wasm_host/src/host.rs index 9295973565..f9371ab7ba 100644 --- a/executor/wasm_host/src/host.rs +++ b/executor/wasm_host/src/host.rs @@ -1444,7 +1444,11 @@ pub fn casper_env_balance( error!("Error when converting hash_bytes from vec to static array"); ExecuteError::InternalHost(InternalHostError::TypeConversion) })?; - let smart_contract_key = Key::SmartContract(hash_bytes); + let smart_contract_key = if caller.context().tracking_copy.enable_addressable_entity() { + Key::SmartContract(hash_bytes) + } else { + Key::Hash(hash_bytes) + }; match caller.context_mut().tracking_copy.read(&smart_contract_key) { Ok(Some(StoredValue::SmartContract(smart_contract_package))) => { match smart_contract_package.versions().latest() { @@ -1463,6 +1467,15 @@ pub fn casper_env_balance( } } } + Ok(Some(StoredValue::Contract(contract))) => { + match contract.named_keys().get(NAME_FOR_V2_CONTRACT_MAIN_PURSE) { + Some(Key::URef(uref)) => Either::Left(*uref), + None | Some(_) => { + // Not found, balance is 0 + return Ok(HOST_ERROR_SUCCESS); + } + } + } Ok(Some(_)) => { return Ok(HOST_ERROR_SUCCESS); } diff --git a/storage/src/system/mint.rs b/storage/src/system/mint.rs index 0204670fb1..117d312e28 100644 --- a/storage/src/system/mint.rs +++ b/storage/src/system/mint.rs @@ -243,7 +243,10 @@ pub trait Mint: RuntimeProvider + StorageProvider + SystemProvider { return Err(Error::DestNotFound); } let addr = match self.get_main_purse() { - None => return Err(Error::InvalidURef), + None => { + println!("foo"); + return Err(Error::InvalidURef); + } Some(uref) => uref.addr(), }; if self.get_caller() != PublicKey::System.to_account_hash() && addr == source.addr() { diff --git a/storage/src/tracking_copy/ext_entity.rs b/storage/src/tracking_copy/ext_entity.rs index 4da7866310..2b0e3216a0 100644 --- a/storage/src/tracking_copy/ext_entity.rs +++ b/storage/src/tracking_copy/ext_entity.rs @@ -206,11 +206,26 @@ where ret }; - return Ok(RuntimeFootprint::new_contract_footprint( - contract_hash, - contract, - maybe_system_entity_type, - )); + if maybe_system_entity_type.is_some() { + return Ok(RuntimeFootprint::new_vm1_contract_footprint( + contract_hash, + contract, + maybe_system_entity_type, + )); + } + + let footprint = if self + .read(&Key::ByteCode(ByteCodeAddr::V2CasperWasm( + contract.contract_wasm_hash().value(), + )))? + .is_some() + { + RuntimeFootprint::new_vm2_contract_footprint + } else { + RuntimeFootprint::new_vm1_contract_footprint + }; + + return Ok(footprint(contract_hash, contract, maybe_system_entity_type)); } Some(StoredValue::CLValue(cl_value)) => cl_value.to_t::()?, Some(_) | None => Key::AddressableEntity(entity_addr), diff --git a/types/src/runtime_footprint.rs b/types/src/runtime_footprint.rs index f84d16c850..b7d50ce676 100644 --- a/types/src/runtime_footprint.rs +++ b/types/src/runtime_footprint.rs @@ -17,6 +17,8 @@ use datasize::DataSize; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; +const V2_MAIN_PURSE_ENTRY: &str = "__v2_main_purse"; + /// Runtime Address. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[cfg_attr(feature = "datasize", derive(DataSize))] @@ -140,7 +142,7 @@ impl RuntimeFootprint { ) } - pub fn new_contract_footprint( + pub fn new_vm1_contract_footprint( contract_hash: ContractHash, contract: Contract, system_entity_type: Option, @@ -178,6 +180,53 @@ impl RuntimeFootprint { ) } + pub fn new_vm2_contract_footprint( + contract_hash: ContractHash, + contract: Contract, + system_entity_type: Option, + ) -> Self { + let contract_package_hash = contract.contract_package_hash(); + let contract_wasm_hash = contract.contract_wasm_hash(); + let entry_points = contract.entry_points().clone().into(); + let protocol_version = contract.protocol_version(); + let mut named_keys = contract.take_named_keys(); + + let runtime_address = RuntimeAddress::new_stored_contract( + contract_hash.value(), + contract_package_hash.value(), + contract_wasm_hash.value(), + protocol_version, + ); + + let main_purse = { + match named_keys + .remove(V2_MAIN_PURSE_ENTRY) + .map(|key| key.into_uref()) + { + Some(Some(uref)) => Some(uref), + Some(_) | None => None, + } + }; + + let action_thresholds = BTreeMap::new(); + let associated_keys = AssociatedKeys::empty_keys(); + + let entity_kind = match system_entity_type { + None => EntityKind::SmartContract(ContractRuntimeTag::VmCasperV2), + Some(kind) => EntityKind::System(kind), + }; + + Self::new( + named_keys, + action_thresholds, + associated_keys, + entry_points, + entity_kind, + main_purse, + runtime_address, + ) + } + pub fn new_entity_footprint( entity_addr: EntityAddr, entity: AddressableEntity, From b97ad6dc34eeff15f82e6f005c8bc3b7409a76ac Mon Sep 17 00:00:00 2001 From: Karan Dhareshwar Date: Fri, 12 Sep 2025 12:14:48 -0500 Subject: [PATCH 06/14] Rework upgrade logic --- executor/wasm_common/src/chain_utils.rs | 12 ++ executor/wasm_host/src/host.rs | 181 ++++++++++++++++++++++-- types/src/contracts.rs | 7 +- 3 files changed, 184 insertions(+), 16 deletions(-) diff --git a/executor/wasm_common/src/chain_utils.rs b/executor/wasm_common/src/chain_utils.rs index ba31e22242..ab19abe392 100644 --- a/executor/wasm_common/src/chain_utils.rs +++ b/executor/wasm_common/src/chain_utils.rs @@ -23,6 +23,18 @@ pub fn compute_predictable_address>( hasher.finalize().into() } +pub fn compute_next_contract_hash_version( + smart_contract_addr: [u8; 32], + next_version: u32, +) -> [u8; 32] { + let mut hasher = Blake2b::::new(); + + hasher.update(smart_contract_addr); + hasher.update(next_version.to_le_bytes()); + + hasher.finalize().into() +} + pub fn compute_wasm_bytecode_hash>(wasm_bytes: T) -> [u8; 32] { let mut hasher = Blake2b::::new(); hasher.update(wasm_bytes); diff --git a/executor/wasm_host/src/host.rs b/executor/wasm_host/src/host.rs index f9371ab7ba..fe1d48d6f7 100644 --- a/executor/wasm_host/src/host.rs +++ b/executor/wasm_host/src/host.rs @@ -51,6 +51,9 @@ use blake2::{ digest::{Update, VariableOutput}, Blake2bVar, }; +use casper_executor_wasm_common::chain_utils::{ + compute_next_contract_hash_version, compute_wasm_bytecode_hash, +}; use casper_executor_wasm_interface::executor::{ AuctionMethods, ExecuteRequest, MintMethods, SystemMenu, }; @@ -834,7 +837,7 @@ pub fn casper_create( result_ptr: u32, ) -> VMResult { // In restricted mode, contract creation is not allowed - + println!("in create"); if caller.context().sandboxed { return Err(InternalHostError::AttemptWriteInRestricted.into()); } @@ -1022,6 +1025,7 @@ pub fn casper_create( ActionThresholds::default(), EntityKind::SmartContract(ContractRuntimeTag::VmCasperV2), ); + println!("bar"); metered_write( &mut caller, @@ -1029,7 +1033,7 @@ pub fn casper_create( StoredValue::AddressableEntity(addressable_entity), )?; } else { - let contract_package_hash = ContractPackageHash::new(smart_contract_addr); + let contract_package_hash = ContractPackageHash::new(package_addr); let contract_wasm_hash = ContractWasmHash::new(bytecode_hash); let named_keys = { @@ -1050,6 +1054,8 @@ pub fn casper_create( ProtocolVersion::V2_0_0, ); + println!("{:?}", Key::Hash(smart_contract_addr)); + metered_write( &mut caller, Key::Hash(smart_contract_addr), @@ -1597,6 +1603,7 @@ pub fn casper_upgrade( error!("Account upgrade is not possible"); return Ok(CALLEE_NOT_CALLABLE); } + Key::Hash(contract_addr) => (contract_addr, Key::Hash(contract_addr)), addressable_entity_key @ Key::SmartContract(smart_contract_addr) => { let smart_contract_key = addressable_entity_key; match caller.context_mut().tracking_copy.read(&smart_contract_key) { @@ -1632,12 +1639,167 @@ pub fn casper_upgrade( other => panic!("should be account or addressable entity but got {other:?}"), }; - let callee_addressable_entity = match caller + println!("A {:?}", callee_addressable_entity_key); + + match caller .context_mut() .tracking_copy .read(&callee_addressable_entity_key) { - Ok(Some(StoredValue::AddressableEntity(addressable_entity))) => addressable_entity, + Ok(Some(StoredValue::AddressableEntity(addressable_entity))) => { + let package_hash = addressable_entity.package_hash(); + + let package_key = Key::SmartContract(package_hash.value()); + let mut package = match caller.context_mut().tracking_copy.read(&package_key) { + Ok(Some(StoredValue::SmartContract(package))) => package, + Ok(Some(other)) => panic!("should be package but got {other:?}"), + Ok(None) => return Ok(CALLEE_NOT_CALLABLE), + Err(error) => { + error!( + ?error, + ?package_hash, + "Error while reading from storage; aborting" + ); + panic!("Error while reading from storage") + } + }; + + if package.is_locked() { + return Ok(CALLEE_NOT_CALLABLE); + } + + match package.current_entity_hash() { + Some(previous_hash) => { + let protocol_version = caller + .context() + .runtime_native_config + .protocol_version() + .value(); + let next_version = package.next_entity_version_for(protocol_version.major); + let new_version_hash_addr = + compute_next_contract_hash_version(previous_hash.value(), next_version); + package.insert_entity_version( + protocol_version.major, + EntityAddr::SmartContract(new_version_hash_addr), + ); + if let Err(_) = package.disable_entity_version(previous_hash) { + return Ok(CALLEE_NOT_CALLABLE); + }; + + metered_write( + &mut caller, + package_key, + StoredValue::SmartContract(package), + )?; + + let bytes = code.clone(); + let new_byte_code_hash = compute_wasm_bytecode_hash(bytes); + let bytecode_key = + Key::ByteCode(ByteCodeAddr::V2CasperWasm(new_byte_code_hash)); + metered_write( + &mut caller, + bytecode_key, + StoredValue::ByteCode(ByteCode::new( + ByteCodeKind::V2CasperWasm, + code.clone().into(), + )), + )?; + + let entity = AddressableEntity::new( + package_hash, + ByteCodeHash::new(new_byte_code_hash), + ProtocolVersion::new(protocol_version), + addressable_entity.main_purse(), + addressable_entity.associated_keys().clone(), + addressable_entity.action_thresholds().clone(), + EntityKind::SmartContract(ContractRuntimeTag::VmCasperV2), + ); + let entity_key = + Key::AddressableEntity(EntityAddr::SmartContract(new_version_hash_addr)); + + metered_write( + &mut caller, + entity_key, + StoredValue::AddressableEntity(entity), + )?; + } + None => return Ok(CALLEE_NOT_CALLABLE), + } + } + Ok(Some(StoredValue::Contract(contract))) => { + println!("foo"); + let package_hash = contract.contract_package_hash(); + + let package_key = Key::Hash(package_hash.value()); + let mut package = match caller.context_mut().tracking_copy.read(&package_key) { + Ok(Some(StoredValue::ContractPackage(package))) => package, + Ok(Some(other)) => panic!("should be package but got {other:?}"), + Ok(None) => return Ok(HOST_ERROR_INVALID_DATA), + Err(error) => { + error!( + ?error, + ?package_hash, + "Error while reading from storage; aborting" + ); + panic!("Error while reading from storage") + } + }; + + if package.is_locked() { + return Ok(CALLEE_NOT_CALLABLE); + } + + match package.current_contract_hash() { + Some(previous_hash) => { + let protocol_version = caller + .context() + .runtime_native_config + .protocol_version() + .value(); + let next_version = package.next_contract_version_for(protocol_version.major); + let new_version_hash_addr = + compute_next_contract_hash_version(previous_hash.value(), next_version); + package.insert_contract_version( + protocol_version.major, + ContractHash::new(new_version_hash_addr), + ); + if let Err(_) = package.disable_contract_version(previous_hash) { + return Ok(CALLEE_NOT_CALLABLE); + }; + + metered_write( + &mut caller, + package_key, + StoredValue::ContractPackage(package), + )?; + + let bytes = code.clone(); + let new_byte_code_hash = compute_wasm_bytecode_hash(bytes); + let bytecode_key = + Key::ByteCode(ByteCodeAddr::V2CasperWasm(new_byte_code_hash)); + metered_write( + &mut caller, + bytecode_key, + StoredValue::ByteCode(ByteCode::new( + ByteCodeKind::V2CasperWasm, + code.clone().into(), + )), + )?; + + let entity = Contract::new( + package_hash, + ContractWasmHash::new(new_byte_code_hash), + contract.named_keys().clone(), + contract.entry_points().clone(), + ProtocolVersion::new(protocol_version), + ); + let smart_contract = Key::Hash(new_version_hash_addr); + + metered_write(&mut caller, smart_contract, StoredValue::Contract(entity))?; + } + None => return Ok(CALLEE_NOT_CALLABLE), + } + } Ok(Some(other_entity)) => { panic!("Unexpected entity type: {other_entity:?}") } @@ -1653,17 +1815,6 @@ pub fn casper_upgrade( // 2. Update the code therefore making hash(new_code) != addressable_entity.bytecode_addr (aka // hash(old_code)) - let bytecode_key = Key::ByteCode(ByteCodeAddr::V2CasperWasm( - callee_addressable_entity.byte_code_addr(), - )); - metered_write( - &mut caller, - bytecode_key, - StoredValue::ByteCode(ByteCode::new( - ByteCodeKind::V2CasperWasm, - code.clone().into(), - )), - )?; // 3. Execute upgrade routine (if specified) // this code should handle reading old state, and saving new state diff --git a/types/src/contracts.rs b/types/src/contracts.rs index 5eee24582c..2877a18150 100644 --- a/types/src/contracts.rs +++ b/types/src/contracts.rs @@ -819,7 +819,12 @@ impl ContractPackage { pub fn remove_group(&mut self, group: &Group) -> bool { self.groups.0.remove(group).is_some() } - fn next_contract_version_for(&self, protocol_version: ProtocolVersionMajor) -> ContractVersion { + + /// Returns the next contract version number + pub fn next_contract_version_for( + &self, + protocol_version: ProtocolVersionMajor, + ) -> ContractVersion { let current_version = self .versions .keys() From edccd09e249c079d0934d84a3da69f3a92c7be31 Mon Sep 17 00:00:00 2001 From: Karan Dhareshwar Date: Mon, 15 Sep 2025 08:31:07 -0500 Subject: [PATCH 07/14] Address lints --- executor/wasm/src/lib.rs | 12 +++++------- executor/wasm_host/src/host.rs | 9 ++++----- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/executor/wasm/src/lib.rs b/executor/wasm/src/lib.rs index 275c254fc2..38a269921b 100644 --- a/executor/wasm/src/lib.rs +++ b/executor/wasm/src/lib.rs @@ -697,11 +697,9 @@ impl ExecutorV2 { let main_purse = contract .named_keys() .get("__v2_main_purse") - .ok_or_else(|| ExecuteError::MainPurseNotFound(vm1_key))? + .ok_or(ExecuteError::MainPurseNotFound(vm1_key))? .into_uref() - .ok_or_else(|| ExecuteError::InvalidKeyForPurse(vm1_key))?; - - println!("{:?}", main_purse); + .ok_or(ExecuteError::InvalidKeyForPurse(vm1_key))?; match system::transfer( &mut tracking_copy, @@ -1309,13 +1307,13 @@ fn get_purse_for_entity( let uref = contract .named_keys() .get(NAME_FOR_V2_CONTRACT_MAIN_PURSE) - .ok_or_else(|| ExecuteError::MainPurseNotFound(entity_key))? + .ok_or(ExecuteError::MainPurseNotFound(entity_key))? .into_uref() - .ok_or_else(|| ExecuteError::InvalidKeyForPurse(entity_key))?; + .ok_or(ExecuteError::InvalidKeyForPurse(entity_key))?; let hash_addr = entity_key .into_hash_addr() - .ok_or_else(|| ExecuteError::EntityNotFound(entity_key))?; + .ok_or(ExecuteError::EntityNotFound(entity_key))?; Ok((EntityAddr::SmartContract(hash_addr), uref)) } diff --git a/executor/wasm_host/src/host.rs b/executor/wasm_host/src/host.rs index fe1d48d6f7..14e00c92ce 100644 --- a/executor/wasm_host/src/host.rs +++ b/executor/wasm_host/src/host.rs @@ -281,8 +281,7 @@ pub fn casper_write( None => { let uref = { let mut address_generator = caller.context().address_generator.write(); - let uref = address_generator.new_uref(AccessRights::NONE); - uref + address_generator.new_uref(AccessRights::NONE) }; // Write payload bytes under the URef as CLValue::Any let cl_value_any = CLValue::from_components(CLType::Any, value.clone()); @@ -619,7 +618,7 @@ pub fn casper_read( }, Ok(Some(StoredValue::AddressableEntity(_))) => { if let Keyspace::AllNamedKeys = keyspace { - let entity_addr = context_to_entity_addr(&caller.context()); + let entity_addr = context_to_entity_addr(caller.context()); let named_keys = caller .context_mut() @@ -1682,7 +1681,7 @@ pub fn casper_upgrade( protocol_version.major, EntityAddr::SmartContract(new_version_hash_addr), ); - if let Err(_) = package.disable_entity_version(previous_hash) { + if package.disable_entity_version(previous_hash).is_err() { return Ok(CALLEE_NOT_CALLABLE); }; @@ -1763,7 +1762,7 @@ pub fn casper_upgrade( protocol_version.major, ContractHash::new(new_version_hash_addr), ); - if let Err(_) = package.disable_contract_version(previous_hash) { + if package.disable_contract_version(previous_hash).is_err() { return Ok(CALLEE_NOT_CALLABLE); }; From fd2bfb91bf646c74845235944ae72e59b7d1dc5a Mon Sep 17 00:00:00 2001 From: Karan Dhareshwar Date: Wed, 17 Sep 2025 09:50:01 -0500 Subject: [PATCH 08/14] Add bytecode indirection for vm2 contracts --- execution_engine/src/runtime/mod.rs | 20 ++++++++++++++++++++ executor/wasm/src/lib.rs | 3 +-- executor/wasm/tests/integration.rs | 8 +++++++- executor/wasm_common/src/error.rs | 4 ++++ executor/wasm_host/src/host.rs | 23 ++++++++++++++--------- executor/wasm_host/src/system.rs | 1 + 6 files changed, 47 insertions(+), 12 deletions(-) diff --git a/execution_engine/src/runtime/mod.rs b/execution_engine/src/runtime/mod.rs index 8b9a78a4a6..c87defd376 100644 --- a/execution_engine/src/runtime/mod.rs +++ b/execution_engine/src/runtime/mod.rs @@ -2144,6 +2144,26 @@ where ByteCode::new(ByteCodeKind::V1CasperWasm, wasm.take_bytes()) } Some(StoredValue::ByteCode(byte_code)) => byte_code, + Some(StoredValue::CLValue(key_as_cl_value)) => { + let byte_code_key = + key_as_cl_value.to_t::().map_err(ExecError::CLValue)?; + if let Key::ByteCode(_) = byte_code_key { + match self.context.read_gs(&byte_code_key)? { + Some(StoredValue::ByteCode(byte_code)) => match byte_code.kind() { + ByteCodeKind::Empty | ByteCodeKind::V1CasperWasm => byte_code, + ByteCodeKind::V2CasperWasm => { + return Err(ExecError::IncompatibleRuntime( + ContractRuntimeTag::VmCasperV2, + )) + } + }, + Some(_) => return Err(ExecError::UnexpectedStoredValueVariant), + None => return Err(ExecError::KeyNotFound(byte_code_key)), + } + } else { + return Err(ExecError::UnexpectedKeyVariant(byte_code_key)); + } + } Some(_) => { return Err(ExecError::InvalidByteCode(ByteCodeHash::new( byte_code_addr, diff --git a/executor/wasm/src/lib.rs b/executor/wasm/src/lib.rs index 38a269921b..2e6317e29c 100644 --- a/executor/wasm/src/lib.rs +++ b/executor/wasm/src/lib.rs @@ -683,13 +683,12 @@ impl ExecutorV2 { // TODO: consult w/ Michal re: charge timing let gas_usage = GasUsage::new(gas_limit, gas_limit); - println!("{:?}", entity_addr); - let runtime_footprint = match tracking_copy .runtime_footprint_by_entity_addr(entity_addr) { Ok(footprint) => footprint, Err(_) => { + println!("1"); return Err(ExecuteError::EntityNotFound(caller_key)); } }; diff --git a/executor/wasm/tests/integration.rs b/executor/wasm/tests/integration.rs index a2c6ef94d2..19876d5d6c 100644 --- a/executor/wasm/tests/integration.rs +++ b/executor/wasm/tests/integration.rs @@ -818,6 +818,7 @@ fn traits() { ); } +#[ignore] #[test] fn upgradable() { let chainspec_config = ChainspecConfig::from_chainspec_path(&*CHAINSPEC_SYMLINK) @@ -983,6 +984,7 @@ fn upgradable() { let _ = state_root_hash; } +#[ignore] #[test] fn backwards_compatibility() { let (global_state, post_state_hash, _temp) = { @@ -1264,7 +1266,11 @@ fn casper_return_writes_to_execution_journal() { } // Verify the key is the contract address - let expected_key = Key::SmartContract(contract_address); + let expected_key = if chainspec_config.core_config.enable_addressable_entity { + Key::AddressableEntity(EntityAddr::SmartContract(contract_address)) + } else { + Key::Hash(contract_address) + }; assert_eq!( ret_transform.key(), &expected_key, diff --git a/executor/wasm_common/src/error.rs b/executor/wasm_common/src/error.rs index 3d11f6fa56..50129a1da7 100644 --- a/executor/wasm_common/src/error.rs +++ b/executor/wasm_common/src/error.rs @@ -31,6 +31,8 @@ pub enum HostResult { MaxMessagesPerBlockExceeded = 8, /// Internal error (for example, failed to acquire a lock) Internal = 9, + /// Error related to CLValues + CLValue = 10, /// An error code not covered by the other variants. Other(u32), } @@ -45,6 +47,7 @@ pub const HOST_ERROR_PAYLOAD_TOO_LONG: u32 = 6; pub const HOST_ERROR_MESSAGE_TOPIC_FULL: u32 = 7; pub const HOST_ERROR_MAX_MESSAGES_PER_BLOCK_EXCEEDED: u32 = 8; pub const HOST_ERROR_INTERNAL: u32 = 9; +pub const HOST_ERROR_CL_VALUE: u32 = 10; impl From for HostResult { fn from(value: u32) -> Self { @@ -59,6 +62,7 @@ impl From for HostResult { HOST_ERROR_MESSAGE_TOPIC_FULL => Self::MessageTopicFull, HOST_ERROR_MAX_MESSAGES_PER_BLOCK_EXCEEDED => Self::MaxMessagesPerBlockExceeded, HOST_ERROR_INTERNAL => Self::Internal, + HOST_ERROR_CL_VALUE => Self::CLValue, other => Self::Other(other), } } diff --git a/executor/wasm_host/src/host.rs b/executor/wasm_host/src/host.rs index b4516d98f7..a3eda0cfd4 100644 --- a/executor/wasm_host/src/host.rs +++ b/executor/wasm_host/src/host.rs @@ -34,11 +34,10 @@ use casper_types::{ contract_messages::{Message, MessageAddr, MessagePayload, MessageTopicSummary}, execution::RetValue, AccessRights, AddressableEntity, BlockGlobalAddr, BlockHash, BlockTime, ByteCode, ByteCodeAddr, - ByteCodeHash, ByteCodeKind, CLType, CLValue, Contract, ContractRuntimeTag, ContractWasm, - ContractWasmHash, Digest, EntityAddr, EntityEntryPoint, EntityKind, EntryPointAccess, - EntryPointAddr, EntryPointPayment, EntryPointType, EntryPointValue, HashAddr, HashAlgorithm, - HostFunctionV2, Key, NamedKeys, Package, PackageHash, ProtocolVersion, Signature, StoredValue, - URef, + ByteCodeHash, ByteCodeKind, CLType, CLValue, Contract, ContractRuntimeTag, ContractWasmHash, + Digest, EntityAddr, EntityEntryPoint, EntityKind, EntryPointAccess, EntryPointAddr, + EntryPointPayment, EntryPointType, EntryPointValue, HashAddr, HashAlgorithm, HostFunctionV2, + Key, NamedKeys, Package, PackageHash, ProtocolVersion, Signature, StoredValue, URef, }; use either::Either; use num_derive::FromPrimitive; @@ -54,8 +53,9 @@ use blake2::{ digest::{Update, VariableOutput}, Blake2bVar, }; -use casper_executor_wasm_common::chain_utils::{ - compute_next_contract_hash_version, compute_wasm_bytecode_hash, +use casper_executor_wasm_common::{ + chain_utils::{compute_next_contract_hash_version, compute_wasm_bytecode_hash}, + error::HOST_ERROR_CL_VALUE, }; use casper_executor_wasm_interface::executor::{ AuctionMethods, ExecuteRequest, MintMethods, SystemMenu, @@ -839,7 +839,6 @@ pub fn casper_create( result_ptr: u32, ) -> VMResult { // In restricted mode, contract creation is not allowed - println!("in create"); if caller.context().sandboxed { return Err(InternalHostError::AttemptWriteInRestricted.into()); } @@ -983,10 +982,16 @@ pub fn casper_create( // 2. Store wasm if !ae_enabled { + let byte_code_key = Key::byte_code_key(ByteCodeAddr::V2CasperWasm(bytecode_hash)); + let byte_code_key_as_cl_value = match CLValue::from_t(byte_code_key) { + Ok(cl_value) => cl_value, + Err(_) => return Ok(HOST_ERROR_CL_VALUE), + }; + metered_write( &mut caller, Key::Hash(bytecode_hash), - StoredValue::ContractWasm(ContractWasm::new(bytecode.clone().take_bytes())), + StoredValue::CLValue(byte_code_key_as_cl_value), )? }; diff --git a/executor/wasm_host/src/system.rs b/executor/wasm_host/src/system.rs index b10db7ed42..da1bc0e06f 100644 --- a/executor/wasm_host/src/system.rs +++ b/executor/wasm_host/src/system.rs @@ -276,6 +276,7 @@ pub fn native_exec( } else if let Key::AddressableEntity(entity_addr) = caller_key { (caller_key, entity_addr) } else { + println!("4"); return Err(ExecuteError::EntityNotFound(caller_key)); }; From d2c1e6d004efa1ce1603cb2c58569f9d4457987e Mon Sep 17 00:00:00 2001 From: Karan Dhareshwar Date: Thu, 18 Sep 2025 09:02:29 -0500 Subject: [PATCH 09/14] Remove prints and address PR feedback --- executor/wasm/src/lib.rs | 6 ++---- executor/wasm_host/src/system.rs | 1 - storage/src/system/mint.rs | 1 - 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/executor/wasm/src/lib.rs b/executor/wasm/src/lib.rs index 2e6317e29c..09750d8b5b 100644 --- a/executor/wasm/src/lib.rs +++ b/executor/wasm/src/lib.rs @@ -62,7 +62,7 @@ const DEFAULT_WASM_ENTRY_POINT: &str = "call"; const DEFAULT_MINT_TRANSFER_GAS_COST: u64 = 1; // NOTE: Require gas while executing and set this to at least 100_000_000 (or use chainspec) -const NAME_FOR_V2_CONTRACT_MAIN_PURSE: &str = "__v2_main_purse"; +const NAME_FOR_V2_CONTRACT_MAIN_PURSE: &str = "__main_purse"; #[derive(Copy, Clone, Debug)] pub enum ExecutorKind { @@ -688,14 +688,13 @@ impl ExecutorV2 { { Ok(footprint) => footprint, Err(_) => { - println!("1"); return Err(ExecuteError::EntityNotFound(caller_key)); } }; let main_purse = contract .named_keys() - .get("__v2_main_purse") + .get(NAME_FOR_V2_CONTRACT_MAIN_PURSE) .ok_or(ExecuteError::MainPurseNotFound(vm1_key))? .into_uref() .ok_or(ExecuteError::InvalidKeyForPurse(vm1_key))?; @@ -742,7 +741,6 @@ impl ExecutorV2 { "Dispatch error while transferring value to the contract's purse", ); - println!("{:?}", error); return Err(ExecuteError::InternalHost( InternalHostError::DispatchSystemContract, )); diff --git a/executor/wasm_host/src/system.rs b/executor/wasm_host/src/system.rs index da1bc0e06f..b10db7ed42 100644 --- a/executor/wasm_host/src/system.rs +++ b/executor/wasm_host/src/system.rs @@ -276,7 +276,6 @@ pub fn native_exec( } else if let Key::AddressableEntity(entity_addr) = caller_key { (caller_key, entity_addr) } else { - println!("4"); return Err(ExecuteError::EntityNotFound(caller_key)); }; diff --git a/storage/src/system/mint.rs b/storage/src/system/mint.rs index 117d312e28..0f5e983953 100644 --- a/storage/src/system/mint.rs +++ b/storage/src/system/mint.rs @@ -244,7 +244,6 @@ pub trait Mint: RuntimeProvider + StorageProvider + SystemProvider { } let addr = match self.get_main_purse() { None => { - println!("foo"); return Err(Error::InvalidURef); } Some(uref) => uref.addr(), From acc600f71b76804678127b832378ed0824da67ec Mon Sep 17 00:00:00 2001 From: Karan Dhareshwar Date: Thu, 18 Sep 2025 10:53:11 -0500 Subject: [PATCH 10/14] Get harness test passing --- executor/wasm/src/lib.rs | 4 +--- executor/wasm/tests/integration.rs | 1 + executor/wasm_host/src/host.rs | 2 +- types/src/lib.rs | 2 +- types/src/runtime_footprint.rs | 4 ++-- 5 files changed, 6 insertions(+), 7 deletions(-) diff --git a/executor/wasm/src/lib.rs b/executor/wasm/src/lib.rs index 09750d8b5b..e5ca6b56b7 100644 --- a/executor/wasm/src/lib.rs +++ b/executor/wasm/src/lib.rs @@ -47,7 +47,7 @@ use casper_types::{ EntryPointPayment, EntryPointType, EntryPointValue, Gas, Groups, InitiatorAddr, Key, MessageLimits, MintCosts, Package, PackageHash, PackageStatus, Parameters, Phase, ProtocolVersion, StorageCosts, StoredValue, TransactionHash, TransactionInvocationTarget, URef, - WasmV2Config, + WasmV2Config, NAME_FOR_V2_CONTRACT_MAIN_PURSE, }; use install::{InstallContractError, InstallContractRequest, InstallContractResult}; use parking_lot::RwLock; @@ -62,8 +62,6 @@ const DEFAULT_WASM_ENTRY_POINT: &str = "call"; const DEFAULT_MINT_TRANSFER_GAS_COST: u64 = 1; // NOTE: Require gas while executing and set this to at least 100_000_000 (or use chainspec) -const NAME_FOR_V2_CONTRACT_MAIN_PURSE: &str = "__main_purse"; - #[derive(Copy, Clone, Debug)] pub enum ExecutorKind { /// Ahead of time compiled Wasm. diff --git a/executor/wasm/tests/integration.rs b/executor/wasm/tests/integration.rs index 19876d5d6c..3c9c438f59 100644 --- a/executor/wasm/tests/integration.rs +++ b/executor/wasm/tests/integration.rs @@ -48,6 +48,7 @@ use casper_types::{ execution::RetValue, system::auction::{BidAddr, BidKind}, BlockHash, BlockTime, Digest, EntityAddr, Key, RuntimeArgs, StoredValue, Timestamp, + NAME_FOR_V2_CONTRACT_MAIN_PURSE, }; use fs_extra::dir; use itertools::Itertools; diff --git a/executor/wasm_host/src/host.rs b/executor/wasm_host/src/host.rs index a3eda0cfd4..30a2c3f327 100644 --- a/executor/wasm_host/src/host.rs +++ b/executor/wasm_host/src/host.rs @@ -64,7 +64,7 @@ use casper_types::contracts::{ContractHash, ContractPackage, ContractPackageHash use keccak_asm::Digest as KeccakDigest; use sha2::Sha256; -const NAME_FOR_V2_CONTRACT_MAIN_PURSE: &str = "__v2_main_purse"; +const NAME_FOR_V2_CONTRACT_MAIN_PURSE: &str = "__main_purse"; #[derive(Debug, Copy, Clone, FromPrimitive, PartialEq)] enum EntityKindTag { diff --git a/types/src/lib.rs b/types/src/lib.rs index 6ff503dc59..5ad71e500e 100644 --- a/types/src/lib.rs +++ b/types/src/lib.rs @@ -182,7 +182,7 @@ pub use package::{ pub use peers_map::{PeerEntry, Peers}; pub use phase::{Phase, PHASE_SERIALIZED_LENGTH}; pub use protocol_version::{ProtocolVersion, VersionCheckResult}; -pub use runtime_footprint::RuntimeFootprint; +pub use runtime_footprint::{RuntimeFootprint, NAME_FOR_V2_CONTRACT_MAIN_PURSE}; pub use semver::{ParseSemVerError, SemVer, SEM_VER_SERIALIZED_LENGTH}; pub use stored_value::{ GlobalStateIdentifier, StoredValue, StoredValueTag, TypeMismatch as StoredValueTypeMismatch, diff --git a/types/src/runtime_footprint.rs b/types/src/runtime_footprint.rs index b7d50ce676..5e4d3288b2 100644 --- a/types/src/runtime_footprint.rs +++ b/types/src/runtime_footprint.rs @@ -17,7 +17,7 @@ use datasize::DataSize; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -const V2_MAIN_PURSE_ENTRY: &str = "__v2_main_purse"; +pub const NAME_FOR_V2_CONTRACT_MAIN_PURSE: &str = "__main_purse"; /// Runtime Address. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] @@ -200,7 +200,7 @@ impl RuntimeFootprint { let main_purse = { match named_keys - .remove(V2_MAIN_PURSE_ENTRY) + .remove(NAME_FOR_V2_CONTRACT_MAIN_PURSE) .map(|key| key.into_uref()) { Some(Some(uref)) => Some(uref), From db2f2a3bf56da591334e1e489c6bbacea00a0768 Mon Sep 17 00:00:00 2001 From: Karan Dhareshwar Date: Tue, 23 Sep 2025 13:14:11 -0500 Subject: [PATCH 11/14] Fix Upgrade logic for VM2 --- executor/wasm/src/install.rs | 6 +- executor/wasm/src/lib.rs | 238 ++++++++++++++++++++++----------- executor/wasm_host/src/host.rs | 20 +-- 3 files changed, 174 insertions(+), 90 deletions(-) diff --git a/executor/wasm/src/install.rs b/executor/wasm/src/install.rs index d0ca864aa4..7feb9f500d 100644 --- a/executor/wasm/src/install.rs +++ b/executor/wasm/src/install.rs @@ -7,7 +7,8 @@ use casper_storage::{ global_state::error::Error as GlobalStateError, AddressGenerator, RuntimeNativeConfig, }; use casper_types::{ - account::AccountHash, execution::Effects, BlockHash, BlockTime, Digest, TransactionHash, + account::AccountHash, execution::Effects, BlockHash, BlockTime, CLValueError, Digest, + TransactionHash, }; use parking_lot::RwLock; use thiserror::Error; @@ -239,4 +240,7 @@ pub enum InstallContractError { #[error("failed building BuildingExecuteRequest: {0}")] FailedBuildingExecuteRequest(&'static str), + + #[error("CLValue error: {0}")] + CLValueError(CLValueError), } diff --git a/executor/wasm/src/lib.rs b/executor/wasm/src/lib.rs index e5ca6b56b7..0f1544fd6b 100644 --- a/executor/wasm/src/lib.rs +++ b/executor/wasm/src/lib.rs @@ -1,7 +1,7 @@ pub mod install; use std::{ - collections::{BTreeSet, VecDeque}, + collections::{BTreeMap, BTreeSet, VecDeque}, sync::Arc, }; @@ -41,13 +41,21 @@ use casper_storage::{ }; use casper_types::{ account::AccountHash, - addressable_entity::{ActionThresholds, AssociatedKeys, EntityEntryPoint}, - bytesrepr, AddressableEntity, AuctionCosts, ByteCode, ByteCodeAddr, ByteCodeHash, ByteCodeKind, - CLType, ContractRuntimeTag, Digest, EntityAddr, EntityKind, EntryPointAccess, EntryPointAddr, - EntryPointPayment, EntryPointType, EntryPointValue, Gas, Groups, InitiatorAddr, Key, - MessageLimits, MintCosts, Package, PackageHash, PackageStatus, Parameters, Phase, - ProtocolVersion, StorageCosts, StoredValue, TransactionHash, TransactionInvocationTarget, URef, - WasmV2Config, NAME_FOR_V2_CONTRACT_MAIN_PURSE, + addressable_entity::{ + ActionThresholds, AssociatedKeys, EntityEntryPoint, EntryPoints as EntityEntryPoints, + }, + bytesrepr, + contracts::{ + ContractHash, ContractPackage, ContractPackageHash, ContractPackageStatus, + EntryPoints as ContractEntryPoints, + }, + AccessRights, AddressableEntity, AuctionCosts, ByteCode, ByteCodeAddr, ByteCodeHash, + ByteCodeKind, CLType, CLValue, Contract, ContractRuntimeTag, ContractWasm, ContractWasmHash, + Digest, EntityAddr, EntityKind, EntryPointAccess, EntryPointAddr, EntryPointPayment, + EntryPointType, EntryPointValue, Gas, Groups, HashAddr, InitiatorAddr, Key, MessageLimits, + MintCosts, NamedKeys, Package, PackageHash, PackageStatus, Parameters, Phase, ProtocolVersion, + StorageCosts, StoredValue, TransactionHash, TransactionInvocationTarget, URef, WasmV2Config, + NAME_FOR_V2_CONTRACT_MAIN_PURSE, }; use install::{InstallContractError, InstallContractRequest, InstallContractResult}; use parking_lot::RwLock; @@ -229,7 +237,7 @@ impl ExecutorV2 { // TODO: Michal: why is this result not evaluated? let _result = get_purse_for_entity(&mut tracking_copy, caller_key); - // 1. Store package hash + let enable_addressable_entity = tracking_copy.enable_addressable_entity(); let smart_contract_addr: [u8; 32] = chain_utils::compute_predictable_address( chain_name.as_bytes(), initiator.value(), @@ -237,52 +245,96 @@ impl ExecutorV2 { seed, ); - let mut smart_contract = Package::new( - Default::default(), - Default::default(), - Groups::default(), - PackageStatus::Unlocked, - ); + // 1. Store package hash + let package_addr: HashAddr = { + address_generator + .write() + .new_uref(AccessRights::NONE) + .addr() + }; let protocol_version = ProtocolVersion::V2_0_0; let protocol_version_major = protocol_version.value().major; - let next_version = smart_contract.next_entity_version_for(protocol_version_major); + if enable_addressable_entity { + let mut smart_contract_package = Package::new( + Default::default(), + Default::default(), + Groups::default(), + PackageStatus::Unlocked, + ); - let entity_version_key = smart_contract.insert_entity_version( - protocol_version_major, - EntityAddr::SmartContract(smart_contract_addr), - ); - debug_assert_eq!(entity_version_key.entity_version(), next_version); + let next_version = + smart_contract_package.next_entity_version_for(protocol_version_major); - let smart_contract_addr = chain_utils::compute_predictable_address( - chain_name.as_bytes(), - initiator.value(), - bytecode_hash, - seed, - ); + let entity_version_key = smart_contract_package.insert_entity_version( + protocol_version_major, + EntityAddr::SmartContract(smart_contract_addr), + ); + debug_assert_eq!(entity_version_key.entity_version(), next_version); - tracking_copy.write( - Key::SmartContract(smart_contract_addr), - StoredValue::SmartContract(smart_contract), - ); + tracking_copy.write( + Key::SmartContract(package_addr), + StoredValue::SmartContract(smart_contract_package), + ); + } else { + let mut contract_package = ContractPackage::new( + Default::default(), + Default::default(), + Default::default(), + Groups::default(), + ContractPackageStatus::Unlocked, + ); - // 2. Store wasm + contract_package.next_contract_version_for(protocol_version_major); + + contract_package.insert_contract_version( + protocol_version_major, + ContractHash::new(smart_contract_addr), + ); + tracking_copy.write( + Key::Hash(package_addr), + StoredValue::ContractPackage(contract_package), + ); + } + + // 2. Store wasm let bytecode = ByteCode::new(ByteCodeKind::V2CasperWasm, wasm_bytes.clone().into()); let bytecode_addr = ByteCodeAddr::V2CasperWasm(bytecode_hash); + let bytecode_key = Key::ByteCode(bytecode_addr); - tracking_copy.write( - Key::ByteCode(bytecode_addr), - StoredValue::ByteCode(bytecode), - ); + tracking_copy.write(bytecode_key, StoredValue::ByteCode(bytecode)); - // 3. Store addressable entity - let addressable_entity_key = - Key::AddressableEntity(EntityAddr::SmartContract(smart_contract_addr)); + // 2.1 Store contract wasm and setup indirection + if !enable_addressable_entity { + let bytecode_key_as_clvalue = + CLValue::from_t(bytecode_key).map_err(InstallContractError::CLValueError)?; - // 3.1 Store entry points first - { + tracking_copy.write( + Key::Hash(bytecode_hash), + StoredValue::CLValue(bytecode_key_as_clvalue), + ); + } + + // TODO: abort(str) as an alternative to trap + let main_purse: URef = match system::create_purse( + &mut tracking_copy, + runtime_native_config.clone(), + transaction_hash, + Arc::clone(&address_generator), + ) { + Ok(uref) => uref, + Err(mint_error) => { + error!(?mint_error, "Failed to create a purse"); + return Err(InstallContractError::SystemContract( + CallError::CalleeTrapped(TrapCode::UnreachableCodeReached), + )); + } + }; + + // 3. Gather entrypoints first. + let entrypoints = { let config = ConfigBuilder::new() .with_gas_limit(gas_limit) .with_memory_limit(self.config.memory_limit) @@ -300,6 +352,8 @@ impl ExecutorV2 { InstallContractError::Execute(ExecuteError::WasmPreparation(wasm_prep_error)) })?; + let mut entrypoints = EntityEntryPoints::new(); + for name in entry_point_names { let entry_point = EntityEntryPoint::new( name.clone(), @@ -310,9 +364,21 @@ impl ExecutorV2 { EntryPointPayment::Caller, ); + entrypoints.add_entry_point(entry_point); + } + + entrypoints + }; + + if enable_addressable_entity { + // 3. Store addressable entity + let addressable_entity_key = + Key::AddressableEntity(EntityAddr::SmartContract(smart_contract_addr)); + + for entrypoint in entrypoints.take_entry_points() { let entry_point_addr = EntryPointAddr::new_v1_entry_point_addr( EntityAddr::SmartContract(smart_contract_addr), - &name, + entrypoint.name(), ) .map_err(|err| { InstallContractError::GlobalState(GlobalStateError::BytesRepr(err)) @@ -322,41 +388,49 @@ impl ExecutorV2 { tracking_copy.write( entry_point_key, - StoredValue::EntryPoint(EntryPointValue::V1CasperVm(entry_point)), + StoredValue::EntryPoint(EntryPointValue::V1CasperVm(entrypoint)), ) } - } - // TODO: abort(str) as an alternative to trap - let main_purse: URef = match system::create_purse( - &mut tracking_copy, - runtime_native_config.clone(), - transaction_hash, - Arc::clone(&address_generator), - ) { - Ok(uref) => uref, - Err(mint_error) => { - error!(?mint_error, "Failed to create a purse"); - return Err(InstallContractError::SystemContract( - CallError::CalleeTrapped(TrapCode::UnreachableCodeReached), - )); - } - }; + // 3.1 Store entry points first + let addressable_entity = AddressableEntity::new( + PackageHash::new(smart_contract_addr), + ByteCodeHash::new(bytecode_hash), + ProtocolVersion::V2_0_0, + main_purse, + AssociatedKeys::default(), + ActionThresholds::default(), + EntityKind::SmartContract(ContractRuntimeTag::VmCasperV2), + ); - let addressable_entity = AddressableEntity::new( - PackageHash::new(smart_contract_addr), - ByteCodeHash::new(bytecode_hash), - ProtocolVersion::V2_0_0, - main_purse, - AssociatedKeys::default(), - ActionThresholds::default(), - EntityKind::SmartContract(ContractRuntimeTag::VmCasperV2), - ); + tracking_copy.write( + addressable_entity_key, + StoredValue::AddressableEntity(addressable_entity), + ); + } else { + let contract_entrypoints = ContractEntryPoints::from(entrypoints); + let named_keys = { + let mut ret = BTreeMap::new(); + ret.insert( + NAME_FOR_V2_CONTRACT_MAIN_PURSE.to_string(), + Key::URef(main_purse), + ); + NamedKeys::from(ret) + }; - tracking_copy.write( - addressable_entity_key, - StoredValue::AddressableEntity(addressable_entity), - ); + let contract = Contract::new( + ContractPackageHash::new(package_addr), + ContractWasmHash::new(bytecode_hash), + named_keys, + contract_entrypoints, + protocol_version, + ); + + tracking_copy.write( + Key::Hash(smart_contract_addr), + StoredValue::Contract(contract), + ) + } let ctor_gas_usage = match entry_point { Some(entry_point_name) => { @@ -925,16 +999,20 @@ impl ExecutorV2 { cache: final_tracking_copy.cache(), messages: final_tracking_copy.messages(), }), - Err(VMError::Trap(trap_code)) => Ok(ExecuteResult { - host_error: Some(CallError::CalleeTrapped(trap_code)), - output: None, - gas_usage, - effects: initial_tracking_copy.effects(), - cache: initial_tracking_copy.cache(), - messages: initial_tracking_copy.messages(), - }), + Err(VMError::Trap(trap_code)) => { + println!("{:?}", trap_code); + Ok(ExecuteResult { + host_error: Some(CallError::CalleeTrapped(trap_code)), + output: None, + gas_usage, + effects: initial_tracking_copy.effects(), + cache: initial_tracking_copy.cache(), + messages: initial_tracking_copy.messages(), + }) + } Err(VMError::Export(export_error)) => { error!(?export_error, "export error"); + println!("{:?}", export_error); Ok(ExecuteResult { host_error: Some(CallError::NotCallable), output: None, diff --git a/executor/wasm_host/src/host.rs b/executor/wasm_host/src/host.rs index 30a2c3f327..1742c5433f 100644 --- a/executor/wasm_host/src/host.rs +++ b/executor/wasm_host/src/host.rs @@ -1061,8 +1061,6 @@ pub fn casper_create( ProtocolVersion::V2_0_0, ); - println!("{:?}", Key::Hash(smart_contract_addr)); - metered_write( &mut caller, Key::Hash(smart_contract_addr), @@ -1673,9 +1671,9 @@ pub fn casper_upgrade( other => panic!("should be account or addressable entity but got {other:?}"), }; - println!("A {:?}", callee_addressable_entity_key); + println!("{}", callee_addressable_entity_key); - match caller + let new_version_addr = match caller .context_mut() .tracking_copy .read(&callee_addressable_entity_key) @@ -1756,12 +1754,14 @@ pub fn casper_upgrade( entity_key, StoredValue::AddressableEntity(entity), )?; + + new_version_hash_addr } None => return Ok(CALLEE_NOT_CALLABLE), } } Ok(Some(StoredValue::Contract(contract))) => { - println!("foo"); + println!("retrieving contract"); let package_hash = contract.contract_package_hash(); let package_key = Key::Hash(package_hash.value()); @@ -1780,7 +1780,7 @@ pub fn casper_upgrade( }; if package.is_locked() { - return Ok(CALLEE_NOT_CALLABLE); + return Ok(7); } match package.current_contract_hash() { @@ -1798,7 +1798,7 @@ pub fn casper_upgrade( ContractHash::new(new_version_hash_addr), ); if package.disable_contract_version(previous_hash).is_err() { - return Ok(CALLEE_NOT_CALLABLE); + return Ok(7); }; metered_write( @@ -1830,8 +1830,10 @@ pub fn casper_upgrade( let smart_contract = Key::Hash(new_version_hash_addr); metered_write(&mut caller, smart_contract, StoredValue::Contract(entity))?; + + new_version_hash_addr } - None => return Ok(CALLEE_NOT_CALLABLE), + None => return Ok(7), } } Ok(Some(other_entity)) => { @@ -1865,7 +1867,7 @@ pub fn casper_upgrade( .with_caller_key(caller.context().callee) .with_gas_limit(gas_limit) .with_execution_kind(ExecutionKind::Stored { - address: smart_contract_addr, + address: new_version_addr, entry_point: entry_point_name.clone(), }) .with_input(input_data.unwrap_or_default()) From a0e32e32a020c65b4b36ca0d1b9f4e38071cb3e8 Mon Sep 17 00:00:00 2001 From: Karan Dhareshwar Date: Thu, 25 Sep 2025 09:11:47 -0500 Subject: [PATCH 12/14] run make lint --- executor/wasm/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/executor/wasm/src/lib.rs b/executor/wasm/src/lib.rs index 0f1544fd6b..f9dfddd32b 100644 --- a/executor/wasm/src/lib.rs +++ b/executor/wasm/src/lib.rs @@ -50,10 +50,10 @@ use casper_types::{ EntryPoints as ContractEntryPoints, }, AccessRights, AddressableEntity, AuctionCosts, ByteCode, ByteCodeAddr, ByteCodeHash, - ByteCodeKind, CLType, CLValue, Contract, ContractRuntimeTag, ContractWasm, ContractWasmHash, - Digest, EntityAddr, EntityKind, EntryPointAccess, EntryPointAddr, EntryPointPayment, - EntryPointType, EntryPointValue, Gas, Groups, HashAddr, InitiatorAddr, Key, MessageLimits, - MintCosts, NamedKeys, Package, PackageHash, PackageStatus, Parameters, Phase, ProtocolVersion, + ByteCodeKind, CLType, CLValue, Contract, ContractRuntimeTag, ContractWasmHash, Digest, + EntityAddr, EntityKind, EntryPointAccess, EntryPointAddr, EntryPointPayment, EntryPointType, + EntryPointValue, Gas, Groups, HashAddr, InitiatorAddr, Key, MessageLimits, MintCosts, + NamedKeys, Package, PackageHash, PackageStatus, Parameters, Phase, ProtocolVersion, StorageCosts, StoredValue, TransactionHash, TransactionInvocationTarget, URef, WasmV2Config, NAME_FOR_V2_CONTRACT_MAIN_PURSE, }; From 74eeb455ec3f8edc3351e2bf72400b9d08e072d7 Mon Sep 17 00:00:00 2001 From: Karan Dhareshwar Date: Thu, 25 Sep 2025 11:33:49 -0500 Subject: [PATCH 13/14] All vm2 tests passing --- executor/wasm/src/lib.rs | 188 ++++++++++++++---------- executor/wasm/tests/integration.rs | 1 - executor/wasm_common/src/error.rs | 17 ++- executor/wasm_host/src/host.rs | 151 ++++++++++++------- executor/wasm_host/src/system.rs | 8 +- executor/wasm_interface/src/executor.rs | 2 +- 6 files changed, 236 insertions(+), 131 deletions(-) diff --git a/executor/wasm/src/lib.rs b/executor/wasm/src/lib.rs index f9dfddd32b..be4671e6bc 100644 --- a/executor/wasm/src/lib.rs +++ b/executor/wasm/src/lib.rs @@ -12,6 +12,7 @@ use casper_execution_engine::{ }; use casper_executor_wasm_common::{ chain_utils, + chain_utils::compute_next_contract_hash_version, error::{CallError, TrapCode}, flags::ReturnFlags, }; @@ -53,9 +54,9 @@ use casper_types::{ ByteCodeKind, CLType, CLValue, Contract, ContractRuntimeTag, ContractWasmHash, Digest, EntityAddr, EntityKind, EntryPointAccess, EntryPointAddr, EntryPointPayment, EntryPointType, EntryPointValue, Gas, Groups, HashAddr, InitiatorAddr, Key, MessageLimits, MintCosts, - NamedKeys, Package, PackageHash, PackageStatus, Parameters, Phase, ProtocolVersion, - StorageCosts, StoredValue, TransactionHash, TransactionInvocationTarget, URef, WasmV2Config, - NAME_FOR_V2_CONTRACT_MAIN_PURSE, + NamedKeys, Package, PackageAddr, PackageHash, PackageStatus, Parameters, Phase, + ProtocolVersion, StorageCosts, StoredValue, TransactionHash, TransactionInvocationTarget, URef, + WasmV2Config, NAME_FOR_V2_CONTRACT_MAIN_PURSE, }; use install::{InstallContractError, InstallContractRequest, InstallContractResult}; use parking_lot::RwLock; @@ -238,25 +239,19 @@ impl ExecutorV2 { let _result = get_purse_for_entity(&mut tracking_copy, caller_key); let enable_addressable_entity = tracking_copy.enable_addressable_entity(); - let smart_contract_addr: [u8; 32] = chain_utils::compute_predictable_address( + + // 1. Store package hash + let package_addr = chain_utils::compute_predictable_address( chain_name.as_bytes(), initiator.value(), bytecode_hash, seed, ); - // 1. Store package hash - let package_addr: HashAddr = { - address_generator - .write() - .new_uref(AccessRights::NONE) - .addr() - }; - let protocol_version = ProtocolVersion::V2_0_0; let protocol_version_major = protocol_version.value().major; - if enable_addressable_entity { + let smart_contract_addr = if enable_addressable_entity { let mut smart_contract_package = Package::new( Default::default(), Default::default(), @@ -267,6 +262,9 @@ impl ExecutorV2 { let next_version = smart_contract_package.next_entity_version_for(protocol_version_major); + let smart_contract_addr = + compute_next_contract_hash_version(package_addr, next_version); + let entity_version_key = smart_contract_package.insert_entity_version( protocol_version_major, EntityAddr::SmartContract(smart_contract_addr), @@ -277,6 +275,7 @@ impl ExecutorV2 { Key::SmartContract(package_addr), StoredValue::SmartContract(smart_contract_package), ); + smart_contract_addr } else { let mut contract_package = ContractPackage::new( Default::default(), @@ -286,7 +285,10 @@ impl ExecutorV2 { ContractPackageStatus::Unlocked, ); - contract_package.next_contract_version_for(protocol_version_major); + let next_version = contract_package.next_contract_version_for(protocol_version_major); + + let smart_contract_addr = + compute_next_contract_hash_version(package_addr, next_version); contract_package.insert_contract_version( protocol_version_major, @@ -297,7 +299,8 @@ impl ExecutorV2 { Key::Hash(package_addr), StoredValue::ContractPackage(contract_package), ); - } + smart_contract_addr + }; // 2. Store wasm let bytecode = ByteCode::new(ByteCodeKind::V2CasperWasm, wasm_bytes.clone().into()); @@ -394,7 +397,7 @@ impl ExecutorV2 { // 3.1 Store entry points first let addressable_entity = AddressableEntity::new( - PackageHash::new(smart_contract_addr), + PackageHash::new(package_addr), ByteCodeHash::new(bytecode_hash), ProtocolVersion::V2_0_0, main_purse, @@ -439,7 +442,7 @@ impl ExecutorV2 { .with_initiator(initiator) .with_caller_key(caller_key) .with_execution_kind(ExecutionKind::Stored { - address: smart_contract_addr, + address: package_addr, entry_point: entry_point_name, }) .with_gas_limit(gas_limit) @@ -496,7 +499,7 @@ impl ExecutorV2 { match state_provider.commit_effects(state_root_hash, effects.clone()) { Ok(post_state_hash) => Ok(InstallContractResult { - smart_contract_addr, + smart_contract_addr: package_addr, gas_usage: ctor_gas_usage, effects, post_state_hash, @@ -581,14 +584,14 @@ impl ExecutorV2 { if let ExecutionKind::SessionBytes(wasm_bytes) = &execution_kind { (wasm_bytes.clone(), DEFAULT_WASM_ENTRY_POINT) } else if let ExecutionKind::Stored { - address: smart_contract_addr, + address: contract_package_addr, entry_point, } = &execution_kind { let smart_contract_key = Key::SmartContract(*smart_contract_addr); let vm1_key = Key::Hash(*smart_contract_addr); - let mut contract = tracking_copy + let mut contract = match tracking_copy .read_first(&[&vm1_key, &smart_contract_key]) .map_err(|read_error| { error!( @@ -596,32 +599,61 @@ impl ExecutorV2 { [&vm1_key, &smart_contract_key] ); ExecuteError::InternalHost(InternalHostError::TrackingCopy) - })?; - - if let Some(StoredValue::SmartContract(smart_contract_package)) = &contract { - let enabled_versions = smart_contract_package.enabled_versions(); - let maybe_contract_hash = enabled_versions.latest(); - let contract_hash = if let Some(contract_hash) = maybe_contract_hash { - contract_hash - } else { - //#TODO this probably should not be a node stopping error? - error!( + })? { + Some(StoredValue::SmartContract(smart_contract_package)) => { + let enabled_versions = smart_contract_package.enabled_versions(); + let maybe_contract_hash = enabled_versions.latest(); + let contract_hash = if let Some(contract_hash) = maybe_contract_hash { + contract_hash + } else { + //#TODO this probably should not be a node stopping error? + error!( "Couldn't find an active version for smart contract under path {:?}", [&vm1_key, &smart_contract_key] ); - return Err(ExecuteError::NoActiveContract(smart_contract_key)); - }; - let entity_addr = EntityAddr::SmartContract(contract_hash.value()); - let latest_version_key = Key::AddressableEntity(entity_addr); - assert_eq!(&entity_addr.value(), smart_contract_addr); - let new_contract = - tracking_copy - .read(&latest_version_key) - .map_err(|read_err| { - error!("Error when fetching smart contract {latest_version_key}. Details {read_err}"); - ExecuteError::InternalHost(InternalHostError::TrackingCopy) - })?; - contract = new_contract; + return Err(ExecuteError::NoActiveContract(smart_contract_key)); + }; + let entity_addr = EntityAddr::SmartContract(contract_hash.value()); + let latest_version_key = Key::AddressableEntity(entity_addr); + assert_eq!(&entity_addr.value(), contract_package_addr); + let new_contract = + tracking_copy + .read(&latest_version_key) + .map_err(|read_err| { + error!("Error when fetching smart contract {latest_version_key}. Details {read_err}"); + ExecuteError::InternalHost(InternalHostError::TrackingCopy) + })?; + + new_contract + } + Some(StoredValue::ContractPackage(smart_contract_package)) => { + let contract_hash = if let Some((_, contract_hash)) = + smart_contract_package.enabled_versions().iter().last() + { + *contract_hash + } else { + //#TODO this probably should not be a node stopping error? + error!( + "Couldn't find an active version for smart contract under path {:?}", + [&vm1_key, &smart_contract_key] + ); + return Err(ExecuteError::NoActiveContract(smart_contract_key)); + }; + let latest_version_key = Key::Hash(contract_hash.value()); + let new_contract = + tracking_copy + .read(&latest_version_key) + .map_err(|read_err| { + error!("Error when fetching smart contract {latest_version_key}. Details {read_err}"); + ExecuteError::InternalHost(InternalHostError::TrackingCopy) + })?; + + new_contract + } + Some(_) | None => { + println!("none case"); + None + } }; match contract { @@ -640,7 +672,7 @@ impl ExecutorV2 { self.execution_engine_v1.config().protocol_version(), ); - let entity_addr = EntityAddr::SmartContract(*smart_contract_addr); + let entity_addr = EntityAddr::SmartContract(*contract_package_addr); return self.execute_vm1_wasm_byte_code( initiator, @@ -830,7 +862,7 @@ impl ExecutorV2 { self.execution_engine_v1.config().protocol_version(), ); - let entity_addr = EntityAddr::SmartContract(*smart_contract_addr); + let entity_addr = EntityAddr::SmartContract(*contract_package_addr); return self.execute_vm1_wasm_byte_code( initiator, @@ -853,7 +885,7 @@ impl ExecutorV2 { } None => { error!( - smart_contract_addr = base16::encode_lower(&smart_contract_addr), + smart_contract_addr = base16::encode_lower(&contract_package_addr), ?execution_kind, "No contract code found", ); @@ -875,13 +907,13 @@ impl ExecutorV2 { // Derive callee key from the execution target. let callee_key = match &execution_kind { ExecutionKind::Stored { - address: smart_contract_addr, + address: smart_contract_package_addr, .. } => { if initial_tracking_copy.enable_addressable_entity() { - Key::AddressableEntity(EntityAddr::SmartContract(*smart_contract_addr)) + Key::SmartContract(*smart_contract_package_addr) } else { - Key::Hash(*smart_contract_addr) + Key::Hash(*smart_contract_package_addr) } } ExecutionKind::SessionBytes(_wasm_bytes) => Key::Account(initiator), @@ -999,20 +1031,16 @@ impl ExecutorV2 { cache: final_tracking_copy.cache(), messages: final_tracking_copy.messages(), }), - Err(VMError::Trap(trap_code)) => { - println!("{:?}", trap_code); - Ok(ExecuteResult { - host_error: Some(CallError::CalleeTrapped(trap_code)), - output: None, - gas_usage, - effects: initial_tracking_copy.effects(), - cache: initial_tracking_copy.cache(), - messages: initial_tracking_copy.messages(), - }) - } + Err(VMError::Trap(trap_code)) => Ok(ExecuteResult { + host_error: Some(CallError::CalleeTrapped(trap_code)), + output: None, + gas_usage, + effects: initial_tracking_copy.effects(), + cache: initial_tracking_copy.cache(), + messages: initial_tracking_copy.messages(), + }), Err(VMError::Export(export_error)) => { error!(?export_error, "export error"); - println!("{:?}", export_error); Ok(ExecuteResult { host_error: Some(CallError::NotCallable), output: None, @@ -1310,12 +1338,12 @@ impl Executor for ExecutorV2 { fn get_purse_for_entity( tracking_copy: &mut TrackingCopy, - entity_key: Key, + caller_key: Key, ) -> Result<(EntityAddr, URef), ExecuteError> { let stored_value = tracking_copy - .read(&entity_key) + .read(&caller_key) .map_err(|_error| ExecuteError::InternalHost(InternalHostError::TrackingCopy))? - .ok_or(ExecuteError::EntityNotFound(entity_key))?; + .ok_or(ExecuteError::EntityNotFound(caller_key))?; match stored_value { StoredValue::CLValue(addressable_entity_key) => { let key = addressable_entity_key.into_t::().map_err(|cl_error| { @@ -1355,8 +1383,8 @@ fn get_purse_for_entity( contract_hash } else { //#TODO this probably should not be a node stopping error? - error!("Couldn't find an active version for smart contract {entity_key}"); - return Err(ExecuteError::NoActiveContract(entity_key)); + error!("Couldn't find an active version for smart contract {caller_key}"); + return Err(ExecuteError::NoActiveContract(caller_key)); }; let entity_addr = EntityAddr::SmartContract(contract_hash.value()); @@ -1376,17 +1404,29 @@ fn get_purse_for_entity( Ok((entity_addr, addressable_entity.main_purse())) } - StoredValue::Contract(contract) => { - let uref = contract - .named_keys() + StoredValue::ContractPackage(contract_package) => { + let contract_hash = match contract_package.enabled_versions().last_key_value() { + Some((_, contract_hash)) => Key::Hash(contract_hash.value()), + None => return Err(ExecuteError::NoActiveContract(caller_key)), + }; + + let named_keys = tracking_copy + .read(&contract_hash) + .map_err(|_error| ExecuteError::InternalHost(InternalHostError::TrackingCopy))? + .ok_or(ExecuteError::EntityNotFound(contract_hash))? + .into_contract() + .map(|contract| contract.take_named_keys()) + .ok_or(ExecuteError::InvalidKeyForPurse(contract_hash))?; + + let uref = named_keys .get(NAME_FOR_V2_CONTRACT_MAIN_PURSE) - .ok_or(ExecuteError::MainPurseNotFound(entity_key))? + .ok_or(ExecuteError::MainPurseNotFound(caller_key))? .into_uref() - .ok_or(ExecuteError::InvalidKeyForPurse(entity_key))?; + .ok_or(ExecuteError::InvalidKeyForPurse(caller_key))?; - let hash_addr = entity_key - .into_hash_addr() - .ok_or(ExecuteError::EntityNotFound(entity_key))?; + let hash_addr = contract_hash + .into_entity_hash_addr() + .ok_or(ExecuteError::EntityNotFound(contract_hash))?; Ok((EntityAddr::SmartContract(hash_addr), uref)) } diff --git a/executor/wasm/tests/integration.rs b/executor/wasm/tests/integration.rs index 3c9c438f59..0d2e94cbb2 100644 --- a/executor/wasm/tests/integration.rs +++ b/executor/wasm/tests/integration.rs @@ -819,7 +819,6 @@ fn traits() { ); } -#[ignore] #[test] fn upgradable() { let chainspec_config = ChainspecConfig::from_chainspec_path(&*CHAINSPEC_SYMLINK) diff --git a/executor/wasm_common/src/error.rs b/executor/wasm_common/src/error.rs index 50129a1da7..ac5f9e52c7 100644 --- a/executor/wasm_common/src/error.rs +++ b/executor/wasm_common/src/error.rs @@ -33,6 +33,14 @@ pub enum HostResult { Internal = 9, /// Error related to CLValues CLValue = 10, + /// No active version found in the package. + NoActiveContract = 11, + /// No byte code was found for execution. + CodeNotFound = 12, + /// Entity not found. + EntityNotFound = 13, + /// Package associated with the package was locked. + LockedPackage = 14, /// An error code not covered by the other variants. Other(u32), } @@ -48,6 +56,10 @@ pub const HOST_ERROR_MESSAGE_TOPIC_FULL: u32 = 7; pub const HOST_ERROR_MAX_MESSAGES_PER_BLOCK_EXCEEDED: u32 = 8; pub const HOST_ERROR_INTERNAL: u32 = 9; pub const HOST_ERROR_CL_VALUE: u32 = 10; +pub const HOST_NO_ACTIVE_CONTRACT: u32 = 11; +pub const HOST_CODE_NOT_FOUND: u32 = 12; +pub const HOST_ENTITY_NOT_FOUND: u32 = 13; +pub const HOST_LOCKED_PACKAGE: u32 = 14; impl From for HostResult { fn from(value: u32) -> Self { @@ -63,6 +75,10 @@ impl From for HostResult { HOST_ERROR_MAX_MESSAGES_PER_BLOCK_EXCEEDED => Self::MaxMessagesPerBlockExceeded, HOST_ERROR_INTERNAL => Self::Internal, HOST_ERROR_CL_VALUE => Self::CLValue, + HOST_NO_ACTIVE_CONTRACT => Self::NoActiveContract, + HOST_CODE_NOT_FOUND => Self::CodeNotFound, + HOST_ENTITY_NOT_FOUND => Self::EntityNotFound, + HOST_LOCKED_PACKAGE => Self::LockedPackage, other => Self::Other(other), } } @@ -113,7 +129,6 @@ pub const CALLEE_TRAPPED: u32 = 2; pub const CALLEE_GAS_DEPLETED: u32 = 3; pub const CALLEE_NOT_CALLABLE: u32 = 4; pub const CALLEE_API_ERROR: u32 = 5; - /// Represents the result of a host function call. /// /// 0 is used as a success. diff --git a/executor/wasm_host/src/host.rs b/executor/wasm_host/src/host.rs index 1742c5433f..c91029bb42 100644 --- a/executor/wasm_host/src/host.rs +++ b/executor/wasm_host/src/host.rs @@ -55,7 +55,7 @@ use blake2::{ }; use casper_executor_wasm_common::{ chain_utils::{compute_next_contract_hash_version, compute_wasm_bytecode_hash}, - error::HOST_ERROR_CL_VALUE, + error::{HOST_ERROR_CL_VALUE, HOST_LOCKED_PACKAGE, HOST_NO_ACTIVE_CONTRACT}, }; use casper_executor_wasm_interface::executor::{ AuctionMethods, ExecuteRequest, MintMethods, SystemMenu, @@ -921,12 +921,7 @@ pub fn casper_create( let callee_addr = context_to_entity_addr(caller.context()).value(); - let package_addr: HashAddr = { - let mut address_generator = caller.context().address_generator.write(); - address_generator.new_uref(AccessRights::NONE).addr() - }; - - let smart_contract_addr: HashAddr = chain_utils::compute_predictable_address( + let package_addr: HashAddr = chain_utils::compute_predictable_address( caller.context().chain_name.as_bytes(), callee_addr, bytecode_hash, @@ -938,31 +933,45 @@ pub fn casper_create( let ae_enabled = caller.context().tracking_copy.enable_addressable_entity(); - let (smart_contract_package_key, smart_contract_package_as_stored_value) = if ae_enabled { - // 1. Store package hash - let mut smart_contract_package = Package::default(); + let (smart_contract_package_key, smart_contract_package_as_stored_value, smart_contract_addr) = + if ae_enabled { + // 1. Store package hash + let mut smart_contract_package = Package::default(); - smart_contract_package.insert_entity_version( - protocol_version_major, - EntityAddr::SmartContract(smart_contract_addr), - ); + let next_version = + smart_contract_package.next_entity_version_for(protocol_version_major); + let smart_contract_addr = + compute_next_contract_hash_version(package_addr, next_version); - ( - Key::SmartContract(package_addr), - StoredValue::SmartContract(smart_contract_package), - ) - } else { - let mut smart_contract_package = ContractPackage::default(); - smart_contract_package.insert_contract_version( - protocol_version_major, - ContractHash::new(smart_contract_addr), - ); + smart_contract_package.insert_entity_version( + protocol_version_major, + EntityAddr::SmartContract(smart_contract_addr), + ); - ( - Key::Hash(package_addr), - StoredValue::ContractPackage(smart_contract_package), - ) - }; + ( + Key::SmartContract(package_addr), + StoredValue::SmartContract(smart_contract_package), + smart_contract_addr, + ) + } else { + let mut smart_contract_package = ContractPackage::default(); + + let next_version = + smart_contract_package.next_contract_version_for(protocol_version_major); + let smart_contract_addr = + compute_next_contract_hash_version(package_addr, next_version); + + smart_contract_package.insert_contract_version( + protocol_version_major, + ContractHash::new(smart_contract_addr), + ); + + ( + Key::Hash(package_addr), + StoredValue::ContractPackage(smart_contract_package), + smart_contract_addr, + ) + }; if caller .context_mut() @@ -1024,7 +1033,7 @@ pub fn casper_create( let addressable_entity_key = Key::AddressableEntity(entity_addr); let addressable_entity = AddressableEntity::new( - PackageHash::new(smart_contract_addr), + PackageHash::new(package_addr), ByteCodeHash::new(bytecode_hash), ProtocolVersion::V2_0_0, main_purse, @@ -1032,7 +1041,6 @@ pub fn casper_create( ActionThresholds::default(), EntityKind::SmartContract(ContractRuntimeTag::VmCasperV2), ); - println!("bar"); metered_write( &mut caller, @@ -1081,7 +1089,7 @@ pub fn casper_create( .with_caller_key(caller.context().callee) .with_gas_limit(gas_limit) .with_execution_kind(ExecutionKind::Stored { - address: smart_contract_addr, + address: package_addr, entry_point: entry_point_name.clone(), }) .with_input(input_data.unwrap_or_default()) @@ -1140,7 +1148,7 @@ pub fn casper_create( }; let create_result = CreateResult { - package_address: smart_contract_addr, + package_address: package_addr, }; let create_result_bytes = safe_transmute::transmute_one_to_bytes(&create_result); @@ -1505,12 +1513,15 @@ pub fn casper_env_balance( } } } - Ok(Some(StoredValue::Contract(contract))) => { - match contract.named_keys().get(NAME_FOR_V2_CONTRACT_MAIN_PURSE) { - Some(Key::URef(uref)) => Either::Left(*uref), - None | Some(_) => { - // Not found, balance is 0 - return Ok(HOST_ERROR_SUCCESS); + Ok(Some(StoredValue::ContractPackage(contract))) => { + match contract.versions().last_key_value() { + Some((_, contract_hash)) => Either::Right(Key::Hash(contract_hash.value())), + None => { + warn!( + ?smart_contract_key, + "Unable to find latest addressable entity hash for contract" + ); + return Ok(HOST_ERROR_NOT_FOUND); } } } @@ -1545,6 +1556,15 @@ pub fn casper_env_balance( Ok(Some(StoredValue::AddressableEntity(addressable_entity))) => { addressable_entity.main_purse() } + Ok(Some(StoredValue::Contract(contract))) => { + match contract.named_keys().get(NAME_FOR_V2_CONTRACT_MAIN_PURSE) { + Some(Key::URef(uref)) => *uref, + None | Some(_) => { + // Not found, balance is 0 + return Ok(HOST_ERROR_SUCCESS); + } + } + } Ok(Some(other_entity)) => { panic!("Unexpected entity type: {other_entity:?}") } @@ -1635,7 +1655,40 @@ pub fn casper_upgrade( error!("Account upgrade is not possible"); return Ok(CALLEE_NOT_CALLABLE); } - Key::Hash(contract_addr) => (contract_addr, Key::Hash(contract_addr)), + Key::Hash(contract_package_addr) => { + let smart_contract_package_key = Key::Hash(contract_package_addr); + match caller + .context_mut() + .tracking_copy + .read(&smart_contract_package_key) + { + Ok(Some(StoredValue::ContractPackage(smart_contract_package))) => { + match smart_contract_package.versions().last_key_value() { + Some((_, hash)) => { + let key = Key::Hash(hash.value()); + (contract_package_addr, key) + } + None => { + warn!( + ?smart_contract_package_key, + "Unable to find latest addressable entity hash for contract" + ); + return Ok(CALLEE_NOT_CALLABLE); + } + } + } + Ok(Some(other)) => panic!("should be smart contract but got {other:?}"), + Ok(None) => return Ok(CALLEE_NOT_CALLABLE), + Err(error) => { + error!( + ?error, + ?smart_contract_package_key, + "Error while reading from storage; aborting" + ); + panic!("Error while reading from storage") + } + } + } addressable_entity_key @ Key::SmartContract(smart_contract_addr) => { let smart_contract_key = addressable_entity_key; match caller.context_mut().tracking_copy.read(&smart_contract_key) { @@ -1670,10 +1723,7 @@ pub fn casper_upgrade( } other => panic!("should be account or addressable entity but got {other:?}"), }; - - println!("{}", callee_addressable_entity_key); - - let new_version_addr = match caller + match caller .context_mut() .tracking_copy .read(&callee_addressable_entity_key) @@ -1754,14 +1804,11 @@ pub fn casper_upgrade( entity_key, StoredValue::AddressableEntity(entity), )?; - - new_version_hash_addr } None => return Ok(CALLEE_NOT_CALLABLE), } } Ok(Some(StoredValue::Contract(contract))) => { - println!("retrieving contract"); let package_hash = contract.contract_package_hash(); let package_key = Key::Hash(package_hash.value()); @@ -1780,7 +1827,7 @@ pub fn casper_upgrade( }; if package.is_locked() { - return Ok(7); + return Ok(HOST_LOCKED_PACKAGE); } match package.current_contract_hash() { @@ -1798,7 +1845,7 @@ pub fn casper_upgrade( ContractHash::new(new_version_hash_addr), ); if package.disable_contract_version(previous_hash).is_err() { - return Ok(7); + return Ok(HOST_ERROR_INVALID_DATA); }; metered_write( @@ -1830,10 +1877,8 @@ pub fn casper_upgrade( let smart_contract = Key::Hash(new_version_hash_addr); metered_write(&mut caller, smart_contract, StoredValue::Contract(entity))?; - - new_version_hash_addr } - None => return Ok(7), + None => return Ok(HOST_NO_ACTIVE_CONTRACT), } } Ok(Some(other_entity)) => { @@ -1867,7 +1912,7 @@ pub fn casper_upgrade( .with_caller_key(caller.context().callee) .with_gas_limit(gas_limit) .with_execution_kind(ExecutionKind::Stored { - address: new_version_addr, + address: smart_contract_addr, entry_point: entry_point_name.clone(), }) .with_input(input_data.unwrap_or_default()) diff --git a/executor/wasm_host/src/system.rs b/executor/wasm_host/src/system.rs index b10db7ed42..404917e3f2 100644 --- a/executor/wasm_host/src/system.rs +++ b/executor/wasm_host/src/system.rs @@ -264,7 +264,13 @@ pub fn native_exec( let (caller_key, entity_addr) = if let Key::Account(account_hash) = caller_key { (caller_key, EntityAddr::Account(account_hash.value())) } else if let Key::Hash(contract_hash_addr) = caller_key { - (caller_key, EntityAddr::SmartContract(contract_hash_addr)) + match tracking_copy.get_package(contract_hash_addr) { + Ok(package) => match package.enabled_versions().latest() { + Some(entity_addr) => (Key::Hash(entity_addr.value()), *entity_addr), + None => return Err(ExecuteError::NoActiveContract(caller_key)), + }, + Err(tce) => return Err(ExecuteError::Api(tce.to_string())), + } } else if let Key::SmartContract(package_addr) = caller_key { match tracking_copy.get_package(package_addr) { Ok(package) => match package.enabled_versions().latest() { diff --git a/executor/wasm_interface/src/executor.rs b/executor/wasm_interface/src/executor.rs index 043535f6c5..32100f1067 100644 --- a/executor/wasm_interface/src/executor.rs +++ b/executor/wasm_interface/src/executor.rs @@ -456,7 +456,7 @@ pub enum ExecutionKind { SessionBytes(Bytes), /// Execute a stored contract by its address. Stored { - /// Address of the contract. + /// Address of the contract's package. address: HashAddr, /// Entry point to call. entry_point: String, From b6d3476d6693788440425851b44d3cf91129950b Mon Sep 17 00:00:00 2001 From: Karan Dhareshwar Date: Thu, 25 Sep 2025 11:40:23 -0500 Subject: [PATCH 14/14] Address lint --- executor/wasm/src/lib.rs | 56 +++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 33 deletions(-) diff --git a/executor/wasm/src/lib.rs b/executor/wasm/src/lib.rs index be4671e6bc..36be0d6d81 100644 --- a/executor/wasm/src/lib.rs +++ b/executor/wasm/src/lib.rs @@ -50,13 +50,12 @@ use casper_types::{ ContractHash, ContractPackage, ContractPackageHash, ContractPackageStatus, EntryPoints as ContractEntryPoints, }, - AccessRights, AddressableEntity, AuctionCosts, ByteCode, ByteCodeAddr, ByteCodeHash, - ByteCodeKind, CLType, CLValue, Contract, ContractRuntimeTag, ContractWasmHash, Digest, - EntityAddr, EntityKind, EntryPointAccess, EntryPointAddr, EntryPointPayment, EntryPointType, - EntryPointValue, Gas, Groups, HashAddr, InitiatorAddr, Key, MessageLimits, MintCosts, - NamedKeys, Package, PackageAddr, PackageHash, PackageStatus, Parameters, Phase, - ProtocolVersion, StorageCosts, StoredValue, TransactionHash, TransactionInvocationTarget, URef, - WasmV2Config, NAME_FOR_V2_CONTRACT_MAIN_PURSE, + AddressableEntity, AuctionCosts, ByteCode, ByteCodeAddr, ByteCodeHash, ByteCodeKind, CLType, + CLValue, Contract, ContractRuntimeTag, ContractWasmHash, Digest, EntityAddr, EntityKind, + EntryPointAccess, EntryPointAddr, EntryPointPayment, EntryPointType, EntryPointValue, Gas, + Groups, InitiatorAddr, Key, MessageLimits, MintCosts, NamedKeys, Package, PackageHash, + PackageStatus, Parameters, Phase, ProtocolVersion, StorageCosts, StoredValue, TransactionHash, + TransactionInvocationTarget, URef, WasmV2Config, NAME_FOR_V2_CONTRACT_MAIN_PURSE, }; use install::{InstallContractError, InstallContractRequest, InstallContractResult}; use parking_lot::RwLock; @@ -588,10 +587,10 @@ impl ExecutorV2 { entry_point, } = &execution_kind { - let smart_contract_key = Key::SmartContract(*smart_contract_addr); - let vm1_key = Key::Hash(*smart_contract_addr); + let smart_contract_key = Key::SmartContract(*contract_package_addr); + let vm1_key = Key::Hash(*contract_package_addr); - let mut contract = match tracking_copy + let contract = match tracking_copy .read_first(&[&vm1_key, &smart_contract_key]) .map_err(|read_error| { error!( @@ -616,15 +615,12 @@ impl ExecutorV2 { let entity_addr = EntityAddr::SmartContract(contract_hash.value()); let latest_version_key = Key::AddressableEntity(entity_addr); assert_eq!(&entity_addr.value(), contract_package_addr); - let new_contract = - tracking_copy - .read(&latest_version_key) - .map_err(|read_err| { - error!("Error when fetching smart contract {latest_version_key}. Details {read_err}"); - ExecuteError::InternalHost(InternalHostError::TrackingCopy) - })?; - - new_contract + tracking_copy + .read(&latest_version_key) + .map_err(|read_err| { + error!("Error when fetching smart contract {latest_version_key}. Details {read_err}"); + ExecuteError::InternalHost(InternalHostError::TrackingCopy) + })? } Some(StoredValue::ContractPackage(smart_contract_package)) => { let contract_hash = if let Some((_, contract_hash)) = @@ -640,20 +636,14 @@ impl ExecutorV2 { return Err(ExecuteError::NoActiveContract(smart_contract_key)); }; let latest_version_key = Key::Hash(contract_hash.value()); - let new_contract = - tracking_copy - .read(&latest_version_key) - .map_err(|read_err| { - error!("Error when fetching smart contract {latest_version_key}. Details {read_err}"); - ExecuteError::InternalHost(InternalHostError::TrackingCopy) - })?; - - new_contract - } - Some(_) | None => { - println!("none case"); - None + tracking_copy + .read(&latest_version_key) + .map_err(|read_err| { + error!("Error when fetching smart contract {latest_version_key}. Details {read_err}"); + ExecuteError::InternalHost(InternalHostError::TrackingCopy) + })? } + Some(_) | None => None, }; match contract { @@ -889,7 +879,7 @@ impl ExecutorV2 { ?execution_kind, "No contract code found", ); - return Err(ExecuteError::CodeNotFound(*smart_contract_addr)); + return Err(ExecuteError::CodeNotFound(*contract_package_addr)); } } } else {