diff --git a/Cargo.toml b/Cargo.toml index ee38e3ad..d4c9e36c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,14 +35,14 @@ odra-casper-rpc-client = { path = "odra-casper/rpc-client", version = "2.0.0" } odra-vm = { path = "odra-vm", version = "2.0.0" } odra-casper-wasm-env = { path = "odra-casper/wasm-env", version = "2.0.0"} odra-schema = { path = "odra-schema", version = "2.0.0" } -casper-contract = { git = "https://github.com/casper-network/casper-node.git", branch = "rustSDK-feat-2.0", default-features = false } +casper-contract = { git = "https://github.com/casper-network/casper-node.git", branch = "feat-2.0", default-features = false } casper-contract-schema = { git = "https://github.com/odradev/casper-contract-schema.git", branch = "feature/casper-2.0" } casper-types = "5.0.0" -casper-execution-engine = { git = "https://github.com/casper-network/casper-node.git", branch = "rustSDK-feat-2.0" } -casper-engine-test-support = { git = "https://github.com/casper-network/casper-node.git", branch = "rustSDK-feat-2.0" } -casper-storage = { git = "https://github.com/casper-network/casper-node.git", branch = "rustSDK-feat-2.0" } -casper-event-standard = { git = "https://github.com/odradev/casper-event-standard.git", branch = "rustSDK-feat-2.0" } -casper-client = { git = "https://github.com/casper-ecosystem/casper-client-rs.git", branch = "rustSDK-feat-2.0" } +casper-execution-engine = { git = "https://github.com/casper-network/casper-node.git", branch = "feat-2.0" } +casper-engine-test-support = { git = "https://github.com/casper-network/casper-node.git", branch = "feat-2.0" } +casper-storage = { git = "https://github.com/casper-network/casper-node.git", branch = "feat-2.0" } +casper-event-standard = { path = "../../casper-event-standard/casper-event-standard" } +casper-client = { git = "https://github.com/casper-ecosystem/casper-client-rs.git", branch = "feat-track-node-2.0" } blake2 = "0.10.6" log = "0.4.20" env_logger = "0.11.1" @@ -61,7 +61,7 @@ convert_case = "0.6.0" lazy_static = "1.5.0" [patch.crates-io] -casper-types = { version = "5.0.0", git = "https://github.com/casper-network/casper-node", branch = "rustSDK-feat-2.0" } +casper-types = { version = "5.0.0", git = "https://github.com/casper-network/casper-node", branch = "feat-2.0" } [profile.release] codegen-units = 1 diff --git a/core/src/address.rs b/core/src/address.rs index 488010be..39fed8d5 100644 --- a/core/src/address.rs +++ b/core/src/address.rs @@ -244,7 +244,13 @@ impl From for Address { fn from(value: Caller) -> Self { match value { Caller::Initiator { account_hash } => Address::from(account_hash), - Caller::Entity { package_hash, .. } => Address::from(package_hash) + Caller::Entity { package_hash, .. } => Address::from(package_hash), + Caller::SmartContract { + contract_hash, + contract_package_hash + } => { + todo!("CONTRACTPACKAGEWHAT!?") + } } } } @@ -293,7 +299,7 @@ const fn hex_char_to_value(c: u8) -> Result { mod tests { use super::*; use casper_types::system::Caller; - use casper_types::{AddressableEntityHash, EraId}; + use casper_types::EraId; // TODO: casper-types > 1.5.0 will have prefix fixed. const PACKAGE_HASH: &str = @@ -464,7 +470,7 @@ mod tests { let address = Address::from(package_hash); let caller = Caller::Entity { package_hash, - entity_hash: AddressableEntityHash::new(package_hash.value()) + entity_addr: EntityAddr::SmartContract(package_hash.value()) }; assert_eq!(address, caller.into()); } diff --git a/odra-casper/rpc-client/src/casper_client.rs b/odra-casper/rpc-client/src/casper_client.rs index 19482e5e..229c59e7 100644 --- a/odra-casper/rpc-client/src/casper_client.rs +++ b/odra-casper/rpc-client/src/casper_client.rs @@ -17,6 +17,7 @@ use casper_client::cli::{ use casper_client::rpcs::results::{GetDeployResult, PutDeployResult}; use casper_client::Verbosity; use casper_types::bytesrepr::{deserialize_from_slice, Bytes, FromBytes, ToBytes}; +use casper_types::contracts::ContractPackageHash; use casper_types::execution::ExecutionResultV1::{Failure, Success}; use casper_types::StoredValue::CLValue; use casper_types::{ @@ -533,12 +534,16 @@ impl CasperClient { call_def.entry_point() )); let session = ExecutableDeployItem::StoredVersionedContractByHash { - hash: *addr.as_package_hash().unwrap_or_else(|| { - panic!( - "Couldn't get package hash from address: {:?}", - addr.to_formatted_string() - ) - }), + hash: ContractPackageHash::from( + addr.as_package_hash() + .unwrap_or_else(|| { + panic!( + "Couldn't get package hash from address: {:?}", + addr.to_formatted_string() + ) + }) + .value() + ), version: None, entry_point: call_def.entry_point().to_string(), args: call_def.args().clone() diff --git a/odra-casper/test-vm/resources/chainspec.toml b/odra-casper/test-vm/resources/chainspec.toml index fec815c6..4efeaf84 100644 --- a/odra-casper/test-vm/resources/chainspec.toml +++ b/odra-casper/test-vm/resources/chainspec.toml @@ -11,7 +11,7 @@ hard_reset = false # in contract-runtime for computing genesis post-state hash. # # If it is an integer, it represents an era ID, meaning the protocol version becomes active at the start of this era. -activation_point = "2024-09-17T09:51:21.872206621Z" +activation_point = '${TIMESTAMP}' [network] # Human readable name for convenience; the genesis_hash is the true identifier. The name influences the genesis hash by @@ -76,6 +76,9 @@ max_runtime_call_stack_height = 12 minimum_delegation_amount = 500_000_000_000 # Maximum allowed delegation amount in motes maximum_delegation_amount = 1_000_000_000_000_000_000 +# Minimum bid amount allowed in motes. Withdrawing one's bid to an amount strictly less than +# the value specified will be treated as a full unbond of a validator and their associated delegators +minimum_bid_amount = 10_000_000_000_000 # Global state prune batch size (0 = this feature is off) prune_batch_size = 0 # Enables strict arguments checking when calling a contract; i.e. that all non-optional args are provided and of the correct `CLType`. @@ -96,7 +99,10 @@ signature_rewards_max_delay = 3 # # Changing this option makes sense only for private chains which dont need auctioning new validator slots. allow_auction_bids = true -# Allow peer to peer transfers between users. Setting this to false makes sense only on private chains. +# Allows transfers between accounts in the blockchain network. +# +# Setting this to false restricts normal accounts from sending tokens to other accounts, allowing transfers only to administrators. +# Changing this option makes sense only on private chains. allow_unrestricted_transfers = true # If set to false, then consensus doesn't compute rewards and always uses 0. compute_rewards = true @@ -157,6 +163,7 @@ gas_hold_interval = '24 hours' # List of public keys of administrator accounts. Setting this option makes only on private chains which require # administrator accounts for regulatory reasons. administrators = [] +enable_addressable_entity = false [highway] # Highway dynamically chooses its round length, between minimum_block_time and maximum_round_length. @@ -193,29 +200,28 @@ max_timestamp_leeway = '5 seconds' # [4] -> The maximum number of transactions the lane can contain native_mint_lane = [0, 1024, 1024, 65_000_000_000, 650] native_auction_lane = [1, 2048, 2048, 362_500_000_000, 145] -wasm_lanes = [[2, 1_048_576, 2048, 1_000_000_000_000, 1], [3, 344_064, 1024, 500_000_000_000, 3], [4, 172_032, 1024, 50_000_000_000, 7], [5, 12_288, 512, 1_500_000_000, 15]] +install_upgrade_lane = [2, 1_048_576, 2048, 1_000_000_000_000, 1] +wasm_lanes = [[3, 344_064, 1024, 500_000_000_000, 3], [4, 172_032, 1024, 50_000_000_000, 7], [5, 12_288, 512, 1_500_000_000, 15]] [transactions.deploy] # The maximum number of Motes allowed to be spent during payment. 0 means unlimited. max_payment_cost = '0' -# The maximum number of other deploys a deploy can depend on (require to have been executed before it can execute). -max_dependencies = 10 # The limit of length of serialized payment code arguments. payment_args_max_length = 1024 # The limit of length of serialized session code arguments. session_args_max_length = 1024 -[wasm] +[wasm.v1] # Amount of free memory (in 64kB pages) each contract can use for stack. max_memory = 64 # Max stack height (native WebAssembly stack limiter). max_stack_height = 500 -[wasm.storage_costs] +[storage_costs] # Gas charged per byte stored in the global state. gas_per_byte = 1_117_587 -[wasm.opcode_costs] +[wasm.v1.opcode_costs] # Bit operations multiplier. bit = 300 # Arithmetic add operations multiplier. @@ -246,9 +252,11 @@ nop = 200 current_memory = 290 # Grow memory cost, per page (64kb). grow_memory = 240_000 +# Sign extension operations cost +sign = 300 # Control flow operations multiplier. -[wasm.opcode_costs.control_flow] +[wasm.v1.opcode_costs.control_flow] block = 440 loop = 440 if = 440 @@ -262,17 +270,18 @@ call = 68_000 call_indirect = 68_000 drop = 440 -[wasm.opcode_costs.control_flow.br_table] +[wasm.v1.opcode_costs.control_flow.br_table] # Fixed cost per `br_table` opcode cost = 35_000 # Size of target labels in the `br_table` opcode will be multiplied by `size_multiplier` size_multiplier = 100 # Host function declarations are located in smart_contracts/contract/src/ext_ffi.rs -[wasm.host_function_costs] +[wasm.v1.host_function_costs] add = { cost = 5_800, arguments = [0, 0, 0, 0] } add_associated_key = { cost = 9_000, arguments = [0, 0, 0] } add_contract_version = { cost = 200, arguments = [0, 0, 0, 0, 120_000, 0, 0, 0, 0, 0] } +add_contract_version_with_message_topics = { cost = 200, arguments = [0, 0, 0, 0, 120_000, 0, 0, 0, 30_000, 0, 0] } add_package_version = { cost = 200, arguments = [0, 0, 0, 0, 120_000, 0, 0, 0, 30_000, 0, 0] } blake2b = { cost = 200, arguments = [0, 0, 0, 0] } call_contract = { cost = 4_500, arguments = [0, 0, 0, 0, 0, 420, 0] } @@ -317,7 +326,9 @@ dictionary_put = { cost = 9_500, arguments = [0, 1_800, 0, 520] } enable_contract_version = { cost = 200, arguments = [0, 0, 0, 0] } manage_message_topic = { cost = 200, arguments = [0, 30_000, 0, 0] } emit_message = { cost = 200, arguments = [0, 30_000, 0, 120_000] } +generic_hash = { cost = 300, arguments = [0, 0, 0, 0, 0] } cost_increase_per_message = 50 +get_block_info = { cost = 330, arguments = [0, 0] } [wasm.messages_limits] max_topic_name_size = 256 diff --git a/odra-casper/test-vm/src/vm/casper_vm.rs b/odra-casper/test-vm/src/vm/casper_vm.rs index eafddd22..ddaf2a69 100644 --- a/odra-casper/test-vm/src/vm/casper_vm.rs +++ b/odra-casper/test-vm/src/vm/casper_vm.rs @@ -259,10 +259,8 @@ impl CasperVm { let messages = messages.messages(); messages.iter().for_each(|message| { let payload = message.payload().clone(); - let addressable_entity = - self.get_addressable_entity_from_entity_addr(message.entity_hash()); - let address = Address::Contract(addressable_entity.package_hash()); - let contract_hash = message.entity_hash().value(); + let package_hash = PackageHash::from(*message.hash_addr()); + let address = Address::from(package_hash); self.messages.entry(address).or_default().push(payload); }); } @@ -318,25 +316,6 @@ impl CasperVm { } .unwrap() } - fn get_messages(&self, address: &Address) { - let entity = self.get_addressable_entity(address); - let (topic_name, message_topic_hash) = entity - .message_topics() - .iter() - .next() - .expect("should have at least one topic"); - - let entity_hash = self.get_addressable_entity_hash(address).value(); - - let q = self - .context - .query( - None, - Key::message_topic(EntityAddr::SmartContract(entity_hash), *message_topic_hash), - &[] - ) - .unwrap(); - } /// Creates a new contract with the specified name, initialization arguments, and entry points caller. pub fn new_contract( @@ -617,15 +596,7 @@ impl CasperVm { impl CasperVm { fn get_package(&self, package_hash: PackageHash) -> Package { - let stored_value = self - .context - .query(None, Key::Package(package_hash.value()), &[]) - .unwrap(); - - match stored_value { - StoredValue::Package(package) => package, - _ => panic!("Expected Package") - } + self.context.get_package(package_hash).unwrap() } fn get_current_contract(&self, package_hash: PackageHash) -> EntityWithNamedKeys { @@ -793,8 +764,6 @@ fn parse_error(err: engine_state::Error) -> OdraError { } _ => OdraError::VmError(VmError::Other(format!("Casper ExecError: {}", exec_err))) } - } else if let engine_state::Error::InsufficientPayment = err { - OdraError::VmError(VmError::BalanceExceeded) } else { OdraError::VmError(VmError::Other(format!("Casper EngineStateError: {}", err))) } diff --git a/odra-casper/wasm-env/src/host_functions.rs b/odra-casper/wasm-env/src/host_functions.rs index 68f9d47a..28a66766 100644 --- a/odra-casper/wasm-env/src/host_functions.rs +++ b/odra-casper/wasm-env/src/host_functions.rs @@ -24,15 +24,16 @@ use casper_contract::{ unwrap_or_revert::UnwrapOrRevert }; use core::mem::MaybeUninit; +use odra_core::casper_types::account::AccountHash; use odra_core::casper_types::addressable_entity::NamedKeys; use odra_core::casper_types::bytesrepr::deserialize; use odra_core::casper_types::contract_messages::{MessagePayload, MessageTopicOperation}; -use odra_core::casper_types::contracts::ContractVersion; -use odra_core::casper_types::system::Caller; +use odra_core::casper_types::contracts::{ContractHash, ContractPackageHash, ContractVersion}; +use odra_core::casper_types::system::{Caller, CallerInfo}; use odra_core::casper_types::{ api_error, bytesrepr, bytesrepr::{Bytes, FromBytes, ToBytes}, - ApiError, CLTyped, CLValue, EntryPoints, Key, PackageHash, RuntimeArgs, URef, + ApiError, CLTyped, CLValue, EntityAddr, EntryPoints, Key, PackageHash, RuntimeArgs, URef, DICTIONARY_ITEM_KEY_MAX_LENGTH, U512, UREF_SERIALIZED_LENGTH }; use odra_core::consts::{ALLOW_KEY_OVERRIDE_ARG, IS_UPGRADABLE_ARG, PACKAGE_HASH_KEY_NAME_ARG}; @@ -369,7 +370,7 @@ pub fn emit_native_event(event: &Bytes) { #[inline(always)] pub fn caller() -> Address { let second_elem = take_nth_caller_from_stack(1); - second_elem.into() + caller_info_to_caller(second_elem).into() } /// Calls a contract method by Address @@ -401,7 +402,7 @@ pub fn call_contract(address: Address, call_def: CallDef) -> Bytes { #[inline(always)] pub fn self_address() -> Address { let first_elem = take_nth_caller_from_stack(0); - first_elem.into() + caller_info_to_caller(first_elem).into() } /// Gets the balance of the current contract. @@ -571,7 +572,7 @@ fn deserialize_contract_result(bytes_written: usize) -> Vec { } } -fn take_nth_caller_from_stack(n: usize) -> Caller { +fn take_nth_caller_from_stack(n: usize) -> CallerInfo { runtime::get_call_stack() .into_iter() .nth_back(n) @@ -699,3 +700,65 @@ fn get_named_arg_size(name: &str) -> Result { _ => Err(ApiError::from(ret as u32)) } } + +fn caller_info_to_caller(info: CallerInfo) -> Caller { + let kind = info.kind(); + match kind { + 0 => { + let account_hash = info + .get_field_by_index(0) + .map(|val| { + val.to_t::>() + .expect("must convert out of cl_value") + }) + .expect("must have index 0 in fields") + .expect("account hash must be some"); + Caller::Initiator { account_hash } + } + 3 => { + let package_hash = info + .get_field_by_index(1) + .map(|val| { + val.to_t::>() + .expect("must convert out of cl_value") + }) + .expect("must have index 1 in fields") + .expect("package hash must be some"); + let entity_addr = info + .get_field_by_index(3) + .map(|val| { + val.to_t::>() + .expect("must convert out of cl_value") + }) + .expect("must have index 3 in fields") + .expect("entity addr must be some"); + Caller::Entity { + package_hash, + entity_addr + } + } + 4 => { + let contract_package_hash = info + .get_field_by_index(2) + .map(|val| { + val.to_t::>() + .expect("must convert out of cl_value") + }) + .expect("must have index 2 in fields") + .expect("contract package hash must be some"); + let contract_hash = info + .get_field_by_index(4) + .map(|val| { + val.to_t::>() + .expect("must convert out of cl_value") + }) + .expect("must have index 4 in fields") + .expect("contract hash must be some"); + Caller::SmartContract { + contract_package_hash, + contract_hash + } + } + _ => panic!("unhandled kind") + } +}