forked from aptos-labs/aptos-core
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[AN-Issue-1394] Added AptosVMViewer wrapper on AptosVM for continous …
…view function execution - AptosVMViewer provides means to continously execute view functions on the same state-view without recreating VM over and over again compared to AptosVM. It provides better about 7-8 times better preformance compared to AptosVM. This will help to retrieve automation task inforamtion in more optimal way. - Added Rust variant of AutomationTaskMetaData and provided means to build AutomatedTransactions based on AutomationTaskMetaData - Enabled aptos-types unit-tests in CI flow. Ignored for the time being the tests which are currently failing. - Added tests for newly introduced APIs/fnctionalities
- Loading branch information
Aregnaz Harutyunyan
committed
Dec 20, 2024
1 parent
ace749e
commit 467724b
Showing
12 changed files
with
768 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
// Copyright (c) 2024 Supra. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
use aptos_types::state_store::StateView; | ||
use aptos_types::transaction::{ViewFunction, ViewFunctionOutput}; | ||
use aptos_vm_logging::log_schema::AdapterLogSchema; | ||
use crate::aptos_vm::get_or_vm_startup_failure; | ||
use crate::AptosVM; | ||
use crate::gas::{make_prod_gas_meter, ProdGasMeter}; | ||
use crate::move_vm_ext::SessionId::Void; | ||
|
||
/// Move VM with only view function API. | ||
/// Convenient to use when more than one view function needs to be executed on the same state-view, | ||
/// as it avoids to set up AptosVM upon each function execution. | ||
pub struct AptosVMViewer<'t, SV: StateView> { | ||
vm: AptosVM, | ||
state_view: &'t SV, | ||
log_context: AdapterLogSchema, | ||
} | ||
|
||
impl <'t, SV: StateView> AptosVMViewer<'t, SV> { | ||
/// Creates a new VM instance, initializing the runtime environment from the state. | ||
pub fn new(state_view: &'t SV) -> Self { | ||
let vm = AptosVM::new(state_view); | ||
let log_context = AdapterLogSchema::new(state_view.id(), 0); | ||
Self { | ||
vm , | ||
state_view, | ||
log_context | ||
} | ||
} | ||
|
||
fn create_gas_meter(&self, max_gas_amount: u64) -> anyhow::Result<ProdGasMeter> { | ||
let vm_gas_params = match get_or_vm_startup_failure(&self.vm.gas_params_internal(), &self.log_context) { | ||
Ok(gas_params) => gas_params.vm.clone(), | ||
Err(err) => { | ||
return Err(anyhow::Error::msg(format!("{}", err))) | ||
}, | ||
}; | ||
let storage_gas_params = | ||
match get_or_vm_startup_failure(&self.vm.storage_gas_params, &self.log_context) { | ||
Ok(gas_params) => gas_params.clone(), | ||
Err(err) => { | ||
return Err(anyhow::Error::msg(format!("{}", err))) | ||
}, | ||
}; | ||
|
||
let gas_meter = make_prod_gas_meter( | ||
self.vm.gas_feature_version, | ||
vm_gas_params, | ||
storage_gas_params, | ||
/* is_approved_gov_script */ false, | ||
max_gas_amount.into(), | ||
); | ||
Ok(gas_meter) | ||
} | ||
|
||
pub fn execute_view_function( | ||
&self, | ||
function: ViewFunction, | ||
max_gas_amount: u64, | ||
) -> ViewFunctionOutput { | ||
|
||
|
||
let resolver = self.vm.as_move_resolver(self.state_view); | ||
let mut session = self.vm.new_session(&resolver, Void, None); | ||
let mut gas_meter = match self.create_gas_meter(max_gas_amount) { | ||
Ok(meter) => meter, | ||
Err(e) => return ViewFunctionOutput::new(Err(e), 0) | ||
}; | ||
let (module_id, func_name, type_args, arguments) = function.into_inner(); | ||
|
||
let execution_result = AptosVM::execute_view_function_in_vm( | ||
&mut session, | ||
&self.vm, | ||
module_id, | ||
func_name, | ||
type_args, | ||
arguments, | ||
&mut gas_meter, | ||
); | ||
let gas_used = AptosVM::gas_used(max_gas_amount.into(), &gas_meter); | ||
match execution_result { | ||
Ok(result) => ViewFunctionOutput::new(Ok(result), gas_used), | ||
Err(e) => ViewFunctionOutput::new(Err(e), gas_used), | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,3 +28,4 @@ mod transaction_fuzzer; | |
mod verify_txn; | ||
mod automation_registration; | ||
mod automated_transactions; | ||
mod vm_viewer; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
// Copyright (c) 2024 Supra. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
use aptos_language_e2e_tests::executor::FakeExecutor; | ||
use aptos_types::move_utils::MemberId; | ||
use aptos_types::transaction::{ViewFunction, ViewFunctionOutput}; | ||
use aptos_vm::aptos_vm_viewer::AptosVMViewer; | ||
use move_core_types::language_storage::TypeTag; | ||
use std::time::Instant; | ||
|
||
const TIMESTAMP_NOW_SECONDS: &str = "0x1::timestamp::now_seconds"; | ||
const ACCOUNT_BALANCE: &str = "0x1::coin::balance"; | ||
const ACCOUNT_SEQ_NUM: &str = "0x1::account::get_sequence_number"; | ||
const SUPRA_COIN: &str = "0x1::supra_coin::SupraCoin"; | ||
|
||
fn to_view_function(fn_ref: MemberId, ty_args: Vec<TypeTag>, args: Vec<Vec<u8>>) -> ViewFunction { | ||
ViewFunction::new(fn_ref.module_id, fn_ref.member_id, ty_args, args) | ||
} | ||
|
||
fn extract_view_output(output: ViewFunctionOutput) -> Vec<u8> { | ||
output.values.unwrap().pop().unwrap() | ||
} | ||
#[test] | ||
fn test_vm_viewer() { | ||
let mut test_executor = FakeExecutor::from_head_genesis(); | ||
let timestamp_now_ref: MemberId = str::parse(TIMESTAMP_NOW_SECONDS).unwrap(); | ||
let account_seq_ref: MemberId = str::parse(ACCOUNT_SEQ_NUM).unwrap(); | ||
let account_balance_ref: MemberId = str::parse(ACCOUNT_BALANCE).unwrap(); | ||
let supra_coin_ty_tag: TypeTag = str::parse(SUPRA_COIN).unwrap(); | ||
|
||
// Prepare 5 accounts with different balance | ||
let accounts = (1..5) | ||
.map(|i| { | ||
let account = test_executor.create_raw_account_data(100 * i, i); | ||
test_executor.add_account_data(&account); | ||
account | ||
}) | ||
.collect::<Vec<_>>(); | ||
// Query account seq number and balance using direct AptosVM one-time interface | ||
let one_time_ifc_time = Instant::now(); | ||
let expected_results = accounts | ||
.iter() | ||
.map(|account| { | ||
let time = Instant::now(); | ||
let timestamp = extract_view_output(test_executor.execute_view_function( | ||
timestamp_now_ref.clone(), | ||
vec![], | ||
vec![], | ||
)); | ||
println!("AptosVM step: {}", time.elapsed().as_secs_f64()); | ||
let time = Instant::now(); | ||
let address_arg = account.address().to_vec(); | ||
let account_balance = extract_view_output(test_executor.execute_view_function( | ||
account_balance_ref.clone(), | ||
vec![supra_coin_ty_tag.clone()], | ||
vec![address_arg.clone()], | ||
)); | ||
println!("AptosVM step: {}", time.elapsed().as_secs_f64()); | ||
let time = Instant::now(); | ||
let account_seq_num = extract_view_output(test_executor.execute_view_function( | ||
account_seq_ref.clone(), | ||
vec![], | ||
vec![address_arg], | ||
)); | ||
println!("AptosVM step: {}", time.elapsed().as_secs_f64()); | ||
(timestamp, account_seq_num, account_balance) | ||
}) | ||
.collect::<Vec<_>>(); | ||
let one_time_ifc_time = one_time_ifc_time.elapsed().as_secs_f64(); | ||
|
||
// Now do the same with AptosVMViewer interface | ||
let viewer_ifc_time = Instant::now(); | ||
let time = Instant::now(); | ||
let vm_viewer = AptosVMViewer::new(test_executor.data_store()); | ||
println!("AptosVMViewer creation time: {}", time.elapsed().as_secs_f64()); | ||
let actual_results = accounts | ||
.iter() | ||
.map(|account| { | ||
let time = Instant::now(); | ||
let timestamp = extract_view_output(vm_viewer.execute_view_function( | ||
to_view_function(timestamp_now_ref.clone(), vec![], vec![]), | ||
u64::MAX, | ||
)); | ||
println!("AptosVMViewer step: {}", time.elapsed().as_secs_f64()); | ||
let time = Instant::now(); | ||
let address_arg = account.address().to_vec(); | ||
let account_balance = extract_view_output(vm_viewer.execute_view_function( | ||
to_view_function( | ||
account_balance_ref.clone(), | ||
vec![supra_coin_ty_tag.clone()], | ||
vec![address_arg.clone()], | ||
), | ||
u64::MAX, | ||
)); | ||
println!("AptosVMViewer step: {}", time.elapsed().as_secs_f64()); | ||
let time = Instant::now(); | ||
let account_seq_num = extract_view_output(vm_viewer.execute_view_function( | ||
to_view_function(account_seq_ref.clone(), vec![], vec![address_arg]), | ||
u64::MAX, | ||
)); | ||
println!("AptosVMViewer step: {}", time.elapsed().as_secs_f64()); | ||
(timestamp, account_seq_num, account_balance) | ||
}) | ||
.collect::<Vec<_>>(); | ||
let viewer_ifc_time = viewer_ifc_time.elapsed().as_secs_f64(); | ||
assert_eq!(actual_results, expected_results); | ||
println!("AptosVM: {one_time_ifc_time} - AptosVMViewer: {viewer_ifc_time}") | ||
} |
Oops, something went wrong.