diff --git a/core/parameters/Cargo.toml b/core/parameters/Cargo.toml index 62bc4f4e25c..37f8de8e687 100644 --- a/core/parameters/Cargo.toml +++ b/core/parameters/Cargo.toml @@ -32,9 +32,11 @@ assert_matches.workspace = true insta.workspace = true [features] +protocol_feature_nonrefundable_transfer_nep491 = [] nightly = [ "near-primitives-core/nightly", "nightly_protocol", + "protocol_feature_nonrefundable_transfer_nep491", ] nightly_protocol = [ "near-primitives-core/nightly_protocol", diff --git a/core/parameters/src/cost.rs b/core/parameters/src/cost.rs index e0bdb42b9e1..3b0d3c1923a 100644 --- a/core/parameters/src/cost.rs +++ b/core/parameters/src/cost.rs @@ -264,6 +264,7 @@ pub enum ActionCosts { new_data_receipt_base = 13, new_data_receipt_byte = 14, delegate = 15, + #[cfg(feature = "protocol_feature_nonrefundable_transfer_nep491")] nonrefundable_transfer = 16, } @@ -421,6 +422,7 @@ impl RuntimeFeesConfig { send_not_sir: 115123062500, execution: 115123062500, }, + #[cfg(feature = "protocol_feature_nonrefundable_transfer_nep491")] ActionCosts::nonrefundable_transfer => Fee { send_sir: 115123062500, send_not_sir: 115123062500, @@ -519,13 +521,16 @@ pub fn transfer_exec_fee( implicit_account_creation_allowed: bool, eth_implicit_accounts_enabled: bool, receiver_account_type: AccountType, - is_nonrefundable: bool, + #[cfg(feature = "protocol_feature_nonrefundable_transfer_nep491")] is_nonrefundable: bool, ) -> Gas { + #[cfg(feature = "protocol_feature_nonrefundable_transfer_nep491")] let transfer_fee = if is_nonrefundable { cfg.fee(ActionCosts::nonrefundable_transfer).exec_fee() } else { cfg.fee(ActionCosts::transfer).exec_fee() }; + #[cfg(not(feature = "protocol_feature_nonrefundable_transfer_nep491"))] + let transfer_fee = cfg.fee(ActionCosts::transfer).exec_fee(); match (implicit_account_creation_allowed, eth_implicit_accounts_enabled, receiver_account_type) { // Regular transfer to a named account. @@ -553,13 +558,16 @@ pub fn transfer_send_fee( implicit_account_creation_allowed: bool, eth_implicit_accounts_enabled: bool, receiver_account_type: AccountType, - is_nonrefundable: bool, + #[cfg(feature = "protocol_feature_nonrefundable_transfer_nep491")] is_nonrefundable: bool, ) -> Gas { + #[cfg(feature = "protocol_feature_nonrefundable_transfer_nep491")] let transfer_fee = if is_nonrefundable { cfg.fee(ActionCosts::nonrefundable_transfer).send_fee(sender_is_receiver) } else { cfg.fee(ActionCosts::transfer).send_fee(sender_is_receiver) }; + #[cfg(not(feature = "protocol_feature_nonrefundable_transfer_nep491"))] + let transfer_fee = cfg.fee(ActionCosts::transfer).send_fee(sender_is_receiver); match (implicit_account_creation_allowed, eth_implicit_accounts_enabled, receiver_account_type) { // Regular transfer to a named account. diff --git a/core/parameters/src/parameter.rs b/core/parameters/src/parameter.rs index b4c23ed06c8..aea3a3c9e9b 100644 --- a/core/parameters/src/parameter.rs +++ b/core/parameters/src/parameter.rs @@ -199,6 +199,8 @@ pub enum FeeParameter { ActionAddFunctionCallKeyPerByte, ActionDeleteKey, ActionDelegate, + #[cfg(feature = "protocol_feature_nonrefundable_transfer_nep491")] + ActionNonrefundableStorageTransfer, } impl Parameter { @@ -252,7 +254,8 @@ impl From for FeeParameter { ActionCosts::function_call_base => Self::ActionFunctionCall, ActionCosts::function_call_byte => Self::ActionFunctionCallPerByte, ActionCosts::transfer => Self::ActionTransfer, - ActionCosts::nonrefundable_transfer => Self::ActionTransfer, // TODO + #[cfg(feature = "protocol_feature_nonrefundable_transfer_nep491")] + ActionCosts::nonrefundable_transfer => Self::ActionNonrefundableStorageTransfer, ActionCosts::stake => Self::ActionStake, ActionCosts::add_full_access_key => Self::ActionAddFullAccessKey, ActionCosts::add_function_call_key_base => Self::ActionAddFunctionCallKey, diff --git a/runtime/near-vm-runner/Cargo.toml b/runtime/near-vm-runner/Cargo.toml index 1e6be8d2397..9afbc58b831 100644 --- a/runtime/near-vm-runner/Cargo.toml +++ b/runtime/near-vm-runner/Cargo.toml @@ -113,11 +113,16 @@ protocol_feature_fix_contract_loading_cost = [ "near-primitives-core/protocol_feature_fix_contract_loading_cost", ] +protocol_feature_nonrefundable_transfer_nep491 = [ + "near-primitives-core/protocol_feature_nonrefundable_transfer_nep491", +] + nightly = [ "near-parameters/nightly", "near-primitives-core/nightly", "nightly_protocol", "protocol_feature_fix_contract_loading_cost", + "protocol_feature_nonrefundable_transfer_nep491", ] sandbox = [] io_trace = [] diff --git a/runtime/near-vm-runner/src/logic/logic.rs b/runtime/near-vm-runner/src/logic/logic.rs index 08c311a4407..b143adc078d 100644 --- a/runtime/near-vm-runner/src/logic/logic.rs +++ b/runtime/near-vm-runner/src/logic/logic.rs @@ -1783,6 +1783,7 @@ impl<'a> VMLogic<'a> { self.config.implicit_account_creation, self.config.eth_implicit_accounts, receiver_id.get_account_type(), + #[cfg(feature = "protocol_feature_nonrefundable_transfer_nep491")] false, ); let exec_fee = transfer_exec_fee( @@ -1790,6 +1791,7 @@ impl<'a> VMLogic<'a> { self.config.implicit_account_creation, self.config.eth_implicit_accounts, receiver_id.get_account_type(), + #[cfg(feature = "protocol_feature_nonrefundable_transfer_nep491")] false, ); let burn_gas = send_fee; diff --git a/runtime/runtime-params-estimator/Cargo.toml b/runtime/runtime-params-estimator/Cargo.toml index 94a3e021d6c..8fea9176262 100644 --- a/runtime/runtime-params-estimator/Cargo.toml +++ b/runtime/runtime-params-estimator/Cargo.toml @@ -68,6 +68,9 @@ no_cache = [ "node-runtime/no_cache", "near-store/no_cache", ] +protocol_feature_nonrefundable_transfer_nep491 = [ + "near-parameters/protocol_feature_nonrefundable_transfer_nep491", +] nightly = [ "genesis-populate/nightly", "near-chain-configs/nightly", @@ -80,6 +83,7 @@ nightly = [ "nearcore/nightly", "nightly_protocol", "node-runtime/nightly", + "protocol_feature_nonrefundable_transfer_nep491", ] nightly_protocol = [ "genesis-populate/nightly_protocol", diff --git a/runtime/runtime-params-estimator/src/cost.rs b/runtime/runtime-params-estimator/src/cost.rs index a27b5efdce1..7735de6ccbe 100644 --- a/runtime/runtime-params-estimator/src/cost.rs +++ b/runtime/runtime-params-estimator/src/cost.rs @@ -725,6 +725,14 @@ pub enum Cost { /// `promise_yield_resume` host function. YieldResumeByte, + /// Estimates `action_creation_config.transfer_cost` which is charged for + /// every `Action::Transfer`, the same value for sending and executing. + /// + /// Estimation: Measure a transaction with only a transfer and subtract the + /// base cost of creating a receipt. + #[cfg(feature = "protocol_feature_nonrefundable_transfer_nep491")] + ActionNonrefundableStorageTransfer, + __Count, } diff --git a/runtime/runtime-params-estimator/src/costs_to_runtime_config.rs b/runtime/runtime-params-estimator/src/costs_to_runtime_config.rs index 619ae49e4d4..e2ab4623024 100644 --- a/runtime/runtime-params-estimator/src/costs_to_runtime_config.rs +++ b/runtime/runtime-params-estimator/src/costs_to_runtime_config.rs @@ -63,7 +63,8 @@ fn runtime_fees_config(cost_table: &CostTable) -> anyhow::Result fee(Cost::ActionFunctionCallBase)?, ActionCosts::function_call_byte => fee(Cost::ActionFunctionCallPerByte)?, ActionCosts::transfer => fee(Cost::ActionTransfer)?, - ActionCosts::nonrefundable_transfer => fee(Cost::ActionTransfer)?, // TODO + #[cfg(feature = "protocol_feature_nonrefundable_transfer_nep491")] + ActionCosts::nonrefundable_transfer => fee(Cost::ActionNonrefundableStorageTransfer)?, ActionCosts::stake => fee(Cost::ActionStake)?, ActionCosts::add_full_access_key => fee(Cost::ActionAddFullAccessKey)?, ActionCosts::add_function_call_key_base => fee(Cost::ActionAddFunctionAccessKeyBase)?, diff --git a/runtime/runtime-params-estimator/src/lib.rs b/runtime/runtime-params-estimator/src/lib.rs index 22f7268c22a..35ccb9a87f2 100644 --- a/runtime/runtime-params-estimator/src/lib.rs +++ b/runtime/runtime-params-estimator/src/lib.rs @@ -101,6 +101,8 @@ use gas_metering::gas_metering_cost; use near_crypto::{KeyType, SecretKey}; use near_parameters::{ExtCosts, RuntimeConfigStore, RuntimeFeesConfig}; use near_primitives::account::{AccessKey, AccessKeyPermission, FunctionCallPermission}; +#[cfg(feature = "protocol_feature_nonrefundable_transfer_nep491")] +use near_primitives::action::NonrefundableStorageTransferAction; use near_primitives::transaction::{ Action, AddKeyAction, CreateAccountAction, DeleteAccountAction, DeleteKeyAction, DeployContractAction, SignedTransaction, StakeAction, TransferAction, @@ -132,6 +134,8 @@ static ALL_COSTS: &[(Cost, fn(&mut EstimatorContext) -> GasCost)] = &[ (Cost::ActionTransferSendSir, action_costs::transfer_send_sir), (Cost::ActionTransferSendNotSir, action_costs::transfer_send_not_sir), (Cost::ActionTransferExec, action_costs::transfer_exec), + #[cfg(feature = "protocol_feature_nonrefundable_transfer_nep491")] + (Cost::ActionNonrefundableStorageTransfer, action_nonrefundable_storage_transfer), (Cost::ActionCreateAccount, action_create_account), (Cost::ActionCreateAccountSendSir, action_costs::create_account_send_sir), (Cost::ActionCreateAccountSendNotSir, action_costs::create_account_send_not_sir), @@ -377,6 +381,29 @@ fn action_transfer(ctx: &mut EstimatorContext) -> GasCost { total_cost.saturating_sub(&base_cost, &NonNegativeTolerance::PER_MILLE) } +#[cfg(feature = "protocol_feature_nonrefundable_transfer_nep491")] +fn action_nonrefundable_storage_transfer(ctx: &mut EstimatorContext) -> GasCost { + let total_cost = { + let mut make_transaction = |tb: &mut TransactionBuilder| -> SignedTransaction { + let (sender, receiver) = tb.random_account_pair(); + + let actions = + vec![Action::NonrefundableStorageTransfer(NonrefundableStorageTransferAction { + deposit: 1, + })]; + tb.transaction_from_actions(sender, receiver, actions) + }; + let block_size = 100; + // Transferring from one account to another may touch two shards, thus executes over two blocks. + let block_latency = 1; + transaction_cost_ext(ctx, block_size, &mut make_transaction, block_latency).0 + }; + + let base_cost = action_receipt_creation(ctx); + + total_cost.saturating_sub(&base_cost, &NonNegativeTolerance::PER_MILLE) +} + fn action_create_account(ctx: &mut EstimatorContext) -> GasCost { let total_cost = { let mut make_transaction = |tb: &mut TransactionBuilder| -> SignedTransaction { diff --git a/runtime/runtime/src/config.rs b/runtime/runtime/src/config.rs index d5ae656c007..68b98fe15ea 100644 --- a/runtime/runtime/src/config.rs +++ b/runtime/runtime/src/config.rs @@ -102,6 +102,7 @@ pub fn total_send_fees( config.wasm_config.implicit_account_creation, config.wasm_config.eth_implicit_accounts, receiver_id.get_account_type(), + #[cfg(feature = "protocol_feature_nonrefundable_transfer_nep491")] false, ) } @@ -116,6 +117,7 @@ pub fn total_send_fees( config.wasm_config.implicit_account_creation, config.wasm_config.eth_implicit_accounts, receiver_id.get_account_type(), + #[cfg(feature = "protocol_feature_nonrefundable_transfer_nep491")] true, ) } @@ -212,6 +214,7 @@ pub fn exec_fee(config: &RuntimeConfig, action: &Action, receiver_id: &AccountId config.wasm_config.implicit_account_creation, config.wasm_config.eth_implicit_accounts, receiver_id.get_account_type(), + #[cfg(feature = "protocol_feature_nonrefundable_transfer_nep491")] false, ) } @@ -223,6 +226,7 @@ pub fn exec_fee(config: &RuntimeConfig, action: &Action, receiver_id: &AccountId config.wasm_config.implicit_account_creation, config.wasm_config.eth_implicit_accounts, receiver_id.get_account_type(), + #[cfg(feature = "protocol_feature_nonrefundable_transfer_nep491")] true, ) }