Skip to content
24 changes: 22 additions & 2 deletions execution_engine/src/runtime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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::<Key>().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,
Expand Down
150 changes: 129 additions & 21 deletions executor/wasm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -666,27 +668,112 @@ 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)) => {
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(_) => {
println!("1");
return Err(ExecuteError::EntityNotFound(caller_key));
}
};

let main_purse = contract
.named_keys()
.get("__v2_main_purse")
.ok_or(ExecuteError::MainPurseNotFound(vm1_key))?
.into_uref()
.ok_or(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",
);

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,
);
println!("{:?}", error);
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,
);
}
}
}
Some(stored_value) => {
todo!(
Expand Down Expand Up @@ -720,7 +807,13 @@ impl ExecutorV2 {
ExecutionKind::Stored {
address: smart_contract_addr,
..
} => Key::SmartContract(*smart_contract_addr),
} => {
if initial_tracking_copy.enable_addressable_entity() {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't this be named addressable_entity_enabled ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ummm I've kept it mirrored to the field name in the chainspec to avoid confusion

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.");
Expand Down Expand Up @@ -898,6 +991,7 @@ impl ExecutorV2 {
let entry_point = entry_point.clone();
let args = bytesrepr::deserialize_from_slice(input)
.map_err(|err| ExecuteError::InternalHost(InternalHostError::Bytesrepr(err)))?;

let phase = Phase::Session;

let wasm_v1_result = {
Expand Down Expand Up @@ -1208,6 +1302,20 @@ fn get_purse_for_entity<R: GlobalStateReader>(

Ok((entity_addr, addressable_entity.main_purse()))
}
StoredValue::Contract(contract) => {
let uref = contract
.named_keys()
.get(NAME_FOR_V2_CONTRACT_MAIN_PURSE)
.ok_or(ExecuteError::MainPurseNotFound(entity_key))?
.into_uref()
.ok_or(ExecuteError::InvalidKeyForPurse(entity_key))?;

let hash_addr = entity_key
.into_hash_addr()
.ok_or(ExecuteError::EntityNotFound(entity_key))?;

Ok((EntityAddr::SmartContract(hash_addr), uref))
}
other => Err(ExecuteError::InternalHost(
InternalHostError::UnexpectedStoredValueVariant {
expected: "AddressableEntity or Account".to_string(),
Expand Down
2 changes: 1 addition & 1 deletion executor/wasm/src/testing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
8 changes: 7 additions & 1 deletion executor/wasm/tests/integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -818,6 +818,7 @@ fn traits() {
);
}

#[ignore]
#[test]
fn upgradable() {
let chainspec_config = ChainspecConfig::from_chainspec_path(&*CHAINSPEC_SYMLINK)
Expand Down Expand Up @@ -983,6 +984,7 @@ fn upgradable() {
let _ = state_root_hash;
}

#[ignore]
#[test]
fn backwards_compatibility() {
let (global_state, post_state_hash, _temp) = {
Expand Down Expand Up @@ -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,
Expand Down
12 changes: 12 additions & 0 deletions executor/wasm_common/src/chain_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,18 @@ pub fn compute_predictable_address<T: AsRef<[u8]>>(
hasher.finalize().into()
}

pub fn compute_next_contract_hash_version(
smart_contract_addr: [u8; 32],
next_version: u32,
) -> [u8; 32] {
let mut hasher = Blake2b::<U32>::new();

hasher.update(smart_contract_addr);
hasher.update(next_version.to_le_bytes());

hasher.finalize().into()
}

pub fn compute_wasm_bytecode_hash<T: AsRef<[u8]>>(wasm_bytes: T) -> [u8; 32] {
let mut hasher = Blake2b::<U32>::new();
hasher.update(wasm_bytes);
Expand Down
4 changes: 4 additions & 0 deletions executor/wasm_common/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
}
Expand All @@ -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<u32> for HostResult {
fn from(value: u32) -> Self {
Expand All @@ -59,6 +62,7 @@ impl From<u32> 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),
}
}
Expand Down
Loading