-
Notifications
You must be signed in to change notification settings - Fork 112
feat: add epoch change to node admin commands #1300
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
base: main
Are you sure you want to change the base?
Changes from 1 commit
21c256e
32e2bbc
d9f8180
63d8719
8dd4ce2
4109fbb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| use crate::common_args::MovementArgs; | ||
| use clap::Parser; | ||
| use mvt_aptos_l1_migration::set_epoch_duration; | ||
|
|
||
| #[derive(Debug, Parser, Clone)] | ||
| #[clap(rename_all = "kebab-case", about = "Rotates the key for a core resource account.")] | ||
| pub struct ChangeEpochDuration { | ||
| #[clap(flatten)] | ||
| pub movement_args: MovementArgs, | ||
| pub new_epoch_duration: Option<u64>, | ||
| } | ||
|
|
||
| impl ChangeEpochDuration { | ||
| pub async fn execute(&self) -> Result<(), anyhow::Error> { | ||
| // get the movement config from dot movement | ||
| let _dot_movement = self.movement_args.dot_movement()?; | ||
| let epoch_duration = self.new_epoch_duration.unwrap_or(7_200_000_000); // default 2hours, 7_200_000_000 micro second. | ||
| set_epoch_duration(epoch_duration).await?; | ||
| Ok(()) | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| use crate::admin::l1_migration::change_epoch_duration::ChangeEpochDuration; | ||
| use clap::Subcommand; | ||
|
|
||
| mod change_epoch_duration; | ||
|
|
||
| #[derive(Subcommand, Debug)] | ||
| #[clap(rename_all = "kebab-case", about = "Commands for rotating keys")] | ||
| pub enum L1Migration { | ||
| ChangeEpoch(ChangeEpochDuration), | ||
| } | ||
|
|
||
| impl L1Migration { | ||
| pub async fn execute(&self) -> Result<(), anyhow::Error> { | ||
| match self { | ||
| L1Migration::ChangeEpoch(change_epoch_duration) => { | ||
| change_epoch_duration.execute().await | ||
| } | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,21 +1,24 @@ | ||
| #![forbid(unsafe_code)] | ||
| use clap::*; | ||
| use movement_full_node::MovementFullNode; | ||
| use tracing_subscriber::EnvFilter; | ||
| // use tracing_subscriber::EnvFilter; | ||
|
|
||
| #[tokio::main] | ||
| async fn main() -> Result<(), anyhow::Error> { | ||
| // Initialize logger (for debugging) | ||
| aptos_logger::Logger::builder().level(aptos_logger::Level::Debug).build(); | ||
|
||
|
|
||
| // Initialize default tracing | ||
| tracing_subscriber::fmt() | ||
| .with_env_filter( | ||
| EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")), | ||
| ) | ||
| .init(); | ||
| // tracing_subscriber::fmt() | ||
| // .with_env_filter( | ||
| // EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")), | ||
| // ) | ||
| // .init(); | ||
|
|
||
| // Initialize telemetry if MOVEMENT_METRICS_ADDR is set | ||
| if std::env::var("MOVEMENT_METRICS_ADDR").is_ok() { | ||
| movement_tracing::ensure_telemetry_initialized(); | ||
| } | ||
| // // Initialize telemetry if MOVEMENT_METRICS_ADDR is set | ||
| // if std::env::var("MOVEMENT_METRICS_ADDR").is_ok() { | ||
| // movement_tracing::ensure_telemetry_initialized(); | ||
| // } | ||
|
|
||
| let suzuka_util = MovementFullNode::parse(); | ||
| let result = suzuka_util.execute().await; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| [package] | ||
| name = "mvt-aptos-l1-migration" | ||
| description = "Mvt Aptos L1 migration functions." | ||
| authors = { workspace = true } | ||
| edition = { workspace = true } | ||
| homepage = { workspace = true } | ||
| license = { workspace = true } | ||
| repository = { workspace = true } | ||
| version = { workspace = true } | ||
|
|
||
| [lib] | ||
| path = "src/lib.rs" | ||
|
|
||
| [dependencies] | ||
| aptos-crypto = { workspace = true } | ||
| serde = { workspace = true } | ||
| maptos-framework-release-util = { workspace = true } | ||
| movement-config = { workspace = true } | ||
| movement-client = { workspace = true } | ||
| once_cell = { workspace = true } | ||
| aptos-framework = { workspace = true } | ||
| tokio = { workspace = true } | ||
| anyhow = { workspace = true } | ||
| url = { workspace = true } | ||
| dot-movement = { workspace = true } | ||
| tempfile = { workspace = true } | ||
| bcs = { workspace = true } | ||
| aptos-framework-upgrade-gas-release = { workspace = true } | ||
| aptos-framework-set-feature-flags-release = { workspace = true } | ||
| aptos-framework-release-script-release = { workspace = true } | ||
| aptos-types = { workspace = true } | ||
| aptos-gas-schedule = { workspace = true } | ||
| aptos-sdk = { workspace = true } | ||
| aptos-release-builder = { workspace = true } | ||
| hex = { workspace = true } | ||
| tracing = { workspace = true } | ||
| tracing-subscriber = { workspace = true } | ||
| rand = { workspace = true } | ||
| ed25519-dalek = { workspace = true } | ||
|
|
||
| [build-dependencies] | ||
| maptos-framework-release-util = { workspace = true } | ||
| movement-config = { workspace = true } | ||
| movement-client = { workspace = true } | ||
| once_cell = { workspace = true } | ||
| aptos-framework = { workspace = true } | ||
| tokio = { workspace = true } | ||
| anyhow = { workspace = true } | ||
| url = { workspace = true } | ||
| dot-movement = { workspace = true } | ||
| tempfile = { workspace = true } | ||
| bcs = { workspace = true } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| script { | ||
| use aptos_framework::aptos_governance; | ||
| // use aptos_framework::signer; | ||
| use aptos_framework::block; | ||
|
|
||
| fun main(core_resources: &signer, new_interval_us: u64) { | ||
| let core_signer = aptos_governance::get_signer_testnet_only(core_resources, @0000000000000000000000000000000000000000000000000000000000000001); | ||
|
|
||
| block::update_epoch_interval_microsecs(&core_signer, new_interval_us); //2h 7_200_000_000 | ||
|
||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,100 @@ | ||
| use aptos_sdk::rest_client::Resource; | ||
| use aptos_sdk::types::transaction::TransactionArgument; | ||
| use aptos_sdk::{ | ||
| rest_client::Client, | ||
| transaction_builder::TransactionFactory, | ||
| types::{account_address::AccountAddress, transaction::TransactionPayload}, | ||
| }; | ||
| use aptos_types::{chain_id::ChainId, transaction::Script}; | ||
| use movement_client::types::{account_config::aptos_test_root_address, LocalAccount}; | ||
| use once_cell::sync::Lazy; | ||
| use std::str::FromStr; | ||
| use url::Url; | ||
|
|
||
| static MOVEMENT_CONFIG: Lazy<movement_config::Config> = Lazy::new(|| { | ||
| let dot_movement = dot_movement::DotMovement::try_from_env().unwrap(); | ||
| dot_movement.try_get_config_from_json::<movement_config::Config>().unwrap() | ||
| }); | ||
|
|
||
| static NODE_URL: Lazy<Url> = Lazy::new(|| { | ||
| let addr = MOVEMENT_CONFIG | ||
| .execution_config | ||
| .maptos_config | ||
| .client | ||
| .maptos_rest_connection_hostname | ||
| .clone(); | ||
| let port = MOVEMENT_CONFIG | ||
| .execution_config | ||
| .maptos_config | ||
| .client | ||
| .maptos_rest_connection_port | ||
| .clone(); | ||
| Url::from_str(&format!("http://{}:{}", addr, port)).unwrap() | ||
| }); | ||
|
|
||
| const GAS_UNIT_LIMIT: u64 = 100_000; | ||
|
|
||
| const CHANGE_EPOCH_MV: &[u8] = include_bytes!("../move/build/change_epoch.mv"); | ||
|
|
||
| pub async fn set_epoch_duration(epoch_duration: u64) -> Result<(), anyhow::Error> { | ||
| let rest_client = Client::new(NODE_URL.clone()); | ||
|
|
||
| // Core resources (aptos_test_root) address | ||
| let gov_root_address = aptos_test_root_address(); | ||
| tracing::info!("aptos_test_root_address() (constant): {}", gov_root_address); | ||
| // Load *core_resources* private key (from your config/genesis) | ||
| let raw_private_key = MOVEMENT_CONFIG | ||
| .execution_config | ||
| .maptos_config | ||
| .chain | ||
| .maptos_private_key_signer_identifier | ||
| .try_raw_private_key()?; | ||
| let gov_priv = | ||
| movement_client::crypto::ed25519::Ed25519PrivateKey::try_from(raw_private_key.as_slice())?; | ||
|
|
||
| // Build signer by *forcing* core_resources address + current on-chain seq | ||
| let gov_root_account = { | ||
| let onchain = rest_client.get_account(gov_root_address).await?.into_inner(); | ||
| LocalAccount::new(gov_root_address, gov_priv.clone(), onchain.sequence_number) | ||
| }; | ||
| tracing::info!("Signer (gov_root_account) address: {}", gov_root_account.address()); | ||
|
|
||
| let ledger_info = rest_client.get_ledger_information().await?.into_inner(); | ||
| let factory = TransactionFactory::new(ChainId::new(ledger_info.chain_id)) | ||
| .with_gas_unit_price(100) | ||
| .with_max_gas_amount(GAS_UNIT_LIMIT); | ||
|
|
||
| let payload = TransactionPayload::Script(Script::new( | ||
| CHANGE_EPOCH_MV.to_vec(), | ||
| vec![], // no type args | ||
| vec![TransactionArgument::U64(epoch_duration)], // no value args; 7_200_000_000 is hardcoded inside | ||
|
||
| )); | ||
|
|
||
| // Sign & submit | ||
| let signed_txn = gov_root_account.sign_with_transaction_builder(factory.payload(payload)); | ||
| let res = rest_client.submit_and_wait(&signed_txn).await?.into_inner(); | ||
|
|
||
| // Verify the epoch has been changed | ||
| let block_res: Resource = rest_client | ||
| .get_account_resource(AccountAddress::from_hex_literal("0x1")?, "0x1::block::BlockResource") | ||
| .await? | ||
| .into_inner() | ||
| .unwrap(); | ||
|
|
||
| let interval_str = block_res.data["epoch_interval"] | ||
| .as_str() | ||
| .ok_or_else(|| anyhow::anyhow!("epoch_interval missing or not a string"))?; | ||
|
|
||
| let onchain_duration: u64 = interval_str.parse()?; | ||
|
|
||
| assert!( | ||
| onchain_duration == epoch_duration, | ||
| "Epoch duration not updated, epoch after update is:{onchain_duration}" | ||
| ); | ||
|
|
||
| tracing::info!( | ||
| "✅ Executed change epoch script, new epoch duration:{onchain_duration}, with Tx hash: {}", | ||
| res.transaction_info().unwrap().hash | ||
| ); | ||
| Ok(()) | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| mod change_epoch; | ||
|
|
||
| pub use change_epoch::set_epoch_duration; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit const this val
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done