Skip to content

Commit

Permalink
[release builder] gov proposal simulation: show gas usage + add gas p…
Browse files Browse the repository at this point in the history
…rofiling support
  • Loading branch information
vgao1996 committed Nov 18, 2024
1 parent 2e349cf commit b67c5f3
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 29 deletions.
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)]
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

0 comments on commit b67c5f3

Please sign in to comment.