From 1c53766b0370f0e7a357b380636608dfb69f2fdc Mon Sep 17 00:00:00 2001 From: Ed Hastings Date: Mon, 1 Apr 2024 02:11:43 -0700 Subject: [PATCH] restoring entry_point to payment execution --- .../src/engine_state/execution_kind.rs | 19 +- execution_engine/src/engine_state/mod.rs | 2 +- execution_engine/src/engine_state/wasm_v1.rs | 340 +++++++++++------- execution_engine/src/execution/executor.rs | 10 +- .../test_support/src/chainspec_config.rs | 24 +- .../src/execute_request_builder.rs | 53 +-- .../test_support/src/wasm_test_builder.rs | 41 ++- .../src/test/contract_api/get_call_stack.rs | 25 +- .../tests/src/test/contract_api/transfer.rs | 128 +++++-- .../src/test/deploy/non_standard_payment.rs | 60 +++- .../tests/src/test/deploy/stored_contracts.rs | 2 +- .../tests/src/test/explorer/faucet.rs | 8 +- .../src/test/explorer/faucet_test_helpers.rs | 24 +- .../tests/src/test/get_balance.rs | 12 +- .../tests/src/test/regression/ee_966.rs | 4 +- ...host_function_metrics_size_and_gas_cost.rs | 2 +- .../test/regression/regression_20210707.rs | 2 +- .../components/transaction_acceptor/tests.rs | 2 +- resources/test/sse_data_schema.json | 6 +- storage/src/data_access_layer/balance.rs | 8 + types/src/transaction/deploy/deploy_header.rs | 2 +- types/src/transaction/pricing_mode.rs | 16 +- types/src/transaction/transaction_v1.rs | 4 +- .../transaction_v1/transaction_v1_header.rs | 5 +- 24 files changed, 488 insertions(+), 311 deletions(-) diff --git a/execution_engine/src/engine_state/execution_kind.rs b/execution_engine/src/engine_state/execution_kind.rs index 06062663a9..a37f241f50 100644 --- a/execution_engine/src/engine_state/execution_kind.rs +++ b/execution_engine/src/engine_state/execution_kind.rs @@ -49,36 +49,31 @@ impl<'a> ExecutionKind<'a> { R: StateReader, { match executable_item { - ExecutableItem::Stored(target) => Self::new_stored( + ExecutableItem::Invocation(target) => Self::new_stored( tracking_copy, named_keys, target, entry_point, protocol_version, ), - ExecutableItem::CustomPayment(module_bytes) - | ExecutableItem::SessionModuleBytes { + ExecutableItem::PaymentBytes(module_bytes) + | ExecutableItem::SessionBytes { kind: TransactionSessionKind::Standard, module_bytes, } => Ok(ExecutionKind::Standard(module_bytes)), - ExecutableItem::SessionModuleBytes { + ExecutableItem::SessionBytes { kind: TransactionSessionKind::Installer, module_bytes, } => Ok(ExecutionKind::Installer(module_bytes)), - ExecutableItem::SessionModuleBytes { + ExecutableItem::SessionBytes { kind: TransactionSessionKind::Upgrader, module_bytes, } => Ok(ExecutionKind::Upgrader(module_bytes)), - ExecutableItem::SessionModuleBytes { + ExecutableItem::SessionBytes { kind: TransactionSessionKind::Isolated, module_bytes, } => Ok(ExecutionKind::Isolated(module_bytes)), - ExecutableItem::DeploySessionModuleBytes(module_bytes) => { - Ok(ExecutionKind::Deploy(module_bytes)) - } - ExecutableItem::StandardPayment => Err(Error::Deprecated( - "standard payment is no longer handled by the execution engine".to_string(), - )), + ExecutableItem::LegacyDeploy(module_bytes) => Ok(ExecutionKind::Deploy(module_bytes)), } } diff --git a/execution_engine/src/engine_state/mod.rs b/execution_engine/src/engine_state/mod.rs index fb7a0bec2a..4dd5d69608 100644 --- a/execution_engine/src/engine_state/mod.rs +++ b/execution_engine/src/engine_state/mod.rs @@ -69,6 +69,7 @@ impl ExecutionEngineV1 { entry_point, args, authorization_keys, + phase, }: WasmV1Request, ) -> WasmV1Result { // NOTE to core engineers: it is intended for the EE to ONLY execute wasm targeting the @@ -112,7 +113,6 @@ impl ExecutionEngineV1 { return WasmV1Result::precondition_failure(gas_limit, Error::TrackingCopy(tce)) } }; - let phase = executable_item.phase(); let execution_kind = match ExecutionKind::new( &mut *tc.borrow_mut(), &named_keys, diff --git a/execution_engine/src/engine_state/wasm_v1.rs b/execution_engine/src/engine_state/wasm_v1.rs index c0e7d43805..a98f24dbcc 100644 --- a/execution_engine/src/engine_state/wasm_v1.rs +++ b/execution_engine/src/engine_state/wasm_v1.rs @@ -37,39 +37,26 @@ pub enum InvalidRequest { } /// The item to be executed. -#[derive(Debug)] -pub enum ExecutableItem<'a> { - /// A stored entity or package. - Stored(TransactionInvocationTarget), - /// Compiled Wasm from a transaction >= V1 as byte code. - SessionModuleBytes { +#[derive(Debug, Clone)] +pub enum ExecutableItem { + /// Legacy deploy byte code. + LegacyDeploy(Bytes), + /// Payment byte code. + PaymentBytes(Bytes), + /// Session byte code. + SessionBytes { /// The kind of session. kind: TransactionSessionKind, /// The compiled Wasm. - module_bytes: &'a Bytes, + module_bytes: Bytes, }, - /// Compiled Wasm from a deploy as byte code. - DeploySessionModuleBytes(&'a Bytes), - /// Module bytes to be used as custom payment. - CustomPayment(&'a Bytes), - /// Standard payment. - StandardPayment, -} - -impl<'a> ExecutableItem<'a> { - pub(super) fn phase(&self) -> Phase { - match self { - ExecutableItem::Stored(_) - | ExecutableItem::SessionModuleBytes { .. } - | ExecutableItem::DeploySessionModuleBytes(_) => Phase::Session, - ExecutableItem::CustomPayment(_) | ExecutableItem::StandardPayment => Phase::Payment, - } - } + /// An attempt to invoke a stored entity or package. + Invocation(TransactionInvocationTarget), } /// A request to execute the given Wasm on the V1 runtime. #[derive(Debug)] -pub struct WasmV1Request<'a> { +pub struct WasmV1Request { /// State root hash of the global state in which the transaction will be executed. pub state_hash: Digest, /// Block time represented as a unix timestamp. @@ -81,45 +68,68 @@ pub struct WasmV1Request<'a> { /// The transaction's initiator. pub initiator_addr: InitiatorAddr, /// The executable item. - pub executable_item: ExecutableItem<'a>, + pub executable_item: ExecutableItem, /// The entry point to call when executing. pub entry_point: String, /// The runtime args. pub args: RuntimeArgs, /// The account hashes of the signers of the transaction. pub authorization_keys: BTreeSet, + /// Execution phase. + pub phase: Phase, } -impl<'a> WasmV1Request<'a> { +impl WasmV1Request { + pub(crate) fn new_from_executable_info( + state_hash: Digest, + block_time: BlockTime, + gas_limit: Gas, + transaction_hash: TransactionHash, + initiator_addr: InitiatorAddr, + authorization_keys: BTreeSet, + executable_info: impl Executable, + ) -> Self { + let executable_item = executable_info.item(); + Self { + state_hash, + block_time, + transaction_hash, + gas_limit, + initiator_addr, + authorization_keys, + executable_item, + entry_point: executable_info.entry_point().clone(), + args: executable_info.args().clone(), + phase: executable_info.phase(), + } + } + /// Creates a new request from a transaction for use as the session code. pub fn new_session( state_hash: Digest, block_time: BlockTime, gas_limit: Gas, - txn: &'a Transaction, + transaction: &Transaction, ) -> Result { - let transaction_hash = txn.hash(); - let initiator_addr = txn.initiator_addr(); - let authorization_keys = txn.signers(); - - let session_info = match txn { + let info = match transaction { Transaction::Deploy(deploy) => { SessionInfo::try_from((deploy.session(), deploy.hash()))? } Transaction::V1(v1_txn) => SessionInfo::try_from(v1_txn)?, }; - Ok(Self { + let transaction_hash = transaction.hash(); + let initiator_addr = transaction.initiator_addr(); + let authorization_keys = transaction.signers(); + Ok(WasmV1Request::new_from_executable_info( state_hash, block_time, - transaction_hash, gas_limit, + transaction_hash, initiator_addr, - executable_item: session_info.session, - entry_point: session_info.entry_point, - args: session_info.args, authorization_keys, - }) + info, + )) } /// Creates a new request from a transaction for use as custom payment. @@ -127,35 +137,30 @@ impl<'a> WasmV1Request<'a> { state_hash: Digest, block_time: BlockTime, gas_limit: Gas, - txn: &'a Transaction, + transaction: &Transaction, ) -> Result { - let transaction_hash = txn.hash(); - let initiator_addr = txn.initiator_addr(); - let authorization_keys = txn.signers(); - - let payment_info = match txn { + let info = match transaction { Transaction::Deploy(deploy) => { PaymentInfo::try_from((deploy.payment(), deploy.hash()))? } Transaction::V1(v1_txn) => PaymentInfo::try_from(v1_txn)?, }; - Ok(Self { + let transaction_hash = transaction.hash(); + let initiator_addr = transaction.initiator_addr(); + let authorization_keys = transaction.signers(); + Ok(WasmV1Request::new_from_executable_info( state_hash, block_time, - transaction_hash, gas_limit, + transaction_hash, initiator_addr, - executable_item: payment_info.payment, - entry_point: DEFAULT_ENTRY_POINT.to_string(), - args: payment_info.args, authorization_keys, - }) + info, + )) } /// Creates a new request from a deploy item for use as the session code. - // - // TODO - deprecate? pub fn new_session_from_deploy_item( state_hash: Digest, block_time: BlockTime, @@ -166,25 +171,24 @@ impl<'a> WasmV1Request<'a> { ref authorization_keys, ref deploy_hash, .. - }: &'a DeployItem, + }: &DeployItem, ) -> Result { - let session_info = SessionInfo::try_from((session, deploy_hash))?; - Ok(Self { + let info = SessionInfo::try_from((session, deploy_hash))?; + let transaction_hash = TransactionHash::Deploy(*deploy_hash); + let initiator_addr = InitiatorAddr::AccountHash(*address); + let authorization_keys = authorization_keys.clone(); + Ok(WasmV1Request::new_from_executable_info( state_hash, block_time, - transaction_hash: TransactionHash::Deploy(*deploy_hash), gas_limit, - initiator_addr: InitiatorAddr::AccountHash(*address), - executable_item: session_info.session, - entry_point: session_info.entry_point, - args: session_info.args, - authorization_keys: authorization_keys.clone(), - }) + transaction_hash, + initiator_addr, + authorization_keys, + info, + )) } /// Creates a new request from a deploy item for use as custom payment. - // - // TODO - deprecate? pub fn new_custom_payment_from_deploy_item( state_hash: Digest, block_time: BlockTime, @@ -195,20 +199,21 @@ impl<'a> WasmV1Request<'a> { ref authorization_keys, ref deploy_hash, .. - }: &'a DeployItem, + }: &DeployItem, ) -> Result { - let payment_info = PaymentInfo::try_from((payment, deploy_hash))?; - Ok(Self { + let info = PaymentInfo::try_from((payment, deploy_hash))?; + let transaction_hash = TransactionHash::Deploy(*deploy_hash); + let initiator_addr = InitiatorAddr::AccountHash(*address); + let authorization_keys = authorization_keys.clone(); + Ok(WasmV1Request::new_from_executable_info( state_hash, block_time, - transaction_hash: TransactionHash::Deploy(*deploy_hash), gas_limit, - initiator_addr: InitiatorAddr::AccountHash(*address), - executable_item: payment_info.payment, - entry_point: DEFAULT_ENTRY_POINT.to_string(), - args: payment_info.args, - authorization_keys: authorization_keys.clone(), - }) + transaction_hash, + initiator_addr, + authorization_keys, + info, + )) } } @@ -352,28 +357,54 @@ impl WasmV1Result { } } -/// Helper struct to carry the appropriate info for converting an `ExecutableDeployItem` or a -/// `TransactionV1` into the corresponding fields of a `WasmV1Request` for execution as session -/// code. -struct SessionInfo<'a> { - session: ExecutableItem<'a>, +/// Helper struct to carry item, entry_point, and arg info for a `WasmV1Request`. +struct ExecutableInfo { + item: ExecutableItem, entry_point: String, args: RuntimeArgs, } -impl<'a> TryFrom<(&'a ExecutableDeployItem, &'a DeployHash)> for SessionInfo<'a> { +pub(crate) trait Executable { + fn item(&self) -> ExecutableItem; + fn entry_point(&self) -> &String; + fn args(&self) -> &RuntimeArgs; + fn phase(&self) -> Phase; +} + +/// New type for hanging session specific impl's off of. +struct SessionInfo(ExecutableInfo); + +impl Executable for SessionInfo { + fn item(&self) -> ExecutableItem { + self.0.item.clone() + } + + fn entry_point(&self) -> &String { + &self.0.entry_point + } + + fn args(&self) -> &RuntimeArgs { + &self.0.args + } + + fn phase(&self) -> Phase { + Phase::Session + } +} + +impl TryFrom<(&ExecutableDeployItem, &DeployHash)> for SessionInfo { type Error = InvalidRequest; fn try_from( - (session_item, deploy_hash): (&'a ExecutableDeployItem, &'a DeployHash), + (session_item, deploy_hash): (&ExecutableDeployItem, &DeployHash), ) -> Result { let transaction_hash = TransactionHash::Deploy(*deploy_hash); - let session: ExecutableItem<'a>; + let session: ExecutableItem; let session_entry_point: String; let session_args: RuntimeArgs; match session_item { ExecutableDeployItem::ModuleBytes { module_bytes, args } => { - session = ExecutableItem::DeploySessionModuleBytes(module_bytes); + session = ExecutableItem::LegacyDeploy(module_bytes.clone()); session_entry_point = DEFAULT_ENTRY_POINT.to_string(); session_args = args.clone(); } @@ -382,7 +413,7 @@ impl<'a> TryFrom<(&'a ExecutableDeployItem, &'a DeployHash)> for SessionInfo<'a> entry_point, args, } => { - session = ExecutableItem::Stored( + session = ExecutableItem::Invocation( TransactionInvocationTarget::new_invocable_entity(*hash), ); session_entry_point = entry_point.clone(); @@ -393,7 +424,7 @@ impl<'a> TryFrom<(&'a ExecutableDeployItem, &'a DeployHash)> for SessionInfo<'a> entry_point, args, } => { - session = ExecutableItem::Stored( + session = ExecutableItem::Invocation( TransactionInvocationTarget::new_invocable_entity_alias(name.clone()), ); session_entry_point = entry_point.clone(); @@ -405,7 +436,7 @@ impl<'a> TryFrom<(&'a ExecutableDeployItem, &'a DeployHash)> for SessionInfo<'a> entry_point, args, } => { - session = ExecutableItem::Stored(TransactionInvocationTarget::new_package( + session = ExecutableItem::Invocation(TransactionInvocationTarget::new_package( *hash, *version, )); session_entry_point = entry_point.clone(); @@ -417,10 +448,9 @@ impl<'a> TryFrom<(&'a ExecutableDeployItem, &'a DeployHash)> for SessionInfo<'a> entry_point, args, } => { - session = ExecutableItem::Stored(TransactionInvocationTarget::new_package_alias( - name.clone(), - *version, - )); + session = ExecutableItem::Invocation( + TransactionInvocationTarget::new_package_alias(name.clone(), *version), + ); session_entry_point = entry_point.clone(); session_args = args.clone(); } @@ -432,18 +462,18 @@ impl<'a> TryFrom<(&'a ExecutableDeployItem, &'a DeployHash)> for SessionInfo<'a> } } - Ok(SessionInfo { - session, + Ok(SessionInfo(ExecutableInfo { + item: session, entry_point: session_entry_point, args: session_args, - }) + })) } } -impl<'a> TryFrom<&'a TransactionV1> for SessionInfo<'a> { +impl TryFrom<&TransactionV1> for SessionInfo { type Error = InvalidRequest; - fn try_from(v1_txn: &'a TransactionV1) -> Result { + fn try_from(v1_txn: &TransactionV1) -> Result { let transaction_hash = TransactionHash::V1(*v1_txn.hash()); let args = v1_txn.args().clone(); let session = match v1_txn.target() { @@ -453,12 +483,12 @@ impl<'a> TryFrom<&'a TransactionV1> for SessionInfo<'a> { v1_txn.target().to_string(), )); } - TransactionTarget::Stored { id, .. } => ExecutableItem::Stored(id.clone()), + TransactionTarget::Stored { id, .. } => ExecutableItem::Invocation(id.clone()), TransactionTarget::Session { kind, module_bytes, .. - } => ExecutableItem::SessionModuleBytes { + } => ExecutableItem::SessionBytes { kind: *kind, - module_bytes, + module_bytes: module_bytes.clone(), }, }; @@ -466,75 +496,102 @@ impl<'a> TryFrom<&'a TransactionV1> for SessionInfo<'a> { return Err(InvalidRequest::InvalidEntryPoint(transaction_hash, v1_txn.entry_point().to_string())); }; - Ok(SessionInfo { - session, + Ok(SessionInfo(ExecutableInfo { + item: session, entry_point: entry_point.clone(), args, - }) + })) } } -/// Helper struct to carry the appropriate info for converting an `ExecutableDeployItem` or a -/// `TransactionV1` into the corresponding fields of a `WasmV1Request` for execution as custom -/// payment. -struct PaymentInfo<'a> { - payment: ExecutableItem<'a>, - args: RuntimeArgs, +/// New type for hanging payment specific impl's off of. +struct PaymentInfo(ExecutableInfo); + +impl Executable for PaymentInfo { + fn item(&self) -> ExecutableItem { + self.0.item.clone() + } + + fn entry_point(&self) -> &String { + &self.0.entry_point + } + + fn args(&self) -> &RuntimeArgs { + &self.0.args + } + + fn phase(&self) -> Phase { + Phase::Payment + } } -impl<'a> TryFrom<(&'a ExecutableDeployItem, &'a DeployHash)> for PaymentInfo<'a> { +impl TryFrom<(&ExecutableDeployItem, &DeployHash)> for PaymentInfo { type Error = InvalidRequest; fn try_from( - (payment_item, deploy_hash): (&'a ExecutableDeployItem, &'a DeployHash), + (payment_item, deploy_hash): (&ExecutableDeployItem, &DeployHash), ) -> Result { let transaction_hash = TransactionHash::Deploy(*deploy_hash); match payment_item { ExecutableDeployItem::ModuleBytes { module_bytes, args } => { - if module_bytes.is_empty() { - Ok(PaymentInfo { - payment: ExecutableItem::StandardPayment, - args: args.clone(), - }) + let payment = if module_bytes.is_empty() { + return Err(InvalidRequest::UnsupportedMode( + transaction_hash, + "standard payment is no longer handled by the execution engine".to_string(), + )); } else { - Ok(PaymentInfo { - payment: ExecutableItem::CustomPayment(module_bytes), - args: args.clone(), - }) - } + ExecutableItem::PaymentBytes(module_bytes.clone()) + }; + Ok(PaymentInfo(ExecutableInfo { + item: payment, + entry_point: DEFAULT_ENTRY_POINT.to_string(), + args: args.clone(), + })) } - ExecutableDeployItem::StoredContractByHash { hash, args, .. } => Ok(PaymentInfo { - payment: ExecutableItem::Stored(TransactionInvocationTarget::ByHash(hash.value())), + ExecutableDeployItem::StoredContractByHash { + hash, + args, + entry_point, + } => Ok(PaymentInfo(ExecutableInfo { + item: ExecutableItem::Invocation(TransactionInvocationTarget::ByHash(hash.value())), + entry_point: entry_point.clone(), args: args.clone(), - }), - ExecutableDeployItem::StoredContractByName { name, args, .. } => Ok(PaymentInfo { - payment: ExecutableItem::Stored(TransactionInvocationTarget::ByName(name.clone())), + })), + ExecutableDeployItem::StoredContractByName { + name, + args, + entry_point, + } => Ok(PaymentInfo(ExecutableInfo { + item: ExecutableItem::Invocation(TransactionInvocationTarget::ByName(name.clone())), + entry_point: entry_point.clone(), args: args.clone(), - }), + })), ExecutableDeployItem::StoredVersionedContractByHash { args, hash, version, - .. - } => Ok(PaymentInfo { - payment: ExecutableItem::Stored(TransactionInvocationTarget::ByPackageHash { + entry_point, + } => Ok(PaymentInfo(ExecutableInfo { + item: ExecutableItem::Invocation(TransactionInvocationTarget::ByPackageHash { addr: hash.value(), version: *version, }), + entry_point: entry_point.clone(), args: args.clone(), - }), + })), ExecutableDeployItem::StoredVersionedContractByName { name, version, args, - .. - } => Ok(PaymentInfo { - payment: ExecutableItem::Stored(TransactionInvocationTarget::ByPackageName { + entry_point, + } => Ok(PaymentInfo(ExecutableInfo { + item: ExecutableItem::Invocation(TransactionInvocationTarget::ByPackageName { name: name.clone(), version: *version, }), + entry_point: entry_point.clone(), args: args.clone(), - }), + })), ExecutableDeployItem::Transfer { .. } => Err(InvalidRequest::UnexpectedVariant( transaction_hash, "payment item".to_string(), @@ -543,10 +600,10 @@ impl<'a> TryFrom<(&'a ExecutableDeployItem, &'a DeployHash)> for PaymentInfo<'a> } } -impl<'a> TryFrom<&'a TransactionV1> for PaymentInfo<'a> { +impl TryFrom<&TransactionV1> for PaymentInfo { type Error = InvalidRequest; - fn try_from(v1_txn: &'a TransactionV1) -> Result { + fn try_from(v1_txn: &TransactionV1) -> Result { let transaction_hash = TransactionHash::V1(*v1_txn.hash()); let pricing_mode = v1_txn.pricing_mode(); let payment_amount = match v1_txn.pricing_mode() { @@ -573,7 +630,7 @@ impl<'a> TryFrom<&'a TransactionV1> for PaymentInfo<'a> { let payment = match v1_txn.target() { TransactionTarget::Session { module_bytes, .. } => { - ExecutableItem::CustomPayment(module_bytes) + ExecutableItem::PaymentBytes(module_bytes.clone()) } TransactionTarget::Native | TransactionTarget::Stored { .. } => { return Err(InvalidRequest::InvalidTarget( @@ -583,6 +640,13 @@ impl<'a> TryFrom<&'a TransactionV1> for PaymentInfo<'a> { } }; let args = runtime_args! { ARG_AMOUNT => U512::from(payment_amount)}; - Ok(PaymentInfo { payment, args }) + let TransactionEntryPoint::Custom(entry_point) = v1_txn.entry_point().clone() else { + return Err(InvalidRequest::InvalidEntryPoint(transaction_hash, v1_txn.entry_point().to_string())); + }; + Ok(PaymentInfo(ExecutableInfo { + item: payment, + entry_point, + args, + })) } } diff --git a/execution_engine/src/execution/executor.rs b/execution_engine/src/execution/executor.rs index 846732760b..53515d4713 100644 --- a/execution_engine/src/execution/executor.rs +++ b/execution_engine/src/execution/executor.rs @@ -5,16 +5,14 @@ use casper_storage::{ tracking_copy::TrackingCopy, AddressGenerator, }; -use casper_types::execution::Effects; use casper_types::{ - account::AccountHash, addressable_entity::NamedKeys, AddressableEntity, AddressableEntityHash, - BlockTime, ContextAccessRights, EntryPointType, Gas, Key, Phase, ProtocolVersion, RuntimeArgs, - StoredValue, Tagged, TransactionHash, U512, + account::AccountHash, addressable_entity::NamedKeys, execution::Effects, AddressableEntity, + AddressableEntityHash, BlockTime, ContextAccessRights, EntryPointType, Gas, Key, Phase, + ProtocolVersion, RuntimeArgs, StoredValue, Tagged, TransactionHash, U512, }; -use crate::engine_state::WasmV1Result; use crate::{ - engine_state::{execution_kind::ExecutionKind, EngineConfig}, + engine_state::{execution_kind::ExecutionKind, EngineConfig, WasmV1Result}, execution::ExecError, runtime::{Runtime, RuntimeStack}, runtime_context::{CallingAddContractVersion, RuntimeContext}, diff --git a/execution_engine_testing/test_support/src/chainspec_config.rs b/execution_engine_testing/test_support/src/chainspec_config.rs index eaa943d45a..5a17e99b78 100644 --- a/execution_engine_testing/test_support/src/chainspec_config.rs +++ b/execution_engine_testing/test_support/src/chainspec_config.rs @@ -106,14 +106,22 @@ impl ChainspecConfig { genesis_accounts: Vec, protocol_version: ProtocolVersion, ) -> Result { - let chainspec_config = ChainspecConfig::from_path(filename)?; + ChainspecConfig::from_path(filename)? + .create_genesis_request(genesis_accounts, protocol_version) + } + /// Create genesis request from self. + pub fn create_genesis_request( + &self, + genesis_accounts: Vec, + protocol_version: ProtocolVersion, + ) -> Result { // if you get a compilation error here, make sure to update the builder below accordingly let ChainspecConfig { core_config, wasm_config, system_costs_config, - } = chainspec_config; + } = self; let CoreConfig { validator_slots, auction_delay, @@ -125,13 +133,13 @@ impl ChainspecConfig { let genesis_config = GenesisConfigBuilder::new() .with_accounts(genesis_accounts) - .with_wasm_config(wasm_config) - .with_system_config(system_costs_config) - .with_validator_slots(validator_slots) - .with_auction_delay(auction_delay) + .with_wasm_config(*wasm_config) + .with_system_config(*system_costs_config) + .with_validator_slots(*validator_slots) + .with_auction_delay(*auction_delay) .with_locked_funds_period_millis(locked_funds_period.millis()) - .with_round_seigniorage_rate(round_seigniorage_rate) - .with_unbonding_delay(unbonding_delay) + .with_round_seigniorage_rate(*round_seigniorage_rate) + .with_unbonding_delay(*unbonding_delay) .with_genesis_timestamp_millis(DEFAULT_GENESIS_TIMESTAMP_MILLIS) .build(); diff --git a/execution_engine_testing/test_support/src/execute_request_builder.rs b/execution_engine_testing/test_support/src/execute_request_builder.rs index 828b0f0724..3000a00852 100644 --- a/execution_engine_testing/test_support/src/execute_request_builder.rs +++ b/execution_engine_testing/test_support/src/execute_request_builder.rs @@ -4,40 +4,42 @@ use casper_execution_engine::engine_state::{ deploy_item::DeployItem, ExecutableItem, WasmV1Request, }; use casper_types::{ - account::AccountHash, runtime_args, AddressableEntityHash, BlockTime, Digest, EntityVersion, - Gas, InitiatorAddr, PackageHash, Phase, RuntimeArgs, Transaction, TransactionHash, - TransactionV1Hash, + account::AccountHash, addressable_entity::DEFAULT_ENTRY_POINT_NAME, runtime_args, + AddressableEntityHash, BlockTime, Digest, EntityVersion, Gas, InitiatorAddr, PackageHash, + Phase, RuntimeArgs, Transaction, TransactionHash, TransactionV1Hash, }; use crate::{DeployItemBuilder, ARG_AMOUNT, DEFAULT_BLOCK_TIME, DEFAULT_PAYMENT}; /// A request comprising a [`WasmV1Request`] for use as session code, and an optional custom /// payment `WasmV1Request`. -pub struct ExecuteRequest<'a> { +#[derive(Debug)] +pub struct ExecuteRequest { /// The session request. - pub session: WasmV1Request<'a>, + pub session: WasmV1Request, /// The optional custom payment request. - pub custom_payment: Option>, + pub custom_payment: Option, } /// Builds an [`ExecuteRequest`]. #[derive(Debug)] -pub struct ExecuteRequestBuilder<'a> { +pub struct ExecuteRequestBuilder { state_hash: Digest, block_time: BlockTime, transaction_hash: TransactionHash, initiator_addr: InitiatorAddr, - payment: Option>, + payment: Option, payment_gas_limit: Gas, + payment_entry_point: String, payment_args: RuntimeArgs, - session: ExecutableItem<'a>, + session: ExecutableItem, session_gas_limit: Gas, session_entry_point: String, session_args: RuntimeArgs, authorization_keys: BTreeSet, } -impl<'a> ExecuteRequestBuilder<'a> { +impl ExecuteRequestBuilder { /// The default value used for `WasmV1Request::state_hash`. pub const DEFAULT_STATE_HASH: Digest = Digest::from_raw([1; 32]); /// The default value used for `WasmV1Request::transaction_hash`. @@ -47,7 +49,7 @@ impl<'a> ExecuteRequestBuilder<'a> { pub const DEFAULT_ENTRY_POINT: &'static str = "call"; /// Converts a `Transaction` into an `ExecuteRequestBuilder`. - pub fn from_transaction(txn: &'a Transaction) -> Self { + pub fn from_transaction(txn: &Transaction) -> Self { let authorization_keys = txn.authorization_keys(); let session = WasmV1Request::new_session( Self::DEFAULT_STATE_HASH, @@ -59,10 +61,12 @@ impl<'a> ExecuteRequestBuilder<'a> { let payment: Option; let payment_gas_limit: Gas; + let payment_entry_point: String; let payment_args: RuntimeArgs; if txn.is_standard_payment() { payment = None; payment_gas_limit = Gas::zero(); + payment_entry_point = DEFAULT_ENTRY_POINT_NAME.to_string(); payment_args = RuntimeArgs::new(); } else { let request = WasmV1Request::new_custom_payment( @@ -74,6 +78,7 @@ impl<'a> ExecuteRequestBuilder<'a> { .unwrap(); payment = Some(request.executable_item); payment_gas_limit = request.gas_limit; + payment_entry_point = request.entry_point; payment_args = request.args; } @@ -84,6 +89,7 @@ impl<'a> ExecuteRequestBuilder<'a> { initiator_addr: session.initiator_addr, payment, payment_gas_limit, + payment_entry_point, payment_args, session: session.executable_item, session_gas_limit: session.gas_limit, @@ -94,7 +100,7 @@ impl<'a> ExecuteRequestBuilder<'a> { } /// Converts a `DeployItem` into an `ExecuteRequestBuilder`. - pub fn from_deploy_item(deploy_item: &'a DeployItem) -> Self { + pub fn from_deploy_item(deploy_item: &DeployItem) -> Self { let authorization_keys = deploy_item.authorization_keys.clone(); let session = WasmV1Request::new_session_from_deploy_item( Self::DEFAULT_STATE_HASH, @@ -106,10 +112,12 @@ impl<'a> ExecuteRequestBuilder<'a> { let payment: Option; let payment_gas_limit: Gas; + let payment_entry_point: String; let payment_args: RuntimeArgs; if deploy_item.payment.is_standard_payment(Phase::Payment) { payment = None; payment_gas_limit = Gas::zero(); + payment_entry_point = DEFAULT_ENTRY_POINT_NAME.to_string(); payment_args = RuntimeArgs::new(); } else { let request = WasmV1Request::new_custom_payment_from_deploy_item( @@ -121,6 +129,7 @@ impl<'a> ExecuteRequestBuilder<'a> { .unwrap(); payment = Some(request.executable_item); payment_gas_limit = request.gas_limit; + payment_entry_point = request.entry_point; payment_args = request.args; } @@ -131,6 +140,7 @@ impl<'a> ExecuteRequestBuilder<'a> { initiator_addr: session.initiator_addr, payment, payment_gas_limit, + payment_entry_point, payment_args, session: session.executable_item, session_gas_limit: session.gas_limit, @@ -154,7 +164,7 @@ impl<'a> ExecuteRequestBuilder<'a> { }) .with_authorization_keys(&[account_hash]) .build(); - Self::from_deploy_item(Box::leak(Box::new(deploy_item))) + Self::from_deploy_item(&deploy_item) } /// Returns an [`ExecuteRequest`] derived from a deploy with session module bytes. @@ -171,7 +181,7 @@ impl<'a> ExecuteRequestBuilder<'a> { }) .with_authorization_keys(&[account_hash]) .build(); - Self::from_deploy_item(Box::leak(Box::new(deploy_item))) + Self::from_deploy_item(&deploy_item) } /// Returns an [`ExecuteRequest`] derived from a deploy with a session item that will call a @@ -188,7 +198,7 @@ impl<'a> ExecuteRequestBuilder<'a> { .with_standard_payment(runtime_args! { ARG_AMOUNT => *DEFAULT_PAYMENT, }) .with_authorization_keys(&[sender]) .build(); - Self::from_deploy_item(Box::leak(Box::new(deploy_item))) + Self::from_deploy_item(&deploy_item) } /// Returns an [`ExecuteRequest`] derived from a deploy with a session item that will call a @@ -205,7 +215,7 @@ impl<'a> ExecuteRequestBuilder<'a> { .with_standard_payment(runtime_args! { ARG_AMOUNT => *DEFAULT_PAYMENT, }) .with_authorization_keys(&[sender]) .build(); - Self::from_deploy_item(Box::leak(Box::new(deploy_item))) + Self::from_deploy_item(&deploy_item) } /// Returns an [`ExecuteRequest`] derived from a deploy with a session item that will call a @@ -228,7 +238,7 @@ impl<'a> ExecuteRequestBuilder<'a> { .with_standard_payment(runtime_args! { ARG_AMOUNT => *DEFAULT_PAYMENT, }) .with_authorization_keys(&[sender]) .build(); - Self::from_deploy_item(Box::leak(Box::new(deploy_item))) + Self::from_deploy_item(&deploy_item) } /// Returns an [`ExecuteRequest`] derived from a deploy with a session item that will call a @@ -246,7 +256,7 @@ impl<'a> ExecuteRequestBuilder<'a> { .with_standard_payment(runtime_args! { ARG_AMOUNT => *DEFAULT_PAYMENT, }) .with_authorization_keys(&[sender]) .build(); - Self::from_deploy_item(Box::leak(Box::new(deploy_item))) + Self::from_deploy_item(&deploy_item) } /// Sets the block time of the [`WasmV1Request`]s. @@ -262,7 +272,7 @@ impl<'a> ExecuteRequestBuilder<'a> { } /// Consumes self and returns an `ExecuteRequest`. - pub fn build(self) -> ExecuteRequest<'a> { + pub fn build(self) -> ExecuteRequest { let ExecuteRequestBuilder { state_hash, block_time, @@ -270,6 +280,7 @@ impl<'a> ExecuteRequestBuilder<'a> { initiator_addr, payment, payment_gas_limit, + payment_entry_point, payment_args, session, session_gas_limit, @@ -285,9 +296,10 @@ impl<'a> ExecuteRequestBuilder<'a> { gas_limit: payment_gas_limit, initiator_addr: initiator_addr.clone(), executable_item, - entry_point: Self::DEFAULT_ENTRY_POINT.to_string(), + entry_point: payment_entry_point, args: payment_args, authorization_keys: authorization_keys.clone(), + phase: Phase::Payment, }); let session = WasmV1Request { @@ -300,6 +312,7 @@ impl<'a> ExecuteRequestBuilder<'a> { entry_point: session_entry_point, args: session_args, authorization_keys, + phase: Phase::Session, }; ExecuteRequest { diff --git a/execution_engine_testing/test_support/src/wasm_test_builder.rs b/execution_engine_testing/test_support/src/wasm_test_builder.rs index 2aea4d2fae..48f39ebe6f 100644 --- a/execution_engine_testing/test_support/src/wasm_test_builder.rs +++ b/execution_engine_testing/test_support/src/wasm_test_builder.rs @@ -21,15 +21,15 @@ use casper_execution_engine::engine_state::{ }; use casper_storage::{ data_access_layer::{ - balance::BalanceHandling, AuctionMethod, BalanceRequest, BalanceResult, BiddingRequest, - BiddingResult, BidsRequest, BlockRewardsRequest, BlockRewardsResult, BlockStore, - DataAccessLayer, EraValidatorsRequest, EraValidatorsResult, FeeRequest, FeeResult, - FlushRequest, FlushResult, GenesisRequest, GenesisResult, ProtocolUpgradeRequest, - ProtocolUpgradeResult, PruneRequest, PruneResult, QueryRequest, QueryResult, - RoundSeigniorageRateRequest, RoundSeigniorageRateResult, StepRequest, StepResult, - SystemEntityRegistryPayload, SystemEntityRegistryRequest, SystemEntityRegistryResult, - SystemEntityRegistrySelector, TotalSupplyRequest, TotalSupplyResult, TransferRequest, - TrieRequest, + balance::BalanceHandling, AuctionMethod, BalanceIdentifier, BalanceRequest, BalanceResult, + BiddingRequest, BiddingResult, BidsRequest, BlockRewardsRequest, BlockRewardsResult, + BlockStore, DataAccessLayer, EraValidatorsRequest, EraValidatorsResult, FeeRequest, + FeeResult, FlushRequest, FlushResult, GenesisRequest, GenesisResult, + ProtocolUpgradeRequest, ProtocolUpgradeResult, PruneRequest, PruneResult, QueryRequest, + QueryResult, RoundSeigniorageRateRequest, RoundSeigniorageRateResult, StepRequest, + StepResult, SystemEntityRegistryPayload, SystemEntityRegistryRequest, + SystemEntityRegistryResult, SystemEntityRegistrySelector, TotalSupplyRequest, + TotalSupplyResult, TransferRequest, TrieRequest, }, global_state::{ state::{ @@ -833,6 +833,7 @@ where } execute_request.session.state_hash = self.post_state_hash.expect("expected post_state_hash"); + let session_result = self .execution_engine .execute(self.data_access_layer.as_ref(), execute_request.session); @@ -843,6 +844,18 @@ where self } + /// Execute a `WasmV1Request`. + pub fn exec_wasm_v1(&mut self, mut request: WasmV1Request) -> &mut Self { + request.state_hash = self.post_state_hash.expect("expected post_state_hash"); + let result = self + .execution_engine + .execute(self.data_access_layer.as_ref(), request); + let effects = result.effects().clone(); + self.exec_results.push(result); + self.effects.push(effects); + self + } + /// Commit effects of previous exec call on the latest post-state hash. pub fn commit(&mut self) -> &mut Self { let prestate_hash = self.post_state_hash.expect("Should have genesis hash"); @@ -1209,7 +1222,7 @@ where pub fn get_purse_balance_result( &self, protocol_version: ProtocolVersion, - purse: URef, + balance_identifier: BalanceIdentifier, block_time: u64, ) -> BalanceResult { let hold_interval = self.chainspec.core_config.balance_hold_interval.millis(); @@ -1217,8 +1230,12 @@ where let balance_handling = BalanceHandling::Available { holds_epoch }; let state_root_hash: Digest = self.post_state_hash.expect("should have post_state_hash"); - let request = - BalanceRequest::from_purse(state_root_hash, protocol_version, purse, balance_handling); + let request = BalanceRequest::new( + state_root_hash, + protocol_version, + balance_identifier, + balance_handling, + ); self.data_access_layer.balance(request) } diff --git a/execution_engine_testing/tests/src/test/contract_api/get_call_stack.rs b/execution_engine_testing/tests/src/test/contract_api/get_call_stack.rs index 9601c8f4bf..70220c6e54 100644 --- a/execution_engine_testing/tests/src/test/contract_api/get_call_stack.rs +++ b/execution_engine_testing/tests/src/test/contract_api/get_call_stack.rs @@ -3573,7 +3573,6 @@ mod payment { #[ignore] #[allow(unused)] - // #[test] fn stored_versioned_payment_by_name_to_stored_versioned_session() { for call_depth in DEPTHS { let mut builder = super::setup(); @@ -3599,7 +3598,6 @@ mod payment { #[ignore] #[allow(unused)] - // #[test] fn stored_versioned_payment_by_hash_to_stored_versioned_session() { for call_depth in DEPTHS { let mut builder = super::setup(); @@ -3629,7 +3627,6 @@ mod payment { #[ignore] #[allow(unused)] - // #[test] fn stored_versioned_payment_by_name_to_stored_session() { for call_depth in DEPTHS { let mut builder = super::setup(); @@ -3650,7 +3647,6 @@ mod payment { #[ignore] #[allow(unused)] - // #[test] fn stored_versioned_payment_by_hash_to_stored_session() { for call_depth in DEPTHS { let mut builder = super::setup(); @@ -3679,7 +3675,6 @@ mod payment { #[ignore] #[allow(unused)] - // #[test] fn stored_payment_by_name_to_stored_versioned_session() { for call_depth in DEPTHS { let mut builder = super::setup(); @@ -3705,7 +3700,6 @@ mod payment { #[ignore] #[allow(unused)] - // #[test] fn stored_payment_by_hash_to_stored_versioned_session() { for call_depth in DEPTHS { let mut builder = super::setup(); @@ -3738,7 +3732,6 @@ mod payment { #[ignore] #[allow(unused)] - // #[test] fn stored_payment_by_name_to_stored_session() { for call_depth in DEPTHS { let mut builder = super::setup(); @@ -3759,7 +3752,6 @@ mod payment { #[ignore] #[allow(unused)] - // #[test] fn stored_payment_by_hash_to_stored_session() { for call_depth in DEPTHS { let mut builder = super::setup(); @@ -3785,7 +3777,6 @@ mod payment { #[ignore] #[allow(unused)] - // #[test] fn stored_versioned_payment_by_name_to_stored_versioned_contract() { for call_depth in DEPTHS { let mut builder = super::setup(); @@ -3811,7 +3802,6 @@ mod payment { #[ignore] #[allow(unused)] - // #[test] fn stored_versioned_payment_by_hash_to_stored_versioned_contract() { for call_depth in DEPTHS { let mut builder = super::setup(); @@ -3842,7 +3832,6 @@ mod payment { #[ignore] #[allow(unused)] - // #[test] fn stored_versioned_payment_by_name_to_stored_contract() { for call_depth in DEPTHS { let mut builder = super::setup(); @@ -3863,7 +3852,6 @@ mod payment { #[ignore] #[allow(unused)] - // #[test] fn stored_versioned_payment_by_hash_to_stored_contract() { for call_depth in DEPTHS { let mut builder = super::setup(); @@ -3892,7 +3880,6 @@ mod payment { #[ignore] #[allow(unused)] - // #[test] fn stored_payment_by_name_to_stored_versioned_contract() { for call_depth in DEPTHS { let mut builder = super::setup(); @@ -3917,7 +3904,6 @@ mod payment { #[ignore] #[allow(unused)] - // #[test] fn stored_payment_by_hash_to_stored_versioned_contract() { for call_depth in DEPTHS { let mut builder = super::setup(); @@ -3950,7 +3936,6 @@ mod payment { #[ignore] #[allow(unused)] - // #[test] fn stored_payment_by_name_to_stored_contract() { for call_depth in DEPTHS { let mut builder = super::setup(); @@ -3971,7 +3956,7 @@ mod payment { #[ignore] #[allow(unused)] - // #[test] + #[test] fn stored_payment_by_hash_to_stored_contract() { for call_depth in DEPTHS { let mut builder = super::setup(); @@ -3999,7 +3984,6 @@ mod payment { #[ignore] #[allow(unused)] - // #[test] fn stored_versioned_payment_by_name_to_stored_versioned_contract_to_stored_versioned_session_should_fail( ) { for call_depth in DEPTHS { @@ -4031,7 +4015,6 @@ mod payment { #[ignore] #[allow(unused)] - // #[test] fn stored_versioned_payment_by_hash_to_stored_versioned_contract_to_stored_session_should_fail() { for call_depth in DEPTHS { @@ -4068,7 +4051,6 @@ mod payment { #[ignore] #[allow(unused)] - // #[test] fn stored_versioned_payment_by_name_to_stored_contract_to_stored_versioned_session_should_fail() { for call_depth in DEPTHS { @@ -4101,7 +4083,6 @@ mod payment { #[ignore] #[allow(unused)] - // #[test] fn stored_versioned_payment_by_hash_to_stored_contract_to_stored_session_should_fail() { for call_depth in DEPTHS { let mut builder = super::setup(); @@ -4136,7 +4117,6 @@ mod payment { #[ignore] #[allow(unused)] - // #[test] fn stored_payment_by_name_to_stored_versioned_contract_to_stored_versioned_session_should_fail() { for call_depth in DEPTHS { @@ -4168,7 +4148,6 @@ mod payment { #[ignore] #[allow(unused)] - // #[test] fn stored_session_by_hash_to_stored_versioned_contract_to_stored_session_should_fail() { for call_depth in DEPTHS { let mut builder = super::setup(); @@ -4204,7 +4183,6 @@ mod payment { #[ignore] #[allow(unused)] - // #[test] fn stored_payment_by_name_to_stored_contract_to_stored_versioned_session_should_fail() { for call_depth in DEPTHS { let mut builder = super::setup(); @@ -4236,7 +4214,6 @@ mod payment { #[ignore] #[allow(unused)] - // #[test] fn stored_payment_by_name_to_stored_contract_to_stored_session_should_fail() { for call_depth in DEPTHS { let mut builder = super::setup(); diff --git a/execution_engine_testing/tests/src/test/contract_api/transfer.rs b/execution_engine_testing/tests/src/test/contract_api/transfer.rs index 443af358bd..60a378ce43 100644 --- a/execution_engine_testing/tests/src/test/contract_api/transfer.rs +++ b/execution_engine_testing/tests/src/test/contract_api/transfer.rs @@ -470,41 +470,105 @@ fn should_fail_when_insufficient_funds() { #[ignore] #[allow(unused)] -// #[test] +#[test] fn should_transfer_total_amount() { - let mut builder = LmdbWasmTestBuilder::default(); - - let exec_request_1 = ExecuteRequestBuilder::standard( - *DEFAULT_ACCOUNT_ADDR, - CONTRACT_TRANSFER_PURSE_TO_ACCOUNT, - runtime_args! { "target" => *ACCOUNT_1_ADDR, "amount" => *ACCOUNT_1_INITIAL_BALANCE }, - ) - .build(); - - let transfer_amount_1 = *ACCOUNT_1_INITIAL_BALANCE - *DEFAULT_PAYMENT; - - let exec_request_2 = ExecuteRequestBuilder::standard( - *ACCOUNT_1_ADDR, - CONTRACT_TRANSFER_PURSE_TO_ACCOUNT, - runtime_args! { "target" => *ACCOUNT_2_ADDR, "amount" => transfer_amount_1 }, - ) - .build(); - - builder.run_genesis(LOCAL_GENESIS_REQUEST.clone()); - - builder.exec(exec_request_1).expect_success().commit(); - - builder.exec(exec_request_2).commit().expect_success(); + // NOTE: as of protocol version 2.0.0 the execution engine is no longer reponsible + // for payment, refund, or fee handling...thus + // full transactions executed via the node are subject to payment, fee, refund, + // etc based upon chainspec settings, but when using the EE directly as is done + // in this test, there is no charge and all transfers are at face value. + fn balance_checker(bldr: &mut LmdbWasmTestBuilder, account_hash: AccountHash) -> U512 { + let entity = bldr + .get_entity_by_account_hash(account_hash) + .expect("should have account entity"); + let entity_main_purse = entity.main_purse(); + bldr.get_purse_balance(entity_main_purse) + } + fn commit(bldr: &mut LmdbWasmTestBuilder, req_bldr: ExecuteRequestBuilder) { + let req = req_bldr.build(); + bldr.exec(req).expect_success().commit(); + } + fn genesis() -> LmdbWasmTestBuilder { + let mut builder = LmdbWasmTestBuilder::default(); + builder.run_genesis(LOCAL_GENESIS_REQUEST.clone()); + builder + } + + let mut builder = genesis(); + + let balance_x_initial = balance_checker(&mut builder, *DEFAULT_ACCOUNT_ADDR); + let amount_to_fund = *ACCOUNT_1_INITIAL_BALANCE; + + // fund account 1 from default account + commit( + &mut builder, + ExecuteRequestBuilder::standard( + *DEFAULT_ACCOUNT_ADDR, + CONTRACT_TRANSFER_PURSE_TO_ACCOUNT, + runtime_args! { "target" => *ACCOUNT_1_ADDR, "amount" => amount_to_fund }, + ), + ); + let balance_x_out = balance_checker(&mut builder, *DEFAULT_ACCOUNT_ADDR); + assert_eq!( + balance_x_initial - amount_to_fund, + balance_x_out, + "funded amount should be deducted from funder's balance" + ); + let balance_y_initial = balance_checker(&mut builder, *ACCOUNT_1_ADDR); + assert_eq!( + amount_to_fund, balance_y_initial, + "receiving account's balance should match funding amount" + ); + let diff = balance_x_initial - balance_y_initial; + assert_eq!( + diff, balance_x_out, + "funder's balance difference should equal funded amount" + ); - let account_1 = builder - .get_entity_by_account_hash(*ACCOUNT_1_ADDR) - .expect("should have account"); - let account_1_main_purse = account_1.main_purse(); - let account_1_balance = builder.get_purse_balance(account_1_main_purse); + // transfer it to a different account + commit( + &mut builder, + ExecuteRequestBuilder::standard( + *ACCOUNT_1_ADDR, + CONTRACT_TRANSFER_PURSE_TO_ACCOUNT, + runtime_args! { "target" => *ACCOUNT_2_ADDR, "amount" => balance_y_initial }, + ), + ); + let balance_y_out = balance_checker(&mut builder, *ACCOUNT_1_ADDR); + assert_eq!( + balance_y_initial - amount_to_fund, + balance_y_out, + "funded amount should be deducted from funder's balance" + ); + let balance_z_initial = balance_checker(&mut builder, *ACCOUNT_2_ADDR); + assert_eq!( + amount_to_fund, balance_z_initial, + "receiving account's balance should match funding amount" + ); + let diff = balance_y_initial - balance_z_initial; + assert_eq!( + diff, balance_y_out, + "funder's balance difference should equal funded amount" + ); + // transfer it back to originator + commit( + &mut builder, + ExecuteRequestBuilder::standard( + *ACCOUNT_2_ADDR, + CONTRACT_TRANSFER_PURSE_TO_ACCOUNT, + runtime_args! { "target" => *DEFAULT_ACCOUNT_ADDR, "amount" => balance_z_initial }, + ), + ); + let balance_x_in = balance_checker(&mut builder, *DEFAULT_ACCOUNT_ADDR); + let balance_z_out = balance_checker(&mut builder, *ACCOUNT_2_ADDR); assert_eq!( - account_1_balance, - builder.calculate_refund_amount(*DEFAULT_PAYMENT), - "account 1 should only have refunded amount after transferring full amount" + U512::zero(), + balance_z_out, + "trampoline account should be zero'd" + ); + assert_eq!( + balance_x_initial, balance_x_in, + "original balance should be restored" ); } diff --git a/execution_engine_testing/tests/src/test/deploy/non_standard_payment.rs b/execution_engine_testing/tests/src/test/deploy/non_standard_payment.rs index 3c20a7dad9..cac1baa96c 100644 --- a/execution_engine_testing/tests/src/test/deploy/non_standard_payment.rs +++ b/execution_engine_testing/tests/src/test/deploy/non_standard_payment.rs @@ -1,8 +1,11 @@ use casper_engine_test_support::{ DeployItemBuilder, ExecuteRequestBuilder, LmdbWasmTestBuilder, DEFAULT_ACCOUNT_ADDR, - DEFAULT_PAYMENT, LOCAL_GENESIS_REQUEST, MINIMUM_ACCOUNT_CREATION_BALANCE, + DEFAULT_PAYMENT, DEFAULT_PROTOCOL_VERSION, LOCAL_GENESIS_REQUEST, + MINIMUM_ACCOUNT_CREATION_BALANCE, }; -use casper_types::{account::AccountHash, runtime_args, RuntimeArgs, U512}; +use casper_execution_engine::engine_state::WasmV1Request; +use casper_storage::data_access_layer::BalanceIdentifier; +use casper_types::{account::AccountHash, runtime_args, Digest, Gas, RuntimeArgs, Timestamp, U512}; const ACCOUNT_1_ADDR: AccountHash = AccountHash::new([42u8; 32]); const DO_NOTHING_WASM: &str = "do_nothing.wasm"; @@ -16,14 +19,13 @@ const ARG_DESTINATION: &str = "destination"; #[ignore] #[allow(unused)] -// #[test] +#[test] fn should_charge_non_main_purse() { // as account_1, create & fund a new purse and use that to pay for something // instead of account_1 main purse const TEST_PURSE_NAME: &str = "test-purse"; let account_1_account_hash = ACCOUNT_1_ADDR; - let payment_purse_amount = *DEFAULT_PAYMENT; let account_1_funding_amount = U512::from(MINIMUM_ACCOUNT_CREATION_BALANCE); let account_1_purse_funding_amount = *DEFAULT_PAYMENT; @@ -41,7 +43,7 @@ fn should_charge_non_main_purse() { TRANSFER_MAIN_PURSE_TO_NEW_PURSE_WASM, runtime_args! { ARG_DESTINATION => TEST_PURSE_NAME, ARG_AMOUNT => account_1_purse_funding_amount }, ) - .build(); + .build(); builder.run_genesis(LOCAL_GENESIS_REQUEST.clone()); @@ -60,14 +62,16 @@ fn should_charge_non_main_purse() { // get purse let purse_key = account_1.named_keys().get(TEST_PURSE_NAME).unwrap(); let purse = purse_key.into_uref().expect("should have uref"); - let purse_starting_balance = builder.get_purse_balance(purse); assert_eq!( purse_starting_balance, account_1_purse_funding_amount, - "purse should be funded with expected amount" + "purse should be funded with expected amount, which in this case is also == to the amount to be paid" ); + // in this test, we're just going to pay everything in the purse to + // keep the math easy. + let amount_to_be_paid = account_1_purse_funding_amount; // should be able to pay for exec using new purse let deploy_item = DeployItemBuilder::new() .with_address(ACCOUNT_1_ADDR) @@ -76,31 +80,53 @@ fn should_charge_non_main_purse() { NAMED_PURSE_PAYMENT_WASM, runtime_args! { ARG_PURSE_NAME => TEST_PURSE_NAME, - ARG_AMOUNT => payment_purse_amount + ARG_AMOUNT => amount_to_be_paid }, ) .with_authorization_keys(&[account_1_account_hash]) .with_deploy_hash([3; 32]) .build(); - let account_payment_exec_request = - ExecuteRequestBuilder::from_deploy_item(&deploy_item).build(); - - let proposer_reward_starting_balance = builder.get_proposer_purse_balance(); + let block_time = Timestamp::now().millis(); builder - .exec(account_payment_exec_request) + .exec_wasm_v1( + WasmV1Request::new_custom_payment_from_deploy_item( + Digest::default(), + block_time.into(), + Gas::from(12_500_000_000_u64), + &deploy_item, + ) + .expect("should be valid req"), + ) .expect_success() .commit(); - let transaction_fee = builder.get_proposer_purse_balance() - proposer_reward_starting_balance; + let payment_purse_balance = builder.get_purse_balance_result( + DEFAULT_PROTOCOL_VERSION, + BalanceIdentifier::Payment, + block_time, + ); - let expected_resting_balance = account_1_purse_funding_amount - transaction_fee; + assert!( + payment_purse_balance.is_success(), + "payment purse balance check should succeed" + ); - let purse_final_balance = builder.get_purse_balance(purse); + let paid_amount = *payment_purse_balance + .motes() + .expect("should have payment amount"); assert_eq!( - purse_final_balance, expected_resting_balance, + paid_amount, amount_to_be_paid, "purse resting balance should equal funding amount minus exec costs" ); + + let purse_final_balance = builder.get_purse_balance(purse); + + assert_eq!( + purse_final_balance, + U512::zero(), + "since we zero'd out the paying purse, the final balance should be zero" + ); } diff --git a/execution_engine_testing/tests/src/test/deploy/stored_contracts.rs b/execution_engine_testing/tests/src/test/deploy/stored_contracts.rs index c771b9f31e..9d1e449407 100644 --- a/execution_engine_testing/tests/src/test/deploy/stored_contracts.rs +++ b/execution_engine_testing/tests/src/test/deploy/stored_contracts.rs @@ -285,7 +285,7 @@ fn should_not_transfer_above_balance_using_stored_payment_code_by_hash() { #[ignore] #[allow(unused)] -// #[test] +#[test] fn should_empty_account_using_stored_payment_code_by_hash() { let payment_purse_amount = *DEFAULT_PAYMENT; diff --git a/execution_engine_testing/tests/src/test/explorer/faucet.rs b/execution_engine_testing/tests/src/test/explorer/faucet.rs index fab2d9125e..9bfbc94020 100644 --- a/execution_engine_testing/tests/src/test/explorer/faucet.rs +++ b/execution_engine_testing/tests/src/test/explorer/faucet.rs @@ -926,10 +926,10 @@ 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 = 91_842_307_540; - const EXPECTED_FAUCET_SET_VARIABLES_COST: u64 = 110_733_980; - const EXPECTED_FAUCET_CALL_BY_INSTALLER_COST: u64 = 2_774_317_720; - const EXPECTED_FAUCET_CALL_BY_USER_COST: u64 = 2_618_815_540; + const EXPECTED_FAUCET_INSTALL_COST: u64 = 91_914_271_090; + const EXPECTED_FAUCET_SET_VARIABLES_COST: u64 = 111_340_630; + const EXPECTED_FAUCET_CALL_BY_INSTALLER_COST: u64 = 2_774_911_250; + const EXPECTED_FAUCET_CALL_BY_USER_COST: u64 = 2_619_882_230; let installer_account = AccountHash::new([1u8; 32]); let user_account: AccountHash = AccountHash::new([2u8; 32]); diff --git a/execution_engine_testing/tests/src/test/explorer/faucet_test_helpers.rs b/execution_engine_testing/tests/src/test/explorer/faucet_test_helpers.rs index ee3de0cd71..c78209c35a 100644 --- a/execution_engine_testing/tests/src/test/explorer/faucet_test_helpers.rs +++ b/execution_engine_testing/tests/src/test/explorer/faucet_test_helpers.rs @@ -97,7 +97,7 @@ impl FaucetInstallSessionRequestBuilder { self } - pub fn build(&self) -> ExecuteRequest<'static> { + pub fn build(&self) -> ExecuteRequest { ExecuteRequestBuilder::standard( self.installer_account, &self.faucet_installer_session, @@ -159,7 +159,7 @@ impl FaucetConfigRequestBuilder { self } - pub fn build(&self) -> ExecuteRequest<'static> { + pub fn build(&self) -> ExecuteRequest { ExecuteRequestBuilder::contract_call_by_hash( self.installer_account, self.faucet_contract_hash @@ -219,7 +219,7 @@ impl FaucetAuthorizeAccountRequestBuilder { self } - pub fn build<'a>(self) -> ExecuteRequest<'a> { + pub fn build(self) -> ExecuteRequest { ExecuteRequestBuilder::contract_call_by_hash( self.installer_account, self.faucet_contract_hash @@ -315,7 +315,7 @@ impl FaucetFundRequestBuilder { self } - pub fn build(self) -> ExecuteRequest<'static> { + pub fn build(self) -> ExecuteRequest { let mut rng = rand::thread_rng(); let deploy_item = DeployItemBuilder::new() @@ -342,14 +342,10 @@ impl FaucetFundRequestBuilder { .build(); match self.block_time { - Some(block_time) => { - ExecuteRequestBuilder::from_deploy_item(Box::leak(Box::new(deploy_item))) - .with_block_time(block_time) - .build() - } - None => { - ExecuteRequestBuilder::from_deploy_item(Box::leak(Box::new(deploy_item))).build() - } + Some(block_time) => ExecuteRequestBuilder::from_deploy_item(&deploy_item) + .with_block_time(block_time) + .build(), + None => ExecuteRequestBuilder::from_deploy_item(&deploy_item).build(), } } } @@ -559,7 +555,7 @@ impl FaucetDeployHelper { .build() } - pub fn faucet_install_request(&self) -> ExecuteRequest<'static> { + pub fn faucet_install_request(&self) -> ExecuteRequest { self.faucet_install_session_request_builder .clone() .with_installer_account(self.installer_account) @@ -569,7 +565,7 @@ impl FaucetDeployHelper { .build() } - pub fn faucet_config_request(&self) -> ExecuteRequest<'static> { + pub fn faucet_config_request(&self) -> ExecuteRequest { self.faucet_config_request_builder .with_installer_account(self.installer_account()) .with_faucet_contract_hash( diff --git a/execution_engine_testing/tests/src/test/get_balance.rs b/execution_engine_testing/tests/src/test/get_balance.rs index 9ef06d0959..c324cbc085 100644 --- a/execution_engine_testing/tests/src/test/get_balance.rs +++ b/execution_engine_testing/tests/src/test/get_balance.rs @@ -3,7 +3,10 @@ use once_cell::sync::Lazy; use casper_engine_test_support::{ LmdbWasmTestBuilder, TransferRequestBuilder, LOCAL_GENESIS_REQUEST, }; -use casper_storage::tracking_copy::{self, ValidationError}; +use casper_storage::{ + data_access_layer::BalanceIdentifier, + tracking_copy::{self, ValidationError}, +}; use casper_types::{ account::AccountHash, AccessRights, Digest, Key, ProtocolVersion, PublicKey, SecretKey, URef, U512, @@ -39,8 +42,11 @@ fn get_balance_should_work() { let alice_main_purse = alice_account.main_purse(); - let alice_balance_result = - builder.get_purse_balance_result(protocol_version, alice_main_purse, block_time); + let alice_balance_result = builder.get_purse_balance_result( + protocol_version, + BalanceIdentifier::Purse(alice_main_purse), + block_time, + ); let alice_balance = alice_balance_result .motes() diff --git a/execution_engine_testing/tests/src/test/regression/ee_966.rs b/execution_engine_testing/tests/src/test/regression/ee_966.rs index 26785ac415..ee472bf628 100644 --- a/execution_engine_testing/tests/src/test/regression/ee_966.rs +++ b/execution_engine_testing/tests/src/test/regression/ee_966.rs @@ -57,7 +57,7 @@ fn make_session_code_with_memory_pages(initial_pages: u32, max_pages: Option(session_code: Vec) -> ExecuteRequest<'a> { +fn make_request_with_session_bytes(session_code: Vec) -> ExecuteRequest { let deploy_item = DeployItemBuilder::new() .with_address(*DEFAULT_ACCOUNT_ADDR) .with_session_bytes(session_code, RuntimeArgs::new()) @@ -68,7 +68,7 @@ fn make_request_with_session_bytes<'a>(session_code: Vec) -> ExecuteRequest< .with_deploy_hash([42; 32]) .build(); - ExecuteRequestBuilder::from_deploy_item(Box::leak(Box::new(deploy_item))).build() + ExecuteRequestBuilder::from_deploy_item(&deploy_item).build() } #[ignore] diff --git a/execution_engine_testing/tests/src/test/regression/host_function_metrics_size_and_gas_cost.rs b/execution_engine_testing/tests/src/test/regression/host_function_metrics_size_and_gas_cost.rs index 3c6debc79f..b594619e28 100644 --- a/execution_engine_testing/tests/src/test/regression/host_function_metrics_size_and_gas_cost.rs +++ b/execution_engine_testing/tests/src/test/regression/host_function_metrics_size_and_gas_cost.rs @@ -59,7 +59,7 @@ fn host_function_metrics_has_acceptable_size() { ) } -fn create_account_exec_request<'a>(address: AccountHash) -> ExecuteRequest<'a> { +fn create_account_exec_request(address: AccountHash) -> ExecuteRequest { ExecuteRequestBuilder::standard( *DEFAULT_ACCOUNT_ADDR, CONTRACT_TRANSFER_TO_ACCOUNT_U512, diff --git a/execution_engine_testing/tests/src/test/regression/regression_20210707.rs b/execution_engine_testing/tests/src/test/regression/regression_20210707.rs index 61b06555cb..d3cdb68ed2 100644 --- a/execution_engine_testing/tests/src/test/regression/regression_20210707.rs +++ b/execution_engine_testing/tests/src/test/regression/regression_20210707.rs @@ -42,7 +42,7 @@ static BOB_KEY: Lazy = Lazy::new(|| { }); static BOB_ADDR: Lazy = Lazy::new(|| AccountHash::from(&*BOB_KEY)); -fn setup_regression_contract<'a>() -> ExecuteRequest<'a> { +fn setup_regression_contract() -> ExecuteRequest { ExecuteRequestBuilder::standard( *DEFAULT_ACCOUNT_ADDR, REGRESSION_20210707, diff --git a/node/src/components/transaction_acceptor/tests.rs b/node/src/components/transaction_acceptor/tests.rs index 51b9c1a0e4..2e6107a20e 100644 --- a/node/src/components/transaction_acceptor/tests.rs +++ b/node/src/components/transaction_acceptor/tests.rs @@ -559,7 +559,7 @@ impl TestScenario { let classic_mode_transaction = TransactionV1Builder::new_random(rng) .with_pricing_mode(PricingMode::Classic { payment_amount: 10000u64, - gas_price: 1u8, + gas_price_tolerance: 1u8, standard_payment: true, }) .with_chain_name("casper-example") diff --git a/resources/test/sse_data_schema.json b/resources/test/sse_data_schema.json index f9f9c1f557..9c1147ab4c 100644 --- a/resources/test/sse_data_schema.json +++ b/resources/test/sse_data_schema.json @@ -1637,7 +1637,7 @@ "Classic": { "type": "object", "required": [ - "gas_price", + "gas_price_tolerance", "payment_amount", "standard_payment" ], @@ -1648,8 +1648,8 @@ "format": "uint64", "minimum": 0.0 }, - "gas_price": { - "description": "User-specified gas_price (minimum 1).", + "gas_price_tolerance": { + "description": "User-specified gas_price tolerance (minimum 1). This is interpreted to mean \"do not include this transaction in a block if the current gas price is greater than this number\"", "type": "integer", "format": "uint8", "minimum": 0.0 diff --git a/storage/src/data_access_layer/balance.rs b/storage/src/data_access_layer/balance.rs index 50acb56e33..14510c7c32 100644 --- a/storage/src/data_access_layer/balance.rs +++ b/storage/src/data_access_layer/balance.rs @@ -345,4 +345,12 @@ impl BalanceResult { } => available_balance >= &cost, } } + + /// Was the balance request successful? + pub fn is_success(&self) -> bool { + match self { + BalanceResult::RootNotFound | BalanceResult::Failure(_) => false, + BalanceResult::Success { .. } => true, + } + } } diff --git a/types/src/transaction/deploy/deploy_header.rs b/types/src/transaction/deploy/deploy_header.rs index 737e3ff95e..09a27057cc 100644 --- a/types/src/transaction/deploy/deploy_header.rs +++ b/types/src/transaction/deploy/deploy_header.rs @@ -87,7 +87,7 @@ impl DeployHeader { pub fn gas_price(&self) -> u64 { // in the original implementation, we did not have dynamic gas pricing // but the sender of the deploy could specify a higher gas price, - // and the the payment amount would be multiplied by that number + // and the payment amount would be multiplied by that number // for settlement purposes. This did not increase their computation limit, // only how much they were charged. The intent was, the total cost // would be a consideration for block proposal but in the end we shipped diff --git a/types/src/transaction/pricing_mode.rs b/types/src/transaction/pricing_mode.rs index 74cc4fbd77..b50f13a52c 100644 --- a/types/src/transaction/pricing_mode.rs +++ b/types/src/transaction/pricing_mode.rs @@ -37,8 +37,10 @@ pub enum PricingMode { Classic { /// User-specified payment amount. payment_amount: u64, - /// User-specified gas_price (minimum 1). - gas_price: u8, + /// User-specified gas_price tolerance (minimum 1). + /// This is interpreted to mean "do not include this transaction in a block + /// if the current gas price is greater than this number" + gas_price_tolerance: u8, /// Standard payment. standard_payment: bool, }, @@ -69,7 +71,7 @@ impl PricingMode { match rng.gen_range(0..3) { 0 => PricingMode::Classic { payment_amount: rng.gen(), - gas_price: 1, + gas_price_tolerance: 1, standard_payment: true, }, 1 => PricingMode::Fixed { @@ -90,7 +92,7 @@ impl Display for PricingMode { match self { PricingMode::Classic { payment_amount, - gas_price, + gas_price_tolerance: gas_price, standard_payment, } => { write!( @@ -120,7 +122,7 @@ impl ToBytes for PricingMode { match self { PricingMode::Classic { payment_amount, - gas_price, + gas_price_tolerance: gas_price, standard_payment, } => { CLASSIC_TAG.write_bytes(writer)?; @@ -158,7 +160,7 @@ impl ToBytes for PricingMode { + match self { PricingMode::Classic { payment_amount, - gas_price, + gas_price_tolerance: gas_price, standard_payment, } => { payment_amount.serialized_length() @@ -193,7 +195,7 @@ impl FromBytes for PricingMode { Ok(( PricingMode::Classic { payment_amount, - gas_price, + gas_price_tolerance: gas_price, standard_payment, }, remainder, diff --git a/types/src/transaction/transaction_v1.rs b/types/src/transaction/transaction_v1.rs index b638b37c78..a72ddc88b8 100644 --- a/types/src/transaction/transaction_v1.rs +++ b/types/src/transaction/transaction_v1.rs @@ -1193,7 +1193,7 @@ mod tests { .with_chain_name(chain_name) .with_pricing_mode(PricingMode::Classic { payment_amount: 100000, - gas_price: 1, + gas_price_tolerance: 1, standard_payment: true, }) .build() @@ -1240,7 +1240,7 @@ mod tests { .with_chain_name(chain_name) .with_pricing_mode(PricingMode::Classic { payment_amount, - gas_price: 1, + gas_price_tolerance: 1, standard_payment: true, }); let transaction = builder.build().expect("should build"); diff --git a/types/src/transaction/transaction_v1/transaction_v1_header.rs b/types/src/transaction/transaction_v1/transaction_v1_header.rs index 8b1e4ecd01..6dbcb43123 100644 --- a/types/src/transaction/transaction_v1/transaction_v1_header.rs +++ b/types/src/transaction/transaction_v1/transaction_v1_header.rs @@ -154,7 +154,10 @@ impl TransactionV1Header { /// Returns the gas price tolerance for the given transaction. pub fn gas_price_tolerance(&self) -> u8 { match self.pricing_mode { - PricingMode::Classic { gas_price, .. } => gas_price, + PricingMode::Classic { + gas_price_tolerance, + .. + } => gas_price_tolerance, PricingMode::Fixed { gas_price_tolerance, ..