Skip to content

Commit f92a197

Browse files
[aptosvm] Simplify VM flows (#11888)
* Duplicated logic for creating the gas meter for view functions has been removed. * Duplicated logic for calculating gas used for view functions has been removed. * There was unreachable code in failure transaction cleanup, where the discarded status has been returned immediately, but then re-checked again. The first check is shifted inside. * No more default transaction metadata. * Scripts are now validated consistently. * Simplifies transaction execution function signature to avoid `Option<String>`. * Removes duplicated features from `AptosVM` and keeps them in `MoveVMExt`. * Fixes a bug when script hash was not computed for `RunOnAbort`. Related tests are moved to `move-e2e-tests`.
1 parent 0d29ccd commit f92a197

File tree

14 files changed

+353
-471
lines changed

14 files changed

+353
-471
lines changed

aptos-move/aptos-vm/src/aptos_vm.rs

+161-255
Large diffs are not rendered by default.

aptos-move/aptos-vm/src/block_executor/vm_wrapper.rs

+5-16
Original file line numberDiff line numberDiff line change
@@ -64,23 +64,12 @@ impl<'a, S: 'a + StateView + Sync> ExecutorTask for AptosExecutorTask<'a, S> {
6464
.vm
6565
.execute_single_transaction(txn, &resolver, &log_context)
6666
{
67-
Ok((vm_status, vm_output, sender)) => {
67+
Ok((vm_status, vm_output)) => {
6868
if vm_output.status().is_discarded() {
69-
match sender {
70-
Some(s) => speculative_trace!(
71-
&log_context,
72-
format!(
73-
"Transaction discarded, sender: {}, error: {:?}",
74-
s, vm_status
75-
),
76-
),
77-
None => {
78-
speculative_trace!(
79-
&log_context,
80-
format!("Transaction malformed, error: {:?}", vm_status),
81-
)
82-
},
83-
};
69+
speculative_trace!(
70+
&log_context,
71+
format!("Transaction discarded, status: {:?}", vm_status),
72+
);
8473
}
8574
if vm_status.status_code() == StatusCode::SPECULATIVE_EXECUTION_ABORT_ERROR {
8675
ExecutionStatus::SpeculativeExecutionAbortError(

aptos-move/aptos-vm/src/move_vm_ext/session.rs

+35-8
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use aptos_framework::natives::{
1616
use aptos_table_natives::{NativeTableContext, TableChangeSet};
1717
use aptos_types::{
1818
access_path::AccessPath, block_metadata::BlockMetadata, block_metadata_ext::BlockMetadataExt,
19-
contract_event::ContractEvent, on_chain_config::Features, state_store::state_key::StateKey,
19+
contract_event::ContractEvent, state_store::state_key::StateKey,
2020
validator_txn::ValidatorTransaction,
2121
};
2222
use aptos_vm_types::{change_set::VMChangeSet, storage::change_set_configs::ChangeSetConfigs};
@@ -151,24 +151,54 @@ impl SessionId {
151151
pub fn as_uuid(&self) -> HashValue {
152152
self.hash()
153153
}
154+
155+
pub(crate) fn into_script_hash(self) -> Vec<u8> {
156+
match self {
157+
Self::Txn {
158+
sender: _,
159+
sequence_number: _,
160+
script_hash,
161+
}
162+
| Self::Prologue {
163+
sender: _,
164+
sequence_number: _,
165+
script_hash,
166+
}
167+
| Self::Epilogue {
168+
sender: _,
169+
sequence_number: _,
170+
script_hash,
171+
}
172+
| Self::RunOnAbort {
173+
sender: _,
174+
sequence_number: _,
175+
script_hash,
176+
}
177+
| Self::ValidatorTxn { script_hash } => script_hash,
178+
Self::BlockMeta { id: _ }
179+
| Self::Genesis { id: _ }
180+
| Self::Void
181+
| Self::BlockMetaExt { id: _ } => vec![],
182+
}
183+
}
154184
}
155185

156186
pub struct SessionExt<'r, 'l> {
157187
inner: Session<'r, 'l>,
158188
remote: &'r dyn AptosMoveResolver,
159-
features: Arc<Features>,
189+
is_storage_slot_metadata_enabled: bool,
160190
}
161191

162192
impl<'r, 'l> SessionExt<'r, 'l> {
163193
pub fn new(
164194
inner: Session<'r, 'l>,
165195
remote: &'r dyn AptosMoveResolver,
166-
features: Arc<Features>,
196+
is_storage_slot_metadata_enabled: bool,
167197
) -> Self {
168198
Self {
169199
inner,
170200
remote,
171-
features,
201+
is_storage_slot_metadata_enabled,
172202
}
173203
}
174204

@@ -219,10 +249,7 @@ impl<'r, 'l> SessionExt<'r, 'l> {
219249
let event_context: NativeEventContext = extensions.remove();
220250
let events = event_context.into_events();
221251

222-
let woc = WriteOpConverter::new(
223-
self.remote,
224-
self.features.is_storage_slot_metadata_enabled(),
225-
);
252+
let woc = WriteOpConverter::new(self.remote, self.is_storage_slot_metadata_enabled);
226253

227254
let change_set = Self::convert_change_set(
228255
&woc,

aptos-move/aptos-vm/src/move_vm_ext/vm.rs

+8-32
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,7 @@ use aptos_gas_algebra::DynamicExpression;
1414
use aptos_gas_schedule::{MiscGasParameters, NativeGasParameters};
1515
use aptos_native_interface::SafeNativeBuilder;
1616
use aptos_table_natives::NativeTableContext;
17-
use aptos_types::{
18-
chain_id::ChainId,
19-
on_chain_config::{FeatureFlag, Features, TimedFeatureFlag, TimedFeatures},
20-
};
17+
use aptos_types::on_chain_config::{FeatureFlag, Features, TimedFeatureFlag, TimedFeatures};
2118
use move_binary_format::{
2219
deserializer::DeserializerConfig,
2320
errors::VMResult,
@@ -28,12 +25,12 @@ use move_bytecode_verifier::VerifierConfig;
2825
use move_vm_runtime::{
2926
config::VMConfig, move_vm::MoveVM, native_extensions::NativeContextExtensions,
3027
};
31-
use std::{ops::Deref, sync::Arc};
28+
use std::ops::Deref;
3229

3330
pub struct MoveVmExt {
3431
inner: MoveVM,
3532
chain_id: u8,
36-
features: Arc<Features>,
33+
features: Features,
3734
}
3835

3936
pub fn get_max_binary_format_version(
@@ -134,7 +131,7 @@ impl MoveVmExt {
134131
resolver,
135132
)?,
136133
chain_id,
137-
features: Arc::new(features),
134+
features,
138135
})
139136
}
140137

@@ -204,30 +201,9 @@ impl MoveVmExt {
204201
extensions.add(NativeRistrettoPointContext::new());
205202
extensions.add(AlgebraContext::new());
206203
extensions.add(NativeAggregatorContext::new(txn_hash, resolver, resolver));
207-
208-
let script_hash = match session_id {
209-
SessionId::Txn {
210-
sender: _,
211-
sequence_number: _,
212-
script_hash,
213-
}
214-
| SessionId::Prologue {
215-
sender: _,
216-
sequence_number: _,
217-
script_hash,
218-
}
219-
| SessionId::Epilogue {
220-
sender: _,
221-
sequence_number: _,
222-
script_hash,
223-
} => script_hash,
224-
SessionId::ValidatorTxn { script_hash } => script_hash,
225-
_ => vec![],
226-
};
227-
228204
extensions.add(NativeTransactionContext::new(
229205
txn_hash.to_vec(),
230-
script_hash,
206+
session_id.into_script_hash(),
231207
self.chain_id,
232208
));
233209
extensions.add(NativeCodeContext::default());
@@ -241,12 +217,12 @@ impl MoveVmExt {
241217
SessionExt::new(
242218
self.inner.new_session_with_extensions(resolver, extensions),
243219
resolver,
244-
self.features.clone(),
220+
self.features.is_storage_slot_metadata_enabled(),
245221
)
246222
}
247223

248-
pub fn get_chain_id(&self) -> ChainId {
249-
ChainId::new(self.chain_id)
224+
pub(crate) fn features(&self) -> &Features {
225+
&self.features
250226
}
251227
}
252228

aptos-move/aptos-vm/src/testing.rs

+39
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
11
// Copyright © Aptos Foundation
22
// SPDX-License-Identifier: Apache-2.0
33

4+
use crate::{
5+
aptos_vm::get_or_vm_startup_failure, data_cache::AsMoveResolver,
6+
transaction_metadata::TransactionMetadata, AptosVM,
7+
};
8+
use aptos_types::{state_store::StateView, transaction::SignedTransaction};
9+
use aptos_vm_logging::log_schema::AdapterLogSchema;
10+
use aptos_vm_types::output::VMOutput;
411
use move_binary_format::errors::VMResult;
12+
use move_core_types::vm_status::VMStatus;
513

614
#[derive(Debug, Eq, Hash, PartialEq)]
715
pub enum InjectedError {
@@ -47,3 +55,34 @@ pub mod testing_only {
4755
})
4856
}
4957
}
58+
59+
impl AptosVM {
60+
#[cfg(any(test, feature = "testing"))]
61+
pub fn test_failed_transaction_cleanup(
62+
&self,
63+
error_vm_status: VMStatus,
64+
txn: &SignedTransaction,
65+
state_view: &impl StateView,
66+
gas_meter_balance: u64,
67+
) -> (VMStatus, VMOutput) {
68+
let txn_data = TransactionMetadata::new(txn);
69+
let log_context = AdapterLogSchema::new(state_view.id(), 0);
70+
71+
let mut gas_meter = self
72+
.make_standard_gas_meter(gas_meter_balance.into(), &log_context)
73+
.expect("Should be able to create a gas meter for tests");
74+
let change_set_configs = &get_or_vm_startup_failure(&self.storage_gas_params, &log_context)
75+
.expect("Storage gas parameters should exist for tests")
76+
.change_set_configs;
77+
78+
let resolver = state_view.as_move_resolver();
79+
self.failed_transaction_cleanup(
80+
error_vm_status,
81+
&mut gas_meter,
82+
&txn_data,
83+
&resolver,
84+
&log_context,
85+
change_set_configs,
86+
)
87+
}
88+
}

aptos-move/aptos-vm/src/transaction_metadata.rs

+3-28
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,13 @@
22
// Parts of the project are originally copyright © Meta Platforms, Inc.
33
// SPDX-License-Identifier: Apache-2.0
44

5-
use aptos_crypto::{ed25519::Ed25519PrivateKey, HashValue, PrivateKey};
5+
use aptos_crypto::HashValue;
66
use aptos_gas_algebra::{FeePerGasUnit, Gas, NumBytes};
77
use aptos_types::{
88
account_address::AccountAddress,
99
chain_id::ChainId,
10-
transaction::{authenticator::AuthenticationKey, SignedTransaction, TransactionPayload},
10+
transaction::{SignedTransaction, TransactionPayload},
1111
};
12-
use std::convert::TryFrom;
1312

1413
pub struct TransactionMetadata {
1514
pub sender: AccountAddress,
@@ -118,30 +117,6 @@ impl TransactionMetadata {
118117
}
119118

120119
pub fn is_multi_agent(&self) -> bool {
121-
!(self.secondary_signers.is_empty() && self.fee_payer.is_none())
122-
}
123-
}
124-
125-
impl Default for TransactionMetadata {
126-
fn default() -> Self {
127-
let mut buf = [0u8; Ed25519PrivateKey::LENGTH];
128-
buf[Ed25519PrivateKey::LENGTH - 1] = 1;
129-
let public_key = Ed25519PrivateKey::try_from(&buf[..]).unwrap().public_key();
130-
TransactionMetadata {
131-
sender: AccountAddress::ZERO,
132-
authentication_key: AuthenticationKey::ed25519(&public_key).to_vec(),
133-
secondary_signers: vec![],
134-
secondary_authentication_keys: vec![],
135-
sequence_number: 0,
136-
fee_payer: None,
137-
fee_payer_authentication_key: None,
138-
max_gas_amount: 100_000_000.into(),
139-
gas_unit_price: 0.into(),
140-
transaction_size: 0.into(),
141-
expiration_timestamp_secs: 0,
142-
chain_id: ChainId::test(),
143-
script_hash: vec![],
144-
script_size: NumBytes::zero(),
145-
}
120+
!self.secondary_signers.is_empty() || self.fee_payer.is_some()
146121
}
147122
}

aptos-move/aptos-vm/src/zkid_validation.rs

+15-3
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use aptos_crypto::ed25519::Ed25519PublicKey;
77
use aptos_types::{
88
invalid_signature,
99
jwks::{jwk::JWK, PatchedJWKs},
10-
on_chain_config::{CurrentTimeMicroseconds, OnChainConfig},
10+
on_chain_config::{CurrentTimeMicroseconds, Features, OnChainConfig},
1111
transaction::authenticator::EphemeralPublicKey,
1212
vm_status::{StatusCode, VMStatus},
1313
zkid::{
@@ -100,16 +100,28 @@ fn get_jwk_for_zkid_authenticator(
100100
Ok(jwk)
101101
}
102102

103-
pub fn validate_zkid_authenticators(
103+
pub(crate) fn validate_zkid_authenticators(
104104
authenticators: &Vec<(ZkIdPublicKey, ZkIdSignature)>,
105+
features: &Features,
105106
resolver: &impl AptosMoveResolver,
106107
) -> Result<(), VMStatus> {
108+
// zkID feature gating.
109+
for (_, sig) in authenticators {
110+
if !features.is_zkid_enabled() && matches!(sig.sig, ZkpOrOpenIdSig::Groth16Zkp { .. }) {
111+
return Err(VMStatus::error(StatusCode::FEATURE_UNDER_GATING, None));
112+
}
113+
if (!features.is_zkid_enabled() || !features.is_zkid_zkless_enabled())
114+
&& matches!(sig.sig, ZkpOrOpenIdSig::OpenIdSig { .. })
115+
{
116+
return Err(VMStatus::error(StatusCode::FEATURE_UNDER_GATING, None));
117+
}
118+
}
119+
107120
if authenticators.is_empty() {
108121
return Ok(());
109122
}
110123

111124
let config = &get_configs_onchain(resolver)?;
112-
113125
if authenticators.len() > config.max_zkid_signatures_per_txn as usize {
114126
return Err(invalid_signature!("Too many zkID authenticators"));
115127
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright © Aptos Foundation
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
use crate::MoveHarness;
5+
use aptos_cached_packages::aptos_stdlib::aptos_account_transfer;
6+
use aptos_language_e2e_tests::account::Account;
7+
use claims::assert_err_eq;
8+
use move_core_types::vm_status::StatusCode;
9+
10+
#[test]
11+
fn non_existent_sender() {
12+
let mut h = MoveHarness::new();
13+
14+
let sender = Account::new();
15+
let receiver = h.new_account_with_balance_and_sequence_number(100_000, 0);
16+
17+
let txn = sender
18+
.transaction()
19+
.payload(aptos_account_transfer(*receiver.address(), 10))
20+
.sequence_number(0)
21+
.sign();
22+
23+
let status = h.run(txn);
24+
assert_err_eq!(status.status(), StatusCode::SENDING_ACCOUNT_DOES_NOT_EXIST);
25+
}

aptos-move/e2e-move-tests/src/tests/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// SPDX-License-Identifier: Apache-2.0
33

44
mod access_path_test;
5+
mod account;
56
mod aggregator;
67
mod aggregator_v2;
78
mod aggregator_v2_events;
@@ -46,4 +47,5 @@ mod token_objects;
4647
mod transaction_fee;
4748
mod type_too_large;
4849
mod vector_numeric_address;
50+
mod vm;
4951
mod vote;

0 commit comments

Comments
 (0)