diff --git a/api/types/src/transaction.rs b/api/types/src/transaction.rs index 108e62a67bf62b..a94bf7bffb9d7c 100755 --- a/api/types/src/transaction.rs +++ b/api/types/src/transaction.rs @@ -1633,6 +1633,7 @@ pub enum AccountSignature { MultiEd25519Signature(MultiEd25519Signature), SingleKeySignature(SingleKeySignature), MultiKeySignature(MultiKeySignature), + NoAccountSignature, } impl VerifyInput for AccountSignature { @@ -1642,6 +1643,7 @@ impl VerifyInput for AccountSignature { AccountSignature::MultiEd25519Signature(inner) => inner.verify(), AccountSignature::SingleKeySignature(inner) => inner.verify(), AccountSignature::MultiKeySignature(inner) => inner.verify(), + AccountSignature::NoAccountSignature => Ok(()), } } } @@ -1815,6 +1817,7 @@ impl From<&AccountAuthenticator> for AccountSignature { signatures_required: public_keys.signatures_required(), }) }, + NoAccountAuthenticator => unreachable!(), // TODO: error or something else? } } } diff --git a/aptos-move/aptos-release-builder/src/components/feature_flags.rs b/aptos-move/aptos-release-builder/src/components/feature_flags.rs index f19e53681363f1..477b09bedc68a0 100644 --- a/aptos-move/aptos-release-builder/src/components/feature_flags.rs +++ b/aptos-move/aptos-release-builder/src/components/feature_flags.rs @@ -121,6 +121,7 @@ pub enum FeatureFlag { DefaultToConcurrentFungibleBalance, LimitVMTypeSize, AbortIfMultisigPayloadMismatch, + SimulationEnhancement, } fn generate_features_blob(writer: &CodeWriter, data: &[u64]) { @@ -316,6 +317,7 @@ impl From for AptosFeatureFlag { FeatureFlag::AbortIfMultisigPayloadMismatch => { AptosFeatureFlag::ABORT_IF_MULTISIG_PAYLOAD_MISMATCH }, + FeatureFlag::SimulationEnhancement => AptosFeatureFlag::SIMULATION_ENHANCEMENT, } } } @@ -440,6 +442,7 @@ impl From for FeatureFlag { AptosFeatureFlag::ABORT_IF_MULTISIG_PAYLOAD_MISMATCH => { FeatureFlag::AbortIfMultisigPayloadMismatch }, + AptosFeatureFlag::SIMULATION_ENHANCEMENT => FeatureFlag::SimulationEnhancement, } } } diff --git a/aptos-move/aptos-vm/src/aptos_vm.rs b/aptos-move/aptos-vm/src/aptos_vm.rs index ee2b68e4286ddd..9ea8bcf4a9478d 100644 --- a/aptos-move/aptos-vm/src/aptos_vm.rs +++ b/aptos-move/aptos-vm/src/aptos_vm.rs @@ -683,6 +683,7 @@ impl AptosVM { txn_data, log_context, traversal_context, + self.is_simulation, ) })?; epilogue_session @@ -710,6 +711,7 @@ impl AptosVM { txn_data, log_context, traversal_context, + self.is_simulation, ) })?; epilogue_session @@ -756,6 +758,7 @@ impl AptosVM { txn_data, log_context, traversal_context, + self.is_simulation, ) })?; let change_set = epilogue_session.finish(change_set_configs)?; @@ -2342,6 +2345,7 @@ impl AptosVM { txn_data, log_context, traversal_context, + self.is_simulation, ) }, TransactionPayload::Multisig(multisig_payload) => { @@ -2353,6 +2357,7 @@ impl AptosVM { txn_data, log_context, traversal_context, + self.is_simulation, )?; // Skip validation if this is part of tx simulation. // This allows simulating multisig txs without having to first create the multisig diff --git a/aptos-move/aptos-vm/src/transaction_metadata.rs b/aptos-move/aptos-vm/src/transaction_metadata.rs index 41a3501b46b569..2c895b53c7355d 100644 --- a/aptos-move/aptos-vm/src/transaction_metadata.rs +++ b/aptos-move/aptos-vm/src/transaction_metadata.rs @@ -38,20 +38,29 @@ impl TransactionMetadata { pub fn new(txn: &SignedTransaction) -> Self { Self { sender: txn.sender(), - authentication_key: txn.authenticator().sender().authentication_key().to_vec(), + authentication_key: txn + .authenticator() + .sender() + .authentication_key() + .map_or_else(|| vec![], |auth_key| auth_key.to_vec()), secondary_signers: txn.authenticator().secondary_signer_addresses(), secondary_authentication_keys: txn .authenticator() .secondary_signers() .iter() - .map(|account_auth| account_auth.authentication_key().to_vec()) + .map(|account_auth| { + account_auth + .authentication_key() + .map_or_else(|| vec![], |auth_key| auth_key.to_vec()) + }) .collect(), sequence_number: txn.sequence_number(), fee_payer: txn.authenticator_ref().fee_payer_address(), - fee_payer_authentication_key: txn - .authenticator() - .fee_payer_signer() - .map(|signer| signer.authentication_key().to_vec()), + fee_payer_authentication_key: txn.authenticator().fee_payer_signer().map(|signer| { + signer + .authentication_key() + .map_or_else(|| vec![], |auth_key| auth_key.to_vec()) + }), max_gas_amount: txn.max_gas_amount().into(), gas_unit_price: txn.gas_unit_price().into(), transaction_size: (txn.raw_txn_bytes_len() as u64).into(), diff --git a/aptos-move/aptos-vm/src/transaction_validation.rs b/aptos-move/aptos-vm/src/transaction_validation.rs index 9448713eb34b9e..31af534d7f2e7c 100644 --- a/aptos-move/aptos-vm/src/transaction_validation.rs +++ b/aptos-move/aptos-vm/src/transaction_validation.rs @@ -89,6 +89,7 @@ pub(crate) fn run_script_prologue( txn_data: &TransactionMetadata, log_context: &AdapterLogSchema, traversal_context: &mut TraversalContext, + is_simulation: bool, ) -> Result<(), VMStatus> { let txn_sequence_number = txn_data.sequence_number(); let txn_authentication_key = txn_data.authentication_key().to_vec(); @@ -118,6 +119,7 @@ pub(crate) fn run_script_prologue( MoveValue::U64(txn_max_gas_units.into()), MoveValue::U64(txn_expiration_timestamp_secs), MoveValue::U8(chain_id.id()), + MoveValue::Bool(is_simulation), ]; if txn_data.required_deposit.is_some() { args.push(txn_data.required_deposit.as_move_value()); @@ -139,6 +141,7 @@ pub(crate) fn run_script_prologue( MoveValue::U64(txn_max_gas_units.into()), MoveValue::U64(txn_expiration_timestamp_secs), MoveValue::U8(chain_id.id()), + MoveValue::Bool(is_simulation), ]; ( &APTOS_TRANSACTION_VALIDATION.multi_agent_prologue_name, @@ -154,6 +157,7 @@ pub(crate) fn run_script_prologue( MoveValue::U64(txn_expiration_timestamp_secs), MoveValue::U8(chain_id.id()), MoveValue::vector_u8(txn_data.script_hash.clone()), + MoveValue::Bool(is_simulation), ]; if txn_data.required_deposit.is_some() { args.push(txn_data.required_deposit.as_move_value()); @@ -229,6 +233,7 @@ fn run_epilogue( txn_data: &TransactionMetadata, features: &Features, traversal_context: &mut TraversalContext, + is_simulation: bool, ) -> VMResult<()> { let txn_gas_price = txn_data.gas_unit_price(); let txn_max_gas_units = txn_data.max_gas_amount(); @@ -244,6 +249,7 @@ fn run_epilogue( MoveValue::U64(txn_gas_price.into()), MoveValue::U64(txn_max_gas_units.into()), MoveValue::U64(gas_remaining.into()), + MoveValue::Bool(is_simulation), ]; if txn_data.required_deposit.is_some() { args.push(txn_data.required_deposit.as_move_value()); @@ -275,6 +281,7 @@ fn run_epilogue( MoveValue::U64(txn_gas_price.into()), MoveValue::U64(txn_max_gas_units.into()), MoveValue::U64(gas_remaining.into()), + MoveValue::Bool(is_simulation), ]; if txn_data.required_deposit.is_some() { args.push(txn_data.required_deposit.as_move_value()); @@ -335,6 +342,7 @@ pub(crate) fn run_success_epilogue( txn_data: &TransactionMetadata, log_context: &AdapterLogSchema, traversal_context: &mut TraversalContext, + is_simulation: bool, ) -> Result<(), VMStatus> { fail_point!("move_adapter::run_success_epilogue", |_| { Err(VMStatus::error( @@ -350,6 +358,7 @@ pub(crate) fn run_success_epilogue( txn_data, features, traversal_context, + is_simulation, ) .or_else(|err| convert_epilogue_error(err, log_context)) } @@ -364,6 +373,7 @@ pub(crate) fn run_failure_epilogue( txn_data: &TransactionMetadata, log_context: &AdapterLogSchema, traversal_context: &mut TraversalContext, + is_simulation: bool, ) -> Result<(), VMStatus> { run_epilogue( session, @@ -372,6 +382,7 @@ pub(crate) fn run_failure_epilogue( txn_data, features, traversal_context, + is_simulation, ) .or_else(|e| { expect_only_successful_execution( diff --git a/aptos-move/framework/aptos-framework/doc/transaction_validation.md b/aptos-move/framework/aptos-framework/doc/transaction_validation.md index 6870a420b97340..e651b561ab271a 100644 --- a/aptos-move/framework/aptos-framework/doc/transaction_validation.md +++ b/aptos-move/framework/aptos-framework/doc/transaction_validation.md @@ -21,6 +21,7 @@ - [Function `epilogue_return_deposit`](#0x1_transaction_validation_epilogue_return_deposit) - [Function `epilogue_gas_payer`](#0x1_transaction_validation_epilogue_gas_payer) - [Function `epilogue_gas_payer_return_deposit`](#0x1_transaction_validation_epilogue_gas_payer_return_deposit) +- [Function `is_auth_key_empty`](#0x1_transaction_validation_is_auth_key_empty) - [Specification](#@Specification_1) - [High-level Requirements](#high-level-req) - [Module-level Specification](#module-level-spec) @@ -53,6 +54,7 @@ use 0x1::system_addresses; use 0x1::timestamp; use 0x1::transaction_fee; +use 0x1::vector; @@ -350,7 +352,7 @@ Called in epilogue to optionally released the amount held in prologue for specia -
fun prologue_common(sender: signer, gas_payer: address, txn_sequence_number: u64, txn_authentication_key: vector<u8>, txn_gas_price: u64, txn_max_gas_units: u64, txn_expiration_time: u64, chain_id: u8)
+
fun prologue_common(sender: signer, gas_payer: address, txn_sequence_number: u64, txn_authentication_key: vector<u8>, txn_gas_price: u64, txn_max_gas_units: u64, txn_expiration_time: u64, chain_id: u8, is_simulation: bool)
 
@@ -368,6 +370,7 @@ Called in epilogue to optionally released the amount held in prologue for specia txn_max_gas_units: u64, txn_expiration_time: u64, chain_id: u8, + is_simulation: bool, ) { assert!( timestamp::now_seconds() < txn_expiration_time, @@ -384,10 +387,12 @@ Called in epilogue to optionally released the amount held in prologue for specia || txn_sequence_number > 0 ) { assert!(account::exists_at(transaction_sender), error::invalid_argument(PROLOGUE_EACCOUNT_DOES_NOT_EXIST)); - assert!( - txn_authentication_key == account::get_authentication_key(transaction_sender), - error::invalid_argument(PROLOGUE_EINVALID_ACCOUNT_AUTH_KEY), - ); + if (!features::simulation_enhancement_enabled() || !is_simulation || !is_auth_key_empty(&txn_authentication_key)) { + assert!( + txn_authentication_key == account::get_authentication_key(transaction_sender), + error::invalid_argument(PROLOGUE_EINVALID_ACCOUNT_AUTH_KEY), + ) + }; let account_sequence_number = account::get_sequence_number(transaction_sender); assert!( @@ -420,16 +425,18 @@ Called in epilogue to optionally released the amount held in prologue for specia let max_transaction_fee = txn_gas_price * txn_max_gas_units; - if (features::operations_default_to_fa_apt_store_enabled()) { - assert!( - aptos_account::is_fungible_balance_at_least(gas_payer, max_transaction_fee), - error::invalid_argument(PROLOGUE_ECANT_PAY_GAS_DEPOSIT) - ); - } else { - assert!( - coin::is_balance_at_least<AptosCoin>(gas_payer, max_transaction_fee), - error::invalid_argument(PROLOGUE_ECANT_PAY_GAS_DEPOSIT) - ); + if (!features::simulation_enhancement_enabled() || !is_simulation || gas_payer != @0x0) { + if (features::operations_default_to_fa_apt_store_enabled()) { + assert!( + aptos_account::is_fungible_balance_at_least(gas_payer, max_transaction_fee), + error::invalid_argument(PROLOGUE_ECANT_PAY_GAS_DEPOSIT) + ); + } else { + assert!( + coin::is_balance_at_least<AptosCoin>(gas_payer, max_transaction_fee), + error::invalid_argument(PROLOGUE_ECANT_PAY_GAS_DEPOSIT) + ); + } } }
@@ -444,7 +451,7 @@ Called in epilogue to optionally released the amount held in prologue for specia -
fun script_prologue(sender: signer, txn_sequence_number: u64, txn_public_key: vector<u8>, txn_gas_price: u64, txn_max_gas_units: u64, txn_expiration_time: u64, chain_id: u8, _script_hash: vector<u8>)
+
fun script_prologue(sender: signer, txn_sequence_number: u64, txn_public_key: vector<u8>, txn_gas_price: u64, txn_max_gas_units: u64, txn_expiration_time: u64, chain_id: u8, _script_hash: vector<u8>, is_simulation: bool)
 
@@ -462,9 +469,10 @@ Called in epilogue to optionally released the amount held in prologue for specia txn_expiration_time: u64, chain_id: u8, _script_hash: vector<u8>, + is_simulation: bool, ) { let gas_payer = signer::address_of(&sender); - prologue_common(sender, gas_payer, txn_sequence_number, txn_public_key, txn_gas_price, txn_max_gas_units, txn_expiration_time, chain_id) + prologue_common(sender, gas_payer, txn_sequence_number, txn_public_key, txn_gas_price, txn_max_gas_units, txn_expiration_time, chain_id, is_simulation) }
@@ -481,7 +489,7 @@ Called in epilogue to optionally released the amount held in prologue for specia Deposit collection goes last so script_prologue() doesn't have to be aware of the deposit logic. -
fun script_prologue_collect_deposit(sender: signer, txn_sequence_number: u64, txn_public_key: vector<u8>, txn_gas_price: u64, txn_max_gas_units: u64, txn_expiration_time: u64, chain_id: u8, script_hash: vector<u8>, required_deposit: option::Option<u64>)
+
fun script_prologue_collect_deposit(sender: signer, txn_sequence_number: u64, txn_public_key: vector<u8>, txn_gas_price: u64, txn_max_gas_units: u64, txn_expiration_time: u64, chain_id: u8, script_hash: vector<u8>, required_deposit: option::Option<u64>, is_simulation: bool)
 
@@ -500,9 +508,10 @@ Deposit collection goes last so chain_id: u8, script_hash: vector<u8>, required_deposit: Option<u64>, + is_simulation: bool, ) { let gas_payer = signer::address_of(&sender); - script_prologue(sender, txn_sequence_number, txn_public_key, txn_gas_price, txn_max_gas_units, txn_expiration_time, chain_id, script_hash); + script_prologue(sender, txn_sequence_number, txn_public_key, txn_gas_price, txn_max_gas_units, txn_expiration_time, chain_id, script_hash, is_simulation); collect_deposit(gas_payer, required_deposit); }
@@ -517,7 +526,7 @@ Deposit collection goes last so multi_agent_script_prologue(sender: signer, txn_sequence_number: u64, txn_sender_public_key: vector<u8>, secondary_signer_addresses: vector<address>, secondary_signer_public_key_hashes: vector<vector<u8>>, txn_gas_price: u64, txn_max_gas_units: u64, txn_expiration_time: u64, chain_id: u8) +
fun multi_agent_script_prologue(sender: signer, txn_sequence_number: u64, txn_sender_public_key: vector<u8>, secondary_signer_addresses: vector<address>, secondary_signer_public_key_hashes: vector<vector<u8>>, txn_gas_price: u64, txn_max_gas_units: u64, txn_expiration_time: u64, chain_id: u8, is_simulation: bool)
 
@@ -536,6 +545,7 @@ Deposit collection goes last so chain_id: u8, + is_simulation: bool, ) { let sender_addr = signer::address_of(&sender); prologue_common( @@ -547,8 +557,9 @@ Deposit collection goes last so chain_id, + is_simulation, ); - multi_agent_common_prologue(secondary_signer_addresses, secondary_signer_public_key_hashes); + multi_agent_common_prologue(secondary_signer_addresses, secondary_signer_public_key_hashes, is_simulation); } @@ -562,7 +573,7 @@ Deposit collection goes last so multi_agent_common_prologue(secondary_signer_addresses: vector<address>, secondary_signer_public_key_hashes: vector<vector<u8>>) +
fun multi_agent_common_prologue(secondary_signer_addresses: vector<address>, secondary_signer_public_key_hashes: vector<vector<u8>>, is_simulation: bool)
 
@@ -574,6 +585,7 @@ Deposit collection goes last so multi_agent_common_prologue( secondary_signer_addresses: vector<address>, secondary_signer_public_key_hashes: vector<vector<u8>>, + is_simulation: bool, ) { let num_secondary_signers = vector::length(&secondary_signer_addresses); assert!( @@ -596,10 +608,12 @@ Deposit collection goes last so account::exists_at(secondary_address), error::invalid_argument(PROLOGUE_EACCOUNT_DOES_NOT_EXIST)); let signer_public_key_hash = *vector::borrow(&secondary_signer_public_key_hashes, i); - assert!( - signer_public_key_hash == account::get_authentication_key(secondary_address), - error::invalid_argument(PROLOGUE_EINVALID_ACCOUNT_AUTH_KEY), - ); + if (!features::simulation_enhancement_enabled() || !is_simulation || !is_auth_key_empty(&signer_public_key_hash)) { + assert!( + signer_public_key_hash == account::get_authentication_key(secondary_address), + error::invalid_argument(PROLOGUE_EINVALID_ACCOUNT_AUTH_KEY), + ) + }; i = i + 1; } } @@ -615,7 +629,7 @@ Deposit collection goes last so fee_payer_script_prologue(sender: signer, txn_sequence_number: u64, txn_sender_public_key: vector<u8>, secondary_signer_addresses: vector<address>, secondary_signer_public_key_hashes: vector<vector<u8>>, fee_payer_address: address, fee_payer_public_key_hash: vector<u8>, txn_gas_price: u64, txn_max_gas_units: u64, txn_expiration_time: u64, chain_id: u8) +
fun fee_payer_script_prologue(sender: signer, txn_sequence_number: u64, txn_sender_public_key: vector<u8>, secondary_signer_addresses: vector<address>, secondary_signer_public_key_hashes: vector<vector<u8>>, fee_payer_address: address, fee_payer_public_key_hash: vector<u8>, txn_gas_price: u64, txn_max_gas_units: u64, txn_expiration_time: u64, chain_id: u8, is_simulation: bool)
 
@@ -636,6 +650,7 @@ Deposit collection goes last so chain_id: u8, + is_simulation: bool, ) { assert!(features::fee_payer_enabled(), error::invalid_state(PROLOGUE_EFEE_PAYER_NOT_ENABLED)); prologue_common( @@ -647,12 +662,15 @@ Deposit collection goes last so chain_id, + is_simulation, ); - multi_agent_common_prologue(secondary_signer_addresses, secondary_signer_public_key_hashes); - assert!( - fee_payer_public_key_hash == account::get_authentication_key(fee_payer_address), - error::invalid_argument(PROLOGUE_EINVALID_ACCOUNT_AUTH_KEY), - ); + multi_agent_common_prologue(secondary_signer_addresses, secondary_signer_public_key_hashes, is_simulation); + if (!features::simulation_enhancement_enabled() || !is_simulation || is_auth_key_empty(&fee_payer_public_key_hash)) { + assert!( + fee_payer_public_key_hash == account::get_authentication_key(fee_payer_address), + error::invalid_argument(PROLOGUE_EINVALID_ACCOUNT_AUTH_KEY), + ) + } } @@ -669,7 +687,7 @@ Deposit collection goes last so fee_payer_script_prologue() doesn't have to be aware of the deposit logic. -
fun fee_payer_script_prologue_collect_deposit(sender: signer, txn_sequence_number: u64, txn_sender_public_key: vector<u8>, secondary_signer_addresses: vector<address>, secondary_signer_public_key_hashes: vector<vector<u8>>, fee_payer_address: address, fee_payer_public_key_hash: vector<u8>, txn_gas_price: u64, txn_max_gas_units: u64, txn_expiration_time: u64, chain_id: u8, required_deposit: option::Option<u64>)
+
fun fee_payer_script_prologue_collect_deposit(sender: signer, txn_sequence_number: u64, txn_sender_public_key: vector<u8>, secondary_signer_addresses: vector<address>, secondary_signer_public_key_hashes: vector<vector<u8>>, fee_payer_address: address, fee_payer_public_key_hash: vector<u8>, txn_gas_price: u64, txn_max_gas_units: u64, txn_expiration_time: u64, chain_id: u8, required_deposit: option::Option<u64>, is_simulation: bool)
 
@@ -691,6 +709,7 @@ Deposit collection goes last so chain_id: u8, required_deposit: Option<u64>, + is_simulation: bool, ) { fee_payer_script_prologue( sender, @@ -704,8 +723,11 @@ Deposit collection goes last so chain_id, + is_simulation, ); - collect_deposit(fee_payer_address, required_deposit); + if (!features::simulation_enhancement_enabled() || !is_simulation || fee_payer_address != @0x0) { + collect_deposit(fee_payer_address, required_deposit); + } }
@@ -721,7 +743,7 @@ Epilogue function is run after a transaction is successfully executed. Called by the Adapter -
fun epilogue(account: signer, storage_fee_refunded: u64, txn_gas_price: u64, txn_max_gas_units: u64, gas_units_remaining: u64)
+
fun epilogue(account: signer, storage_fee_refunded: u64, txn_gas_price: u64, txn_max_gas_units: u64, gas_units_remaining: u64, is_simulation: bool)
 
@@ -735,10 +757,11 @@ Called by the Adapter storage_fee_refunded: u64, txn_gas_price: u64, txn_max_gas_units: u64, - gas_units_remaining: u64 + gas_units_remaining: u64, + is_simulation: bool, ) { let addr = signer::address_of(&account); - epilogue_gas_payer(account, addr, storage_fee_refunded, txn_gas_price, txn_max_gas_units, gas_units_remaining); + epilogue_gas_payer(account, addr, storage_fee_refunded, txn_gas_price, txn_max_gas_units, gas_units_remaining, is_simulation); }
@@ -755,7 +778,7 @@ Return the deposit held in prologue, then epilogue() doesn't have to be aware of this change. -
fun epilogue_return_deposit(account: signer, storage_fee_refunded: u64, txn_gas_price: u64, txn_max_gas_units: u64, gas_units_remaining: u64, required_deposit: option::Option<u64>)
+
fun epilogue_return_deposit(account: signer, storage_fee_refunded: u64, txn_gas_price: u64, txn_max_gas_units: u64, gas_units_remaining: u64, required_deposit: option::Option<u64>, is_simulation: bool)
 
@@ -771,15 +794,19 @@ Deposit return goes first so signer::address_of(&account); - return_deposit(gas_payer, required_deposit); + if (!features::simulation_enhancement_enabled() || !is_simulation || gas_payer != @0x0) { + return_deposit(gas_payer, required_deposit) + }; epilogue( account, storage_fee_refunded, txn_gas_price, txn_max_gas_units, gas_units_remaining, + is_simulation, ); }
@@ -796,7 +823,7 @@ Epilogue function with explicit gas payer specified, is run after a transaction Called by the Adapter -
fun epilogue_gas_payer(account: signer, gas_payer: address, storage_fee_refunded: u64, txn_gas_price: u64, txn_max_gas_units: u64, gas_units_remaining: u64)
+
fun epilogue_gas_payer(account: signer, gas_payer: address, storage_fee_refunded: u64, txn_gas_price: u64, txn_max_gas_units: u64, gas_units_remaining: u64, is_simulation: bool)
 
@@ -811,7 +838,8 @@ Called by the Adapter storage_fee_refunded: u64, txn_gas_price: u64, txn_max_gas_units: u64, - gas_units_remaining: u64 + gas_units_remaining: u64, + is_simulation: bool, ) { assert!(txn_max_gas_units >= gas_units_remaining, error::invalid_argument(EOUT_OF_GAS)); let gas_used = txn_max_gas_units - gas_units_remaining; @@ -824,39 +852,41 @@ Called by the Adapter // it's important to maintain the error code consistent with vm // to do failed transaction cleanup. - if (features::operations_default_to_fa_apt_store_enabled()) { - assert!( - aptos_account::is_fungible_balance_at_least(gas_payer, transaction_fee_amount), - error::out_of_range(PROLOGUE_ECANT_PAY_GAS_DEPOSIT), - ); - } else { - assert!( - coin::is_balance_at_least<AptosCoin>(gas_payer, transaction_fee_amount), - error::out_of_range(PROLOGUE_ECANT_PAY_GAS_DEPOSIT), - ); - }; - - let amount_to_burn = if (features::collect_and_distribute_gas_fees()) { - // TODO(gas): We might want to distinguish the refundable part of the charge and burn it or track - // it separately, so that we don't increase the total supply by refunding. + if (!features::simulation_enhancement_enabled() || !is_simulation || gas_payer != @0x0) { + if (features::operations_default_to_fa_apt_store_enabled()) { + assert!( + aptos_account::is_fungible_balance_at_least(gas_payer, transaction_fee_amount), + error::out_of_range(PROLOGUE_ECANT_PAY_GAS_DEPOSIT), + ); + } else { + assert!( + coin::is_balance_at_least<AptosCoin>(gas_payer, transaction_fee_amount), + error::out_of_range(PROLOGUE_ECANT_PAY_GAS_DEPOSIT), + ); + }; - // If transaction fees are redistributed to validators, collect them here for - // later redistribution. - transaction_fee::collect_fee(gas_payer, transaction_fee_amount); - 0 - } else { - // Otherwise, just burn the fee. - // TODO: this branch should be removed completely when transaction fee collection - // is tested and is fully proven to work well. - transaction_fee_amount - }; + let amount_to_burn = if (features::collect_and_distribute_gas_fees()) { + // TODO(gas): We might want to distinguish the refundable part of the charge and burn it or track + // it separately, so that we don't increase the total supply by refunding. + + // If transaction fees are redistributed to validators, collect them here for + // later redistribution. + transaction_fee::collect_fee(gas_payer, transaction_fee_amount); + 0 + } else { + // Otherwise, just burn the fee. + // TODO: this branch should be removed completely when transaction fee collection + // is tested and is fully proven to work well. + transaction_fee_amount + }; - if (amount_to_burn > storage_fee_refunded) { - let burn_amount = amount_to_burn - storage_fee_refunded; - transaction_fee::burn_fee(gas_payer, burn_amount); - } else if (amount_to_burn < storage_fee_refunded) { - let mint_amount = storage_fee_refunded - amount_to_burn; - transaction_fee::mint_and_refund(gas_payer, mint_amount) + if (amount_to_burn > storage_fee_refunded) { + let burn_amount = amount_to_burn - storage_fee_refunded; + transaction_fee::burn_fee(gas_payer, burn_amount); + } else if (amount_to_burn < storage_fee_refunded) { + let mint_amount = storage_fee_refunded - amount_to_burn; + transaction_fee::mint_and_refund(gas_payer, mint_amount) + }; }; // Increment sequence number @@ -878,7 +908,7 @@ Return the deposit held in prologue to the gas payer, then epilogue_gas_payer() doesn't have to be aware of this change. -
fun epilogue_gas_payer_return_deposit(account: signer, gas_payer: address, storage_fee_refunded: u64, txn_gas_price: u64, txn_max_gas_units: u64, gas_units_remaining: u64, required_deposit: option::Option<u64>)
+
fun epilogue_gas_payer_return_deposit(account: signer, gas_payer: address, storage_fee_refunded: u64, txn_gas_price: u64, txn_max_gas_units: u64, gas_units_remaining: u64, required_deposit: option::Option<u64>, is_simulation: bool)
 
@@ -895,6 +925,7 @@ Deposit return should go first so return_deposit(gas_payer, required_deposit); epilogue_gas_payer( @@ -904,12 +935,37 @@ Deposit return should go first so + +## Function `is_auth_key_empty` + + + +
fun is_auth_key_empty(auth_key: &vector<u8>): bool
+
+ + + +
+Implementation + + +
inline fun is_auth_key_empty(auth_key: &vector<u8>): bool {
+    vector::is_empty(auth_key)
+}
+
+ + +
@@ -1073,7 +1129,7 @@ Give some constraints that may abort according to the conditions. ### Function `prologue_common` -
fun prologue_common(sender: signer, gas_payer: address, txn_sequence_number: u64, txn_authentication_key: vector<u8>, txn_gas_price: u64, txn_max_gas_units: u64, txn_expiration_time: u64, chain_id: u8)
+
fun prologue_common(sender: signer, gas_payer: address, txn_sequence_number: u64, txn_authentication_key: vector<u8>, txn_gas_price: u64, txn_max_gas_units: u64, txn_expiration_time: u64, chain_id: u8, is_simulation: bool)
 
@@ -1090,7 +1146,7 @@ Give some constraints that may abort according to the conditions. ### Function `script_prologue` -
fun script_prologue(sender: signer, txn_sequence_number: u64, txn_public_key: vector<u8>, txn_gas_price: u64, txn_max_gas_units: u64, txn_expiration_time: u64, chain_id: u8, _script_hash: vector<u8>)
+
fun script_prologue(sender: signer, txn_sequence_number: u64, txn_public_key: vector<u8>, txn_gas_price: u64, txn_max_gas_units: u64, txn_expiration_time: u64, chain_id: u8, _script_hash: vector<u8>, is_simulation: bool)
 
@@ -1133,7 +1189,7 @@ Give some constraints that may abort according to the conditions. ### Function `script_prologue_collect_deposit` -
fun script_prologue_collect_deposit(sender: signer, txn_sequence_number: u64, txn_public_key: vector<u8>, txn_gas_price: u64, txn_max_gas_units: u64, txn_expiration_time: u64, chain_id: u8, script_hash: vector<u8>, required_deposit: option::Option<u64>)
+
fun script_prologue_collect_deposit(sender: signer, txn_sequence_number: u64, txn_public_key: vector<u8>, txn_gas_price: u64, txn_max_gas_units: u64, txn_expiration_time: u64, chain_id: u8, script_hash: vector<u8>, required_deposit: option::Option<u64>, is_simulation: bool)
 
@@ -1149,7 +1205,7 @@ Give some constraints that may abort according to the conditions. ### Function `multi_agent_script_prologue` -
fun multi_agent_script_prologue(sender: signer, txn_sequence_number: u64, txn_sender_public_key: vector<u8>, secondary_signer_addresses: vector<address>, secondary_signer_public_key_hashes: vector<vector<u8>>, txn_gas_price: u64, txn_max_gas_units: u64, txn_expiration_time: u64, chain_id: u8)
+
fun multi_agent_script_prologue(sender: signer, txn_sequence_number: u64, txn_sender_public_key: vector<u8>, secondary_signer_addresses: vector<address>, secondary_signer_public_key_hashes: vector<vector<u8>>, txn_gas_price: u64, txn_max_gas_units: u64, txn_expiration_time: u64, chain_id: u8, is_simulation: bool)
 
@@ -1178,7 +1234,7 @@ not equal the number of singers. ### Function `multi_agent_common_prologue` -
fun multi_agent_common_prologue(secondary_signer_addresses: vector<address>, secondary_signer_public_key_hashes: vector<vector<u8>>)
+
fun multi_agent_common_prologue(secondary_signer_addresses: vector<address>, secondary_signer_public_key_hashes: vector<vector<u8>>, is_simulation: bool)
 
@@ -1197,7 +1253,7 @@ not equal the number of singers. ### Function `fee_payer_script_prologue` -
fun fee_payer_script_prologue(sender: signer, txn_sequence_number: u64, txn_sender_public_key: vector<u8>, secondary_signer_addresses: vector<address>, secondary_signer_public_key_hashes: vector<vector<u8>>, fee_payer_address: address, fee_payer_public_key_hash: vector<u8>, txn_gas_price: u64, txn_max_gas_units: u64, txn_expiration_time: u64, chain_id: u8)
+
fun fee_payer_script_prologue(sender: signer, txn_sequence_number: u64, txn_sender_public_key: vector<u8>, secondary_signer_addresses: vector<address>, secondary_signer_public_key_hashes: vector<vector<u8>>, fee_payer_address: address, fee_payer_public_key_hash: vector<u8>, txn_gas_price: u64, txn_max_gas_units: u64, txn_expiration_time: u64, chain_id: u8, is_simulation: bool)
 
@@ -1227,7 +1283,7 @@ not equal the number of singers. ### Function `fee_payer_script_prologue_collect_deposit` -
fun fee_payer_script_prologue_collect_deposit(sender: signer, txn_sequence_number: u64, txn_sender_public_key: vector<u8>, secondary_signer_addresses: vector<address>, secondary_signer_public_key_hashes: vector<vector<u8>>, fee_payer_address: address, fee_payer_public_key_hash: vector<u8>, txn_gas_price: u64, txn_max_gas_units: u64, txn_expiration_time: u64, chain_id: u8, required_deposit: option::Option<u64>)
+
fun fee_payer_script_prologue_collect_deposit(sender: signer, txn_sequence_number: u64, txn_sender_public_key: vector<u8>, secondary_signer_addresses: vector<address>, secondary_signer_public_key_hashes: vector<vector<u8>>, fee_payer_address: address, fee_payer_public_key_hash: vector<u8>, txn_gas_price: u64, txn_max_gas_units: u64, txn_expiration_time: u64, chain_id: u8, required_deposit: option::Option<u64>, is_simulation: bool)
 
@@ -1243,7 +1299,7 @@ not equal the number of singers. ### Function `epilogue` -
fun epilogue(account: signer, storage_fee_refunded: u64, txn_gas_price: u64, txn_max_gas_units: u64, gas_units_remaining: u64)
+
fun epilogue(account: signer, storage_fee_refunded: u64, txn_gas_price: u64, txn_max_gas_units: u64, gas_units_remaining: u64, is_simulation: bool)
 
@@ -1263,7 +1319,7 @@ Skip transaction_fee::burn_fee verification. ### Function `epilogue_return_deposit` -
fun epilogue_return_deposit(account: signer, storage_fee_refunded: u64, txn_gas_price: u64, txn_max_gas_units: u64, gas_units_remaining: u64, required_deposit: option::Option<u64>)
+
fun epilogue_return_deposit(account: signer, storage_fee_refunded: u64, txn_gas_price: u64, txn_max_gas_units: u64, gas_units_remaining: u64, required_deposit: option::Option<u64>, is_simulation: bool)
 
@@ -1279,7 +1335,7 @@ Skip transaction_fee::burn_fee verification. ### Function `epilogue_gas_payer` -
fun epilogue_gas_payer(account: signer, gas_payer: address, storage_fee_refunded: u64, txn_gas_price: u64, txn_max_gas_units: u64, gas_units_remaining: u64)
+
fun epilogue_gas_payer(account: signer, gas_payer: address, storage_fee_refunded: u64, txn_gas_price: u64, txn_max_gas_units: u64, gas_units_remaining: u64, is_simulation: bool)
 
@@ -1365,7 +1421,7 @@ Skip transaction_fee::burn_fee verification. ### Function `epilogue_gas_payer_return_deposit` -
fun epilogue_gas_payer_return_deposit(account: signer, gas_payer: address, storage_fee_refunded: u64, txn_gas_price: u64, txn_max_gas_units: u64, gas_units_remaining: u64, required_deposit: option::Option<u64>)
+
fun epilogue_gas_payer_return_deposit(account: signer, gas_payer: address, storage_fee_refunded: u64, txn_gas_price: u64, txn_max_gas_units: u64, gas_units_remaining: u64, required_deposit: option::Option<u64>, is_simulation: bool)
 
diff --git a/aptos-move/framework/aptos-framework/sources/transaction_validation.move b/aptos-move/framework/aptos-framework/sources/transaction_validation.move index 95f59effb787a2..d5b86e93baf9a1 100644 --- a/aptos-move/framework/aptos-framework/sources/transaction_validation.move +++ b/aptos-move/framework/aptos-framework/sources/transaction_validation.move @@ -101,6 +101,7 @@ module aptos_framework::transaction_validation { txn_max_gas_units: u64, txn_expiration_time: u64, chain_id: u8, + is_simulation: bool, ) { assert!( timestamp::now_seconds() < txn_expiration_time, @@ -117,10 +118,12 @@ module aptos_framework::transaction_validation { || txn_sequence_number > 0 ) { assert!(account::exists_at(transaction_sender), error::invalid_argument(PROLOGUE_EACCOUNT_DOES_NOT_EXIST)); - assert!( - txn_authentication_key == account::get_authentication_key(transaction_sender), - error::invalid_argument(PROLOGUE_EINVALID_ACCOUNT_AUTH_KEY), - ); + if (!features::simulation_enhancement_enabled() || !is_simulation || !is_auth_key_empty(&txn_authentication_key)) { + assert!( + txn_authentication_key == account::get_authentication_key(transaction_sender), + error::invalid_argument(PROLOGUE_EINVALID_ACCOUNT_AUTH_KEY), + ) + }; let account_sequence_number = account::get_sequence_number(transaction_sender); assert!( @@ -153,16 +156,18 @@ module aptos_framework::transaction_validation { let max_transaction_fee = txn_gas_price * txn_max_gas_units; - if (features::operations_default_to_fa_apt_store_enabled()) { - assert!( - aptos_account::is_fungible_balance_at_least(gas_payer, max_transaction_fee), - error::invalid_argument(PROLOGUE_ECANT_PAY_GAS_DEPOSIT) - ); - } else { - assert!( - coin::is_balance_at_least(gas_payer, max_transaction_fee), - error::invalid_argument(PROLOGUE_ECANT_PAY_GAS_DEPOSIT) - ); + if (!features::simulation_enhancement_enabled() || !is_simulation || gas_payer != @0x0) { + if (features::operations_default_to_fa_apt_store_enabled()) { + assert!( + aptos_account::is_fungible_balance_at_least(gas_payer, max_transaction_fee), + error::invalid_argument(PROLOGUE_ECANT_PAY_GAS_DEPOSIT) + ); + } else { + assert!( + coin::is_balance_at_least(gas_payer, max_transaction_fee), + error::invalid_argument(PROLOGUE_ECANT_PAY_GAS_DEPOSIT) + ); + } } } @@ -175,9 +180,10 @@ module aptos_framework::transaction_validation { txn_expiration_time: u64, chain_id: u8, _script_hash: vector, + is_simulation: bool, ) { let gas_payer = signer::address_of(&sender); - prologue_common(sender, gas_payer, txn_sequence_number, txn_public_key, txn_gas_price, txn_max_gas_units, txn_expiration_time, chain_id) + prologue_common(sender, gas_payer, txn_sequence_number, txn_public_key, txn_gas_price, txn_max_gas_units, txn_expiration_time, chain_id, is_simulation) } /// `script_prologue()` then collect an optional deposit depending on the txn. @@ -193,9 +199,10 @@ module aptos_framework::transaction_validation { chain_id: u8, script_hash: vector, required_deposit: Option, + is_simulation: bool, ) { let gas_payer = signer::address_of(&sender); - script_prologue(sender, txn_sequence_number, txn_public_key, txn_gas_price, txn_max_gas_units, txn_expiration_time, chain_id, script_hash); + script_prologue(sender, txn_sequence_number, txn_public_key, txn_gas_price, txn_max_gas_units, txn_expiration_time, chain_id, script_hash, is_simulation); collect_deposit(gas_payer, required_deposit); } @@ -209,6 +216,7 @@ module aptos_framework::transaction_validation { txn_max_gas_units: u64, txn_expiration_time: u64, chain_id: u8, + is_simulation: bool, ) { let sender_addr = signer::address_of(&sender); prologue_common( @@ -220,13 +228,15 @@ module aptos_framework::transaction_validation { txn_max_gas_units, txn_expiration_time, chain_id, + is_simulation, ); - multi_agent_common_prologue(secondary_signer_addresses, secondary_signer_public_key_hashes); + multi_agent_common_prologue(secondary_signer_addresses, secondary_signer_public_key_hashes, is_simulation); } fun multi_agent_common_prologue( secondary_signer_addresses: vector
, secondary_signer_public_key_hashes: vector>, + is_simulation: bool, ) { let num_secondary_signers = vector::length(&secondary_signer_addresses); assert!( @@ -249,10 +259,12 @@ module aptos_framework::transaction_validation { assert!(account::exists_at(secondary_address), error::invalid_argument(PROLOGUE_EACCOUNT_DOES_NOT_EXIST)); let signer_public_key_hash = *vector::borrow(&secondary_signer_public_key_hashes, i); - assert!( - signer_public_key_hash == account::get_authentication_key(secondary_address), - error::invalid_argument(PROLOGUE_EINVALID_ACCOUNT_AUTH_KEY), - ); + if (!features::simulation_enhancement_enabled() || !is_simulation || !is_auth_key_empty(&signer_public_key_hash)) { + assert!( + signer_public_key_hash == account::get_authentication_key(secondary_address), + error::invalid_argument(PROLOGUE_EINVALID_ACCOUNT_AUTH_KEY), + ) + }; i = i + 1; } } @@ -269,6 +281,7 @@ module aptos_framework::transaction_validation { txn_max_gas_units: u64, txn_expiration_time: u64, chain_id: u8, + is_simulation: bool, ) { assert!(features::fee_payer_enabled(), error::invalid_state(PROLOGUE_EFEE_PAYER_NOT_ENABLED)); prologue_common( @@ -280,12 +293,15 @@ module aptos_framework::transaction_validation { txn_max_gas_units, txn_expiration_time, chain_id, + is_simulation, ); - multi_agent_common_prologue(secondary_signer_addresses, secondary_signer_public_key_hashes); - assert!( - fee_payer_public_key_hash == account::get_authentication_key(fee_payer_address), - error::invalid_argument(PROLOGUE_EINVALID_ACCOUNT_AUTH_KEY), - ); + multi_agent_common_prologue(secondary_signer_addresses, secondary_signer_public_key_hashes, is_simulation); + if (!features::simulation_enhancement_enabled() || !is_simulation || is_auth_key_empty(&fee_payer_public_key_hash)) { + assert!( + fee_payer_public_key_hash == account::get_authentication_key(fee_payer_address), + error::invalid_argument(PROLOGUE_EINVALID_ACCOUNT_AUTH_KEY), + ) + } } /// `fee_payer_script_prologue()` then collect an optional deposit depending on the txn. @@ -304,6 +320,7 @@ module aptos_framework::transaction_validation { txn_expiration_time: u64, chain_id: u8, required_deposit: Option, + is_simulation: bool, ) { fee_payer_script_prologue( sender, @@ -317,8 +334,11 @@ module aptos_framework::transaction_validation { txn_max_gas_units, txn_expiration_time, chain_id, + is_simulation, ); - collect_deposit(fee_payer_address, required_deposit); + if (!features::simulation_enhancement_enabled() || !is_simulation || fee_payer_address != @0x0) { + collect_deposit(fee_payer_address, required_deposit); + } } /// Epilogue function is run after a transaction is successfully executed. @@ -328,10 +348,11 @@ module aptos_framework::transaction_validation { storage_fee_refunded: u64, txn_gas_price: u64, txn_max_gas_units: u64, - gas_units_remaining: u64 + gas_units_remaining: u64, + is_simulation: bool, ) { let addr = signer::address_of(&account); - epilogue_gas_payer(account, addr, storage_fee_refunded, txn_gas_price, txn_max_gas_units, gas_units_remaining); + epilogue_gas_payer(account, addr, storage_fee_refunded, txn_gas_price, txn_max_gas_units, gas_units_remaining, is_simulation); } /// Return the deposit held in prologue, then `epilogue()`. @@ -344,15 +365,19 @@ module aptos_framework::transaction_validation { txn_max_gas_units: u64, gas_units_remaining: u64, required_deposit: Option, + is_simulation: bool, ) { let gas_payer = signer::address_of(&account); - return_deposit(gas_payer, required_deposit); + if (!features::simulation_enhancement_enabled() || !is_simulation || gas_payer != @0x0) { + return_deposit(gas_payer, required_deposit) + }; epilogue( account, storage_fee_refunded, txn_gas_price, txn_max_gas_units, gas_units_remaining, + is_simulation, ); } @@ -364,7 +389,8 @@ module aptos_framework::transaction_validation { storage_fee_refunded: u64, txn_gas_price: u64, txn_max_gas_units: u64, - gas_units_remaining: u64 + gas_units_remaining: u64, + is_simulation: bool, ) { assert!(txn_max_gas_units >= gas_units_remaining, error::invalid_argument(EOUT_OF_GAS)); let gas_used = txn_max_gas_units - gas_units_remaining; @@ -377,39 +403,41 @@ module aptos_framework::transaction_validation { // it's important to maintain the error code consistent with vm // to do failed transaction cleanup. - if (features::operations_default_to_fa_apt_store_enabled()) { - assert!( - aptos_account::is_fungible_balance_at_least(gas_payer, transaction_fee_amount), - error::out_of_range(PROLOGUE_ECANT_PAY_GAS_DEPOSIT), - ); - } else { - assert!( - coin::is_balance_at_least(gas_payer, transaction_fee_amount), - error::out_of_range(PROLOGUE_ECANT_PAY_GAS_DEPOSIT), - ); - }; - - let amount_to_burn = if (features::collect_and_distribute_gas_fees()) { - // TODO(gas): We might want to distinguish the refundable part of the charge and burn it or track - // it separately, so that we don't increase the total supply by refunding. + if (!features::simulation_enhancement_enabled() || !is_simulation || gas_payer != @0x0) { + if (features::operations_default_to_fa_apt_store_enabled()) { + assert!( + aptos_account::is_fungible_balance_at_least(gas_payer, transaction_fee_amount), + error::out_of_range(PROLOGUE_ECANT_PAY_GAS_DEPOSIT), + ); + } else { + assert!( + coin::is_balance_at_least(gas_payer, transaction_fee_amount), + error::out_of_range(PROLOGUE_ECANT_PAY_GAS_DEPOSIT), + ); + }; - // If transaction fees are redistributed to validators, collect them here for - // later redistribution. - transaction_fee::collect_fee(gas_payer, transaction_fee_amount); - 0 - } else { - // Otherwise, just burn the fee. - // TODO: this branch should be removed completely when transaction fee collection - // is tested and is fully proven to work well. - transaction_fee_amount - }; + let amount_to_burn = if (features::collect_and_distribute_gas_fees()) { + // TODO(gas): We might want to distinguish the refundable part of the charge and burn it or track + // it separately, so that we don't increase the total supply by refunding. + + // If transaction fees are redistributed to validators, collect them here for + // later redistribution. + transaction_fee::collect_fee(gas_payer, transaction_fee_amount); + 0 + } else { + // Otherwise, just burn the fee. + // TODO: this branch should be removed completely when transaction fee collection + // is tested and is fully proven to work well. + transaction_fee_amount + }; - if (amount_to_burn > storage_fee_refunded) { - let burn_amount = amount_to_burn - storage_fee_refunded; - transaction_fee::burn_fee(gas_payer, burn_amount); - } else if (amount_to_burn < storage_fee_refunded) { - let mint_amount = storage_fee_refunded - amount_to_burn; - transaction_fee::mint_and_refund(gas_payer, mint_amount) + if (amount_to_burn > storage_fee_refunded) { + let burn_amount = amount_to_burn - storage_fee_refunded; + transaction_fee::burn_fee(gas_payer, burn_amount); + } else if (amount_to_burn < storage_fee_refunded) { + let mint_amount = storage_fee_refunded - amount_to_burn; + transaction_fee::mint_and_refund(gas_payer, mint_amount) + }; }; // Increment sequence number @@ -428,6 +456,7 @@ module aptos_framework::transaction_validation { txn_max_gas_units: u64, gas_units_remaining: u64, required_deposit: Option, + is_simulation: bool, ) { return_deposit(gas_payer, required_deposit); epilogue_gas_payer( @@ -437,6 +466,11 @@ module aptos_framework::transaction_validation { txn_gas_price, txn_max_gas_units, gas_units_remaining, + is_simulation, ); } + + inline fun is_auth_key_empty(auth_key: &vector): bool { + vector::is_empty(auth_key) + } } diff --git a/aptos-move/framework/aptos-framework/sources/transaction_validation.spec.move b/aptos-move/framework/aptos-framework/sources/transaction_validation.spec.move index f50b7b7b0dc15b..8d4a26ad764403 100644 --- a/aptos-move/framework/aptos-framework/sources/transaction_validation.spec.move +++ b/aptos-move/framework/aptos-framework/sources/transaction_validation.spec.move @@ -106,6 +106,7 @@ spec aptos_framework::transaction_validation { txn_max_gas_units: u64, txn_expiration_time: u64, chain_id: u8, + is_simulation: bool, ) { // TODO(fa_migration) pragma verify = false; @@ -121,6 +122,7 @@ spec aptos_framework::transaction_validation { txn_expiration_time: u64, chain_id: u8, _script_hash: vector, + is_simulation: bool, ) { // TODO(fa_migration) pragma verify = false; @@ -156,6 +158,7 @@ spec aptos_framework::transaction_validation { spec multi_agent_common_prologue( secondary_signer_addresses: vector
, secondary_signer_public_key_hashes: vector>, + is_simulation: bool, ) { include MultiAgentPrologueCommonAbortsIf { secondary_signer_addresses, @@ -175,6 +178,7 @@ spec aptos_framework::transaction_validation { txn_max_gas_units: u64, txn_expiration_time: u64, chain_id: u8, + is_simulation: bool, ) { pragma verify_duration_estimate = 120; let gas_payer = signer::address_of(sender); @@ -203,6 +207,7 @@ spec aptos_framework::transaction_validation { txn_max_gas_units: u64, txn_expiration_time: u64, chain_id: u8, + is_simulation: bool, ) { pragma verify_duration_estimate = 120; @@ -231,7 +236,8 @@ spec aptos_framework::transaction_validation { storage_fee_refunded: u64, txn_gas_price: u64, txn_max_gas_units: u64, - gas_units_remaining: u64 + gas_units_remaining: u64, + is_simulation: bool, ) { // TODO(fa_migration) pragma verify = false; @@ -247,7 +253,8 @@ spec aptos_framework::transaction_validation { storage_fee_refunded: u64, txn_gas_price: u64, txn_max_gas_units: u64, - gas_units_remaining: u64 + gas_units_remaining: u64, + is_simulation: bool, ) { // TODO(fa_migration) pragma verify = false; diff --git a/aptos-move/framework/move-stdlib/doc/features.md b/aptos-move/framework/move-stdlib/doc/features.md index d35bb996c55c86..2d8b9da48929c7 100644 --- a/aptos-move/framework/move-stdlib/doc/features.md +++ b/aptos-move/framework/move-stdlib/doc/features.md @@ -129,6 +129,8 @@ return true. - [Function `default_to_concurrent_fungible_balance_enabled`](#0x1_features_default_to_concurrent_fungible_balance_enabled) - [Function `get_abort_if_multisig_payload_mismatch_feature`](#0x1_features_get_abort_if_multisig_payload_mismatch_feature) - [Function `abort_if_multisig_payload_mismatch_enabled`](#0x1_features_abort_if_multisig_payload_mismatch_enabled) +- [Function `get_simulation_enhancement_feature`](#0x1_features_get_simulation_enhancement_feature) +- [Function `simulation_enhancement_enabled`](#0x1_features_simulation_enhancement_enabled) - [Function `change_feature_flags`](#0x1_features_change_feature_flags) - [Function `change_feature_flags_internal`](#0x1_features_change_feature_flags_internal) - [Function `change_feature_flags_for_next_epoch`](#0x1_features_change_feature_flags_for_next_epoch) @@ -822,6 +824,19 @@ Lifetime: transient + + +Whether the multisig v2 fix is enabled. Once enabled, the multisig transaction execution will explicitly +abort if the provided payload does not match the payload stored on-chain. + +Lifetime: transient + + +
const SIMULATION_ENHANCEMENT: u64 = 71;
+
+ + + @@ -3152,6 +3167,52 @@ Lifetime: transient + + + + +## Function `get_simulation_enhancement_feature` + + + +
public fun get_simulation_enhancement_feature(): u64
+
+ + + +
+Implementation + + +
public fun get_simulation_enhancement_feature(): u64 { SIMULATION_ENHANCEMENT }
+
+ + + +
+ + + +## Function `simulation_enhancement_enabled` + + + +
public fun simulation_enhancement_enabled(): bool
+
+ + + +
+Implementation + + +
public fun simulation_enhancement_enabled(): bool acquires Features {
+    is_enabled(SIMULATION_ENHANCEMENT)
+}
+
+ + +
diff --git a/aptos-move/framework/move-stdlib/sources/configs/features.move b/aptos-move/framework/move-stdlib/sources/configs/features.move index a1e55fc0653d0b..7547769e523ef4 100644 --- a/aptos-move/framework/move-stdlib/sources/configs/features.move +++ b/aptos-move/framework/move-stdlib/sources/configs/features.move @@ -582,6 +582,18 @@ module std::features { is_enabled(ABORT_IF_MULTISIG_PAYLOAD_MISMATCH) } + /// Whether the multisig v2 fix is enabled. Once enabled, the multisig transaction execution will explicitly + /// abort if the provided payload does not match the payload stored on-chain. + /// + /// Lifetime: transient + const SIMULATION_ENHANCEMENT: u64 = 71; + + public fun get_simulation_enhancement_feature(): u64 { SIMULATION_ENHANCEMENT } + + public fun simulation_enhancement_enabled(): bool acquires Features { + is_enabled(SIMULATION_ENHANCEMENT) + } + // ============================================================================================ // Feature Flag Implementation diff --git a/execution/executor/src/components/chunk_output.rs b/execution/executor/src/components/chunk_output.rs index 13a57887338814..a044f496dfa304 100644 --- a/execution/executor/src/components/chunk_output.rs +++ b/execution/executor/src/components/chunk_output.rs @@ -392,6 +392,11 @@ pub fn update_counters_for_processed_chunk( .inc(); } }, + AccountAuthenticator::NoAccountAuthenticator => { // TODO: check this. + metrics::APTOS_PROCESSED_TXNS_AUTHENTICATOR + .with_label_values(&[process_type, "NoAccountAuthenticator"]) + .inc(); + }, }; } diff --git a/types/src/on_chain_config/aptos_features.rs b/types/src/on_chain_config/aptos_features.rs index af11392ea60071..86b7ad445fd70c 100644 --- a/types/src/on_chain_config/aptos_features.rs +++ b/types/src/on_chain_config/aptos_features.rs @@ -86,6 +86,7 @@ pub enum FeatureFlag { DEFAULT_TO_CONCURRENT_FUNGIBLE_BALANCE = 68, LIMIT_VM_TYPE_SIZE = 69, ABORT_IF_MULTISIG_PAYLOAD_MISMATCH = 70, + SIMULATION_ENHANCEMENT = 71, } impl FeatureFlag { @@ -152,6 +153,7 @@ impl FeatureFlag { FeatureFlag::CONCURRENT_FUNGIBLE_BALANCE, // FeatureFlag::LIMIT_VM_TYPE_SIZE, // TODO: Enable when type builder rolls out FeatureFlag::ABORT_IF_MULTISIG_PAYLOAD_MISMATCH, + FeatureFlag::SIMULATION_ENHANCEMENT, ] } } diff --git a/types/src/transaction/authenticator.rs b/types/src/transaction/authenticator.rs index 7aa6ede30680ab..98f91bfc3119bf 100644 --- a/types/src/transaction/authenticator.rs +++ b/types/src/transaction/authenticator.rs @@ -358,6 +358,9 @@ impl TransactionAuthenticator { AccountAuthenticator::MultiKey { authenticator } => { single_key_authenticators.extend(authenticator.to_single_key_authenticators()?); }, + AccountAuthenticator::NoAccountAuthenticator => { + // TODO: check this. + }, }; } Ok(single_key_authenticators) @@ -449,6 +452,7 @@ pub enum Scheme { MultiEd25519 = 1, SingleKey = 2, MultiKey = 3, + NoScheme = 250, /// Scheme identifier used to derive addresses (not the authentication key) of objects and /// resources accounts. This application serves to domain separate hashes. Without such /// separation, an adversary could create (and get a signer for) a these accounts @@ -468,6 +472,7 @@ impl fmt::Display for Scheme { Scheme::MultiEd25519 => "MultiEd25519", Scheme::SingleKey => "SingleKey", Scheme::MultiKey => "MultiKey", + Scheme::NoScheme => "NoScheme", Scheme::DeriveAuid => "DeriveAuid", Scheme::DeriveObjectAddressFromObject => "DeriveObjectAddressFromObject", Scheme::DeriveObjectAddressFromGuid => "DeriveObjectAddressFromGuid", @@ -502,6 +507,7 @@ pub enum AccountAuthenticator { MultiKey { authenticator: MultiKeyAuthenticator, }, + NoAccountAuthenticator, // ... add more schemes here } @@ -513,6 +519,7 @@ impl AccountAuthenticator { Self::MultiEd25519 { .. } => Scheme::MultiEd25519, Self::SingleKey { .. } => Scheme::SingleKey, Self::MultiKey { .. } => Scheme::MultiKey, + Self::NoAccountAuthenticator => Scheme::NoScheme, } } @@ -558,6 +565,7 @@ impl AccountAuthenticator { } => signature.verify(message, public_key), Self::SingleKey { authenticator } => authenticator.verify(message), Self::MultiKey { authenticator } => authenticator.verify(message), + Self::NoAccountAuthenticator => bail!("No signature to verify."), } } @@ -568,6 +576,7 @@ impl AccountAuthenticator { Self::MultiEd25519 { public_key, .. } => public_key.to_bytes().to_vec(), Self::SingleKey { authenticator } => authenticator.public_key_bytes(), Self::MultiKey { authenticator } => authenticator.public_key_bytes(), + Self::NoAccountAuthenticator => vec![], // TODO: check this. } } @@ -578,12 +587,20 @@ impl AccountAuthenticator { Self::MultiEd25519 { signature, .. } => signature.to_bytes().to_vec(), Self::SingleKey { authenticator } => authenticator.signature_bytes(), Self::MultiKey { authenticator } => authenticator.signature_bytes(), + Self::NoAccountAuthenticator => vec![], // TODO: check this. } } /// Return an authentication key derived from `self`'s public key and scheme id - pub fn authentication_key(&self) -> AuthenticationKey { - AuthenticationKey::from_preimage(self.public_key_bytes(), self.scheme()) + pub fn authentication_key(&self) -> Option { + if let Self::NoAccountAuthenticator = self { + None + } else { + Some(AuthenticationKey::from_preimage( + self.public_key_bytes(), + self.scheme(), + )) + } } /// Return the number of signatures included in this account authenticator. @@ -593,6 +610,7 @@ impl AccountAuthenticator { Self::MultiEd25519 { signature, .. } => signature.signatures().len(), Self::SingleKey { .. } => 1, Self::MultiKey { authenticator } => authenticator.signatures.len(), + Self::NoAccountAuthenticator => 0, } } }