Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions execution_engine/src/runtime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2819,6 +2819,9 @@ where
.metered_write_gs_unsafe(contract_package_key, contract_package)?;
let current_blocktime = self.context.get_block_info().block_time();

self.context
.record_contract_install(ContractHash::new(contract_hash_addr))?;

match self.context.emit_messages_for_new_installed_version(
current_blocktime,
contract_package_key,
Expand Down Expand Up @@ -2992,6 +2995,8 @@ where
}
}
let current_blocktime = self.context.get_block_info().block_time();
self.context
.record_contract_install(ContractHash::new(entity_addr.value()))?;
match self.context.emit_messages_for_new_installed_version(
current_blocktime,
Key::Hash(package_hash.value()),
Expand Down
13 changes: 13 additions & 0 deletions execution_engine/src/runtime_context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1350,6 +1350,19 @@ where
Ok(())
}

pub(crate) fn record_contract_install(
&mut self,
contract_hash: ContractHash,
) -> Result<(), ExecError> {
let hash_addr = contract_hash.value();
let key = Key::Install(hash_addr);
let cl_value = CLValue::from_t(self.transaction_hash).map_err(ExecError::CLValue)?;
let stored_value = StoredValue::CLValue(cl_value);

// No need for key and stored value validation.
self.metered_write_gs_unsafe(key, stored_value)
}

fn addressable_entity_to_validated_value(
&self,
entity: AddressableEntity,
Expand Down
8 changes: 4 additions & 4 deletions execution_engine_testing/tests/src/test/explorer/faucet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -663,14 +663,14 @@ fn faucet_costs() {
// This test will fail if execution costs vary. The expected costs should not be updated
// without understanding why the cost has changed. If the costs do change, it should be
// reflected in the "Costs by Entry Point" section of the faucet crate's README.md.
const EXPECTED_FAUCET_INSTALL_COST: u64 = 154_231_011_056;
const EXPECTED_FAUCET_INSTALL_COST: u64 = 154_608_771_777;
const EXPECTED_FAUCET_INSTALL_COST_ALT: u64 = 149_230_872_143;

const EXPECTED_FAUCET_SET_VARIABLES_COST: u64 = 79_486_430;
const EXPECTED_FAUCET_SET_VARIABLES_COST: u64 = 79_493_950;

const EXPECTED_FAUCET_CALL_BY_INSTALLER_COST: u64 = 2_652_652_793;
const EXPECTED_FAUCET_CALL_BY_INSTALLER_COST: u64 = 2_652_659_058;

const EXPECTED_FAUCET_CALL_BY_USER_COST: u64 = 2_558_376_706;
const EXPECTED_FAUCET_CALL_BY_USER_COST: u64 = 2_558_391_246;

let installer_account = AccountHash::new([1u8; 32]);
let user_account: AccountHash = AccountHash::new([2u8; 32]);
Expand Down
23 changes: 22 additions & 1 deletion execution_engine_testing/tests/src/test/upgrade.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ use casper_types::{
addressable_entity::{AssociatedKeys, Weight},
contracts::ContractPackageHash,
runtime_args, AddressableEntityHash, CLValue, EntityVersion, EraId, HoldBalanceHandling, Key,
PackageAddr, ProtocolVersion, RuntimeArgs, StoredValue, Timestamp, ENTITY_INITIAL_VERSION,
KeyTag, PackageAddr, ProtocolVersion, RuntimeArgs, StoredValue, Timestamp, TransactionHash,
ENTITY_INITIAL_VERSION,
};

const DO_NOTHING_STORED_CONTRACT_NAME: &str = "do_nothing_stored";
Expand Down Expand Up @@ -69,7 +70,27 @@ fn should_upgrade_do_nothing_to_do_something_version_hash_call() {
.build()
};

let expected_transaction_hash = exec_request.session.transaction_hash;
builder.exec(exec_request).expect_success().commit();

let install_key = *builder
.get_keys(KeyTag::Install)
.expect("must get keys")
.first()
.expect("must have one install key");

let actual_transaction_hash = builder
.query(None, install_key, &[])
.expect("must get stored value")
.as_cl_value()
.map(|cl_value| {
cl_value
.to_t::<TransactionHash>()
.expect("must get cl value")
})
.expect("must get transaction hash");

assert_eq!(expected_transaction_hash, actual_transaction_hash)
}

// Calling initial version from contract package hash, should have no effects
Expand Down
42 changes: 40 additions & 2 deletions executor/wasm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1123,7 +1123,22 @@ impl ExecutorV2 {
Err(global_state_error) => return Err(global_state_error.into()),
};

let tracking_copy = TrackingCopy::new(tracking_copy, 1, state_provider.enable_entity());
let mut tracking_copy = TrackingCopy::new(tracking_copy, 1, state_provider.enable_entity());

if tracking_copy
.authorized_runtime_footprint_by_account(
execute_request.runtime_native_config.protocol_version(),
execute_request.initiator,
&execute_request.authorization_keys,
self.execution_engine_v1.config().administrative_accounts(),
execute_request.sandboxed,
)
.is_err()
{
return Err(ExecuteWithProviderError::Execute(
ExecuteError::UnauthorizedEntity,
));
}

match self.execute_with_tracking_copy(tracking_copy, execute_request) {
Ok(ExecuteResult {
Expand Down Expand Up @@ -1172,7 +1187,7 @@ impl ExecutorV2 {
R: StateProvider + CommitProvider,
<R as StateProvider>::Reader: 'static,
{
let tracking_copy = match state_provider.checkout(state_root_hash) {
let mut tracking_copy = match state_provider.checkout(state_root_hash) {
Ok(Some(tracking_copy)) => {
TrackingCopy::new(tracking_copy, 1, state_provider.enable_entity())
}
Expand All @@ -1185,6 +1200,16 @@ impl ExecutorV2 {
};
let sandboxed = install_request.sandboxed;

if let Err(tce) = tracking_copy.authorized_runtime_footprint_by_account(
install_request.runtime_native_config.protocol_version(),
install_request.initiator,
&install_request.authorization_keys,
self.execution_engine_v1.config().administrative_accounts(),
sandboxed,
) {
return Err(InstallContractError::TrackingCopy(tce));
}

let res = self.install_contract(tracking_copy, install_request);
match res {
Ok(InstallContractResult {
Expand Down Expand Up @@ -1724,6 +1749,12 @@ impl Executor for ExecutorV2 {
addressable_entity_key,
StoredValue::AddressableEntity(addressable_entity),
)?;
let cl_value =
CLValue::from_t(transaction_hash).map_err(InstallContractError::CLValueError)?;
state.metered_write(
Key::Install(smart_contract_addr),
StoredValue::CLValue(cl_value),
)?;
addressable_entity_key
} else {
let contract_entrypoints = ContractEntryPoints::from(entity_entrypoints);
Expand All @@ -1746,6 +1777,13 @@ impl Executor for ExecutorV2 {

let contract_key = Key::Hash(smart_contract_addr);
state.metered_write(contract_key, StoredValue::Contract(contract))?;
let cl_value =
CLValue::from_t(transaction_hash).map_err(InstallContractError::CLValueError)?;
state.metered_write(
Key::Install(smart_contract_addr),
StoredValue::CLValue(cl_value),
)?;

contract_key
};

Expand Down
2 changes: 2 additions & 0 deletions executor/wasm_interface/src/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,8 @@ pub enum ExecuteError {
InvalidFFIOption(u32),
#[error("unexpected output after vm1 return")]
UnexpectedOutputAfterVm1Ret,
#[error("the initiator is unauthorized")]
UnauthorizedEntity,
}

#[derive(Debug, Error)]
Expand Down
28 changes: 28 additions & 0 deletions types/src/key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ const BLOCK_GLOBAL_PROTOCOL_VERSION_PREFIX: &str = "block-protocol-version-";
const BLOCK_GLOBAL_ADDRESSABLE_ENTITY_PREFIX: &str = "block-addressable-entity-";
const STATE_PREFIX: &str = "state-";
const TYPE_DEF_PREFIX: &str = "typedef-";
const INSTALL_PREFIX: &str = "install-";

/// The number of bytes in a Blake2b hash
pub const BLAKE2B_DIGEST_LENGTH: usize = 32;
Expand Down Expand Up @@ -163,6 +164,7 @@ pub enum KeyTag {
EntryPoint = 23,
State = 24,
TypeDefinitions = 25,
Install = 26,
}

impl KeyTag {
Expand Down Expand Up @@ -230,6 +232,7 @@ impl Display for KeyTag {
KeyTag::State => write!(f, "State"),
KeyTag::EntryPoint => write!(f, "EntryPoint"),
KeyTag::TypeDefinitions => write!(f, "TypeDefinitions"),
KeyTag::Install => write!(f, "Install"),
}
}
}
Expand Down Expand Up @@ -281,6 +284,7 @@ impl FromBytes for KeyTag {
tag if tag == KeyTag::EntryPoint as u8 => KeyTag::EntryPoint,
tag if tag == KeyTag::State as u8 => KeyTag::State,
tag if tag == KeyTag::TypeDefinitions as u8 => KeyTag::TypeDefinitions,
tag if tag == KeyTag::Install as u8 => KeyTag::Install,
_ => return Err(Error::Formatting),
};
Ok((tag, rem))
Expand Down Expand Up @@ -347,6 +351,8 @@ pub enum Key {
State(StateFieldAddr),
/// A `Key` under which a set of type definitions is stored.
TypeDef(TypeUid),
/// A `Key` which records a transaction hash for a contract install
Install(HashAddr),
}

#[cfg(feature = "json-schema")]
Expand Down Expand Up @@ -546,6 +552,7 @@ impl Key {
Key::EntryPoint(_) => String::from("Key::EntryPoint"),
Key::State(_) => String::from("Key::State"),
Key::TypeDef(_) => String::from("Key::TypeDef"),
Key::Install(_) => String::from("Key::Install"),
}
}

Expand Down Expand Up @@ -677,6 +684,9 @@ impl Key {
Key::TypeDef(type_uid) => {
format!("{}{:08x}", TYPE_DEF_PREFIX, type_uid.value())
}
Key::Install(hash_addr) => {
format!("{}{}", INSTALL_PREFIX, base16::encode_lower(&hash_addr))
}
}
}

Expand Down Expand Up @@ -1492,6 +1502,9 @@ impl Display for Key {
Key::TypeDef(type_uid) => {
write!(f, "Key::TypeDef({})", type_uid)
}
Key::Install(hash_addr) => {
write!(f, "Key::Install({})", base16::encode_lower(hash_addr))
}
}
}
}
Expand Down Expand Up @@ -1531,6 +1544,7 @@ impl Tagged<KeyTag> for Key {
Key::EntryPoint(_) => KeyTag::EntryPoint,
Key::State(_) => KeyTag::State,
Key::TypeDef(_) => KeyTag::TypeDefinitions,
Key::Install(_) => KeyTag::Install,
}
}
}
Expand Down Expand Up @@ -1649,6 +1663,7 @@ impl ToBytes for Key {
}
Key::State(addr) => KEY_ID_SERIALIZED_LENGTH + addr.serialized_length(),
Key::TypeDef(_) => KEY_TYPE_DEF_SERIALIZED_LENGTH,
Key::Install(_) => U8_SERIALIZED_LENGTH + KEY_HASH_LENGTH,
}
}

Expand Down Expand Up @@ -1684,6 +1699,7 @@ impl ToBytes for Key {
Key::EntryPoint(entry_point_addr) => entry_point_addr.write_bytes(writer),
Key::State(addr) => addr.write_bytes(writer),
Key::TypeDef(type_uid) => type_uid.write_bytes(writer),
Key::Install(hash_addr) => hash_addr.write_bytes(writer),
}
}
}
Expand Down Expand Up @@ -1806,6 +1822,10 @@ impl FromBytes for Key {
let (type_uid, rem) = TypeUid::from_bytes(remainder)?;
Ok((Key::TypeDef(type_uid), rem))
}
KeyTag::Install => {
let (hash, rem) = HashAddr::from_bytes(remainder)?;
Ok((Key::Install(hash), rem))
}
}
}
}
Expand Down Expand Up @@ -1841,6 +1861,7 @@ fn please_add_to_distribution_impl(key: Key) {
Key::EntryPoint(_) => unimplemented!(),
Key::State(_) => unimplemented!(),
Key::TypeDef(_) => unimplemented!(),
Key::Install(_) => unimplemented!(),
}
}

Expand Down Expand Up @@ -1877,6 +1898,7 @@ impl Distribution<Key> for Standard {
23 => Key::EntryPoint(rng.gen()),
24 => Key::State(rng.gen()),
25 => Key::TypeDef(TypeUid::new(rng.gen())),
26 => Key::Install(rng.gen()),
_ => unreachable!(),
}
}
Expand Down Expand Up @@ -1914,6 +1936,7 @@ mod serde_helpers {
EntryPoint(&'a EntryPointAddr),
State(&'a StateFieldAddr),
TypeDef(&'a TypeUid),
Install(&'a HashAddr),
}

#[derive(Deserialize)]
Expand Down Expand Up @@ -1945,6 +1968,7 @@ mod serde_helpers {
EntryPoint(EntryPointAddr),
State(StateFieldAddr),
TypeDef(TypeUid),
Install(HashAddr),
}

impl<'a> From<&'a Key> for BinarySerHelper<'a> {
Expand Down Expand Up @@ -1980,6 +2004,7 @@ mod serde_helpers {
Key::EntryPoint(entry_point_addr) => BinarySerHelper::EntryPoint(entry_point_addr),
Key::State(addr) => BinarySerHelper::State(addr),
Key::TypeDef(type_uid) => BinarySerHelper::TypeDef(type_uid),
Key::Install(hash_addr) => BinarySerHelper::Install(hash_addr),
}
}
}
Expand Down Expand Up @@ -2019,6 +2044,7 @@ mod serde_helpers {
}
BinaryDeserHelper::State(addr) => Key::State(addr),
BinaryDeserHelper::TypeDef(type_uid) => Key::TypeDef(type_uid),
BinaryDeserHelper::Install(hash_addr) => Key::Hash(hash_addr),
}
}
}
Expand Down Expand Up @@ -2118,6 +2144,7 @@ mod tests {
[43; 32],
));
const TYPE_DEF_KEY: Key = Key::TypeDef(TypeUid::new(0x0000_0042));
const INSTALL_KEY: Key = Key::Install([42; 32]);
const KEYS: &[Key] = &[
ACCOUNT_KEY,
HASH_KEY,
Expand Down Expand Up @@ -2151,6 +2178,7 @@ mod tests {
BALANCE_HOLD,
STATE_KEY,
TYPE_DEF_KEY,
INSTALL_KEY,
];
const HEX_STRING: &str = "2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a";
const TOPIC_NAME_HEX_STRING: &str =
Expand Down
8 changes: 7 additions & 1 deletion types/src/transaction/transaction_hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use super::{DeployHash, TransactionV1Hash};
use crate::testing::TestRng;
use crate::{
bytesrepr::{self, FromBytes, ToBytes, U8_SERIALIZED_LENGTH},
Digest,
CLType, CLTyped, Digest, KEY_HASH_LENGTH,
};

const DEPLOY_TAG: u8 = 0;
Expand Down Expand Up @@ -161,6 +161,12 @@ impl FromBytes for TransactionHash {
}
}

impl CLTyped for TransactionHash {
fn cl_type() -> CLType {
CLType::ByteArray(KEY_HASH_LENGTH as u32)
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
Loading