Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[release builder] gov proposal simulation: show gas usage + add gas profiling support #15304

Merged
merged 1 commit into from
Nov 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions aptos-move/aptos-release-builder/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ aptos = { workspace = true, features = [ "no-upload-proposal" ] }
aptos-build-info = { workspace = true }
aptos-crypto = { workspace = true }
aptos-framework = { workspace = true }
aptos-gas-profiling = { workspace = true }
aptos-gas-schedule = { workspace = true }
aptos-gas-schedule-updator = { workspace = true }
aptos-genesis = { workspace = true }
Expand Down
39 changes: 33 additions & 6 deletions aptos-move/aptos-release-builder/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright © Aptos Foundation
// SPDX-License-Identifier: Apache-2.0

use anyhow::Context;
use anyhow::{bail, Context};
use aptos_crypto::{ed25519::Ed25519PrivateKey, ValidCryptoMaterialStringExt};
use aptos_framework::natives::code::PackageRegistry;
use aptos_gas_schedule::LATEST_GAS_FEATURE_VERSION;
Expand Down Expand Up @@ -69,13 +69,22 @@ impl NetworkSelection {
pub enum Commands {
/// Generate sets of governance proposals based on the release_config file passed in
GenerateProposals {
/// Path to the release config.
#[clap(short, long)]
release_config: PathBuf,

/// Output directory to store the generated artifacts.
#[clap(short, long)]
output_dir: PathBuf,

/// If set, simulate the governance proposals after generation.
#[clap(long)]
simulate: Option<NetworkSelection>,

/// Set this flag to enable the gas profiler.
/// Can only be used in combination with `--simulate`.
#[clap(long)]
profile_gas: Option<bool>,
},
/// Simulate a multi-step proposal on the specified network, using its current states.
/// The simulation will execute the governance scripts, as if the proposal is already
Expand All @@ -91,6 +100,10 @@ pub enum Commands {
/// Possible values: devnet, testnet, mainnet, <url to rest endpoint>
#[clap(long)]
network: NetworkSelection,

/// Set this flag to enable the gas profiler
#[clap(long, default_value_t = false)]
vgao1996 marked this conversation as resolved.
Show resolved Hide resolved
profile_gas: bool,
},
/// Generate sets of governance proposals with default release config.
WriteDefault {
Expand Down Expand Up @@ -184,22 +197,36 @@ async fn main() -> anyhow::Result<()> {
release_config,
output_dir,
simulate,
profile_gas,
} => {
aptos_release_builder::ReleaseConfig::load_config(release_config.as_path())
.with_context(|| "Failed to load release config".to_string())?
.generate_release_proposal_scripts(output_dir.as_path())
.await
.with_context(|| "Failed to generate release proposal scripts".to_string())?;

if let Some(network) = simulate {
let remote_endpoint = network.to_url()?;
simulate_all_proposals(remote_endpoint, output_dir.as_path()).await?;
match simulate {
Some(network) => {
let profile_gas = profile_gas.unwrap_or(false);
let remote_endpoint = network.to_url()?;
simulate_all_proposals(remote_endpoint, output_dir.as_path(), profile_gas)
.await?;
},
None => {
if profile_gas.is_some() {
bail!("--profile-gas can only be set in combination with --simulate")
}
},
}

Ok(())
},
Commands::Simulate { network, path } => {
simulate_all_proposals(network.to_url()?, &path).await?;
Commands::Simulate {
network,
path,
profile_gas,
} => {
simulate_all_proposals(network.to_url()?, &path, profile_gas).await?;
Ok(())
},
Commands::WriteDefault { output_path } => {
Expand Down
78 changes: 55 additions & 23 deletions aptos-move/aptos-release-builder/src/simulate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ use aptos::{
common::types::PromptOptions, governance::compile_in_temp_dir, move_tool::FrameworkPackageArgs,
};
use aptos_crypto::HashValue;
use aptos_gas_profiling::GasProfiler;
use aptos_gas_schedule::{AptosGasParameters, FromOnChainGasSchedule};
use aptos_language_e2e_tests::account::AccountData;
use aptos_move_debugger::aptos_debugger::AptosDebugger;
Expand Down Expand Up @@ -510,6 +511,7 @@ pub async fn simulate_multistep_proposal(
remote_url: Url,
proposal_dir: &Path,
proposal_scripts: &[PathBuf],
profile_gas: bool,
) -> Result<()> {
println!("Simulating proposal at {}", proposal_dir.display());

Expand Down Expand Up @@ -626,28 +628,51 @@ pub async fn simulate_multistep_proposal(
let resolver = state_view.as_move_resolver();
let code_storage = state_view.as_aptos_code_storage(env);

let (_vm_status, vm_output) = vm.execute_user_transaction(
&resolver,
&code_storage,
&account
.account()
.transaction()
.script(Script::new(script_blob, vec![], vec![
TransactionArgument::U64(DUMMY_PROPOSAL_ID), // dummy proposal id, ignored by the patched function
]))
.chain_id(chain_id.chain_id())
.sequence_number(script_idx as u64)
.gas_unit_price(gas_params.vm.txn.min_price_per_gas_unit.into())
.max_gas_amount(100000)
.ttl(u64::MAX)
.sign(),
&log_context,
);
let txn = account
.account()
.transaction()
.script(Script::new(script_blob, vec![], vec![
TransactionArgument::U64(DUMMY_PROPOSAL_ID), // dummy proposal id, ignored by the patched function
]))
.chain_id(chain_id.chain_id())
.sequence_number(script_idx as u64)
.gas_unit_price(gas_params.vm.txn.min_price_per_gas_unit.into())
.max_gas_amount(100000)
.ttl(u64::MAX)
.sign();

let vm_output = if !profile_gas {
let (_vm_status, vm_output) =
vm.execute_user_transaction(&resolver, &code_storage, &txn, &log_context);
vm_output
} else {
let (_vm_status, vm_output, gas_profiler) = vm
.execute_user_transaction_with_modified_gas_meter(
&resolver,
&code_storage,
&txn,
&log_context,
GasProfiler::new_script,
)?;

let gas_log = gas_profiler.finish();
let report_path = proposal_dir
.join("gas-profiling")
.join(script_path.file_stem().unwrap());
gas_log.generate_html_report(&report_path, format!("Gas Report - {}", script_name))?;

println!(" Gas report saved to {}", report_path.display());

vm_output
};
// TODO: ensure all scripts trigger reconfiguration.

let txn_output = vm_output
.try_materialize_into_transaction_output(&resolver)
.context("failed to materialize transaction output")?;

println!(" Gas used: {}", txn_output.gas_used());

let txn_status = txn_output.status();
match txn_status {
TransactionStatus::Keep(ExecutionStatus::Success) => {
Expand Down Expand Up @@ -710,7 +735,11 @@ pub fn collect_proposals(root_dir: &Path) -> Result<Vec<(PathBuf, Vec<PathBuf>)>
Ok(result)
}

pub async fn simulate_all_proposals(remote_url: Url, output_dir: &Path) -> Result<()> {
pub async fn simulate_all_proposals(
remote_url: Url,
output_dir: &Path,
profile_gas: bool,
) -> Result<()> {
let proposals =
collect_proposals(output_dir).context("failed to collect proposals for simulation")?;

Expand All @@ -735,11 +764,14 @@ pub async fn simulate_all_proposals(remote_url: Url, output_dir: &Path) -> Resul
}

for (proposal_dir, proposal_scripts) in &proposals {
simulate_multistep_proposal(remote_url.clone(), proposal_dir, proposal_scripts)
.await
.with_context(|| {
format!("failed to simulate proposal at {}", proposal_dir.display())
})?;
simulate_multistep_proposal(
remote_url.clone(),
proposal_dir,
proposal_scripts,
profile_gas,
)
.await
.with_context(|| format!("failed to simulate proposal at {}", proposal_dir.display()))?;
}

println!("All proposals succeeded!");
Expand Down
Loading