Skip to content

Commit

Permalink
Merge pull request #27 from movemntdev/testnet
Browse files Browse the repository at this point in the history
Add faucet subcommand to movement-cli
  • Loading branch information
danMove authored Jul 12, 2023
2 parents e630040 + 6e1a3cb commit 83b5c13
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 24 deletions.
57 changes: 33 additions & 24 deletions vm/aptos-vm/subnet/movement/src/common/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,13 @@ use std::{
str::FromStr,
time::{Duration, Instant, SystemTime, UNIX_EPOCH},
};
use reqwest::Url;
use thiserror::Error;

pub const USER_AGENT: &str = concat!("movement-cli/", env!("CARGO_PKG_VERSION"));
const US_IN_SECS: u64 = 1_000_000;
const ACCEPTED_CLOCK_SKEW_US: u64 = 5 * US_IN_SECS;
pub const DEFAULT_EXPIRATION_SECS: u64 = 30;
pub const DEFAULT_EXPIRATION_SECS: u64 = 60;
pub const DEFAULT_PROFILE: &str = "default";

/// A common result to be returned to users
Expand Down Expand Up @@ -491,15 +492,15 @@ impl EncodingType {
let hex_string = String::from_utf8(data)?;
Key::from_encoded_string(hex_string.trim())
.map_err(|err| CliError::UnableToParse(name, err.to_string()))
},
}
EncodingType::Base64 => {
let string = String::from_utf8(data)?;
let bytes = base64::decode(string.trim())
.map_err(|err| CliError::UnableToParse(name, err.to_string()))?;
Key::try_from(bytes.as_slice()).map_err(|err| {
CliError::UnableToParse(name, format!("Failed to parse key {:?}", err))
})
},
}
}
}
}
Expand Down Expand Up @@ -653,7 +654,7 @@ impl ExtractPublicKey for PublicKeyInputOptions {
profile.profile_name(),
ConfigSearchMode::CurrentDirAndParents,
)?
.map(|p| p.public_key)
.map(|p| p.public_key)
{
Ok(public_key)
} else {
Expand Down Expand Up @@ -756,15 +757,15 @@ impl PrivateKeyInputOptions {
profile.profile_name(),
ConfigSearchMode::CurrentDirAndParents,
)?
.map(|p| (p.private_key, p.account))
.map(|p| (p.private_key, p.account))
{
match (maybe_address, maybe_config_address) {
(Some(address), _) => Ok((key, address)),
(_, Some(address)) => Ok((key, address)),
(None, None) => {
let address = account_address_from_public_key(&key.public_key());
Ok((key, address))
},
}
}
} else {
Err(CliError::CommandArgumentError(
Expand All @@ -785,7 +786,7 @@ impl PrivateKeyInputOptions {
profile.profile_name(),
ConfigSearchMode::CurrentDirAndParents,
)?
.map(|p| p.private_key)
.map(|p| p.private_key)
{
Ok(private_key)
} else {
Expand Down Expand Up @@ -892,7 +893,7 @@ impl RestOptions {
profile.profile_name(),
ConfigSearchMode::CurrentDirAndParents,
)?
.map(|p| p.rest_url)
.map(|p| p.rest_url)
{
reqwest::Url::parse(&url)
.map_err(|err| CliError::UnableToParse("Rest URL", err.to_string()))
Expand All @@ -908,6 +909,13 @@ impl RestOptions {
USER_AGENT,
))
}
pub fn client_raw(&self, url: Url) -> CliTypedResult<Client> {
Ok(Client::new_with_timeout_and_user_agent(
url,
Duration::from_secs(self.connection_timeout_secs),
USER_AGENT,
))
}
}

/// Options for compiling a move package dir
Expand Down Expand Up @@ -1117,6 +1125,7 @@ impl From<Transaction> for TransactionSummary {
TransactionSummary::from(&transaction)
}
}

impl From<&Transaction> for TransactionSummary {
fn from(transaction: &Transaction) -> Self {
match transaction {
Expand Down Expand Up @@ -1223,7 +1232,7 @@ impl FaucetOptions {
profile.profile_name(),
ConfigSearchMode::CurrentDirAndParents,
)?
.map(|profile| profile.faucet_url)
.map(|profile| profile.faucet_url)
{
reqwest::Url::parse(&url)
.map_err(|err| CliError::UnableToParse("config faucet_url", err.to_string()))
Expand Down Expand Up @@ -1284,7 +1293,7 @@ pub struct TransactionOptions {
///
/// This allows you to override the account address from the derived account address
/// in the event that the authentication key was rotated or for a resource account
#[clap(long, parse(try_from_str=crate::common::types::load_account_arg))]
#[clap(long, parse(try_from_str = crate::common::types::load_account_arg))]
pub(crate) sender_account: Option<AccountAddress>,

#[clap(flatten)]
Expand Down Expand Up @@ -1381,7 +1390,7 @@ impl TransactionOptions {
// Warn local user that clock is skewed behind the blockchain.
// There will always be a little lag from real time to blockchain time
if now_usecs < state.timestamp_usecs - ACCEPTED_CLOCK_SKEW_US {
eprintln!("Local clock is is skewed from blockchain clock. Clock is more than {} seconds behind the blockchain {}", ACCEPTED_CLOCK_SKEW_US, state.timestamp_usecs / US_IN_SECS );
eprintln!("Local clock is is skewed from blockchain clock. Clock is more than {} seconds behind the blockchain {}", ACCEPTED_CLOCK_SKEW_US, state.timestamp_usecs / US_IN_SECS);
}
let expiration_time_secs = now + self.gas_options.expiration_secs;

Expand All @@ -1391,7 +1400,7 @@ impl TransactionOptions {
let max_gas = if let Some(max_gas) = self.gas_options.max_gas {
// If the gas unit price was estimated ask, but otherwise you've chosen hwo much you want to spend
if ask_to_confirm_price {
let message = format!("Do you want to submit transaction for a maximum of {} Octas at a gas unit price of {} Octas?", max_gas * gas_unit_price, gas_unit_price);
let message = format!("Do you want to submit transaction for a maximum of {} Octas at a gas unit price of {} Octas?", max_gas * gas_unit_price, gas_unit_price);
prompt_yes_with_override(&message, self.prompt_options)?;
}
max_gas
Expand Down Expand Up @@ -1434,10 +1443,10 @@ impl TransactionOptions {
let upper_cost_bound = adjusted_max_gas * gas_unit_price;
let lower_cost_bound = gas_used * gas_unit_price;
let message = format!(
"Do you want to submit a transaction for a range of [{} - {}] Octas at a gas unit price of {} Octas?",
lower_cost_bound,
upper_cost_bound,
gas_unit_price);
"Do you want to submit a transaction for a range of [{} - {}] Octas at a gas unit price of {} Octas?",
lower_cost_bound,
upper_cost_bound,
gas_unit_price);
prompt_yes_with_override(&message, self.prompt_options)?;
adjusted_max_gas
};
Expand Down Expand Up @@ -1530,7 +1539,7 @@ impl TransactionOptions {
addr_short.as_str()
};
format!("0x{}-{}-{}", addr_truncated, module_id.name(), name)
},
}
};
let raw_file_name = format!("txn-{}-{}", hash, human_readable_name);

Expand Down Expand Up @@ -1567,10 +1576,10 @@ impl TransactionOptions {
"Execution & IO Gas flamegraph saved to {}",
graph_file_path.display()
);
},
}
None => {
println!("Skipped generating execution & IO flamegraph");
},
}
}

// Generate the storage fee flamegraph.
Expand All @@ -1592,10 +1601,10 @@ impl TransactionOptions {
"Storage fee flamegraph saved to {}",
graph_file_path.display()
);
},
}
None => {
println!("Skipped generating storage fee flamegraph");
},
}
}

println!();
Expand Down Expand Up @@ -1642,14 +1651,14 @@ pub struct OptionalPoolAddressArgs {
/// Address of the Staking pool
///
/// Defaults to the profile's `AccountAddress`
#[clap(long, parse(try_from_str=crate::common::types::load_account_arg))]
#[clap(long, parse(try_from_str = crate::common::types::load_account_arg))]
pub(crate) pool_address: Option<AccountAddress>,
}

#[derive(Parser)]
pub struct PoolAddressArgs {
/// Address of the Staking pool
#[clap(long, parse(try_from_str=crate::common::types::load_account_arg))]
#[clap(long, parse(try_from_str = crate::common::types::load_account_arg))]
pub(crate) pool_address: AccountAddress,
}

Expand Down Expand Up @@ -1739,6 +1748,6 @@ impl EntryFunctionArguments {
#[derive(Clone, Debug, Parser, Serialize)]
pub struct MultisigAccount {
/// The address of the multisig account to interact with.
#[clap(long, parse(try_from_str=crate::common::types::load_account_arg))]
#[clap(long, parse(try_from_str = crate::common::types::load_account_arg))]
pub(crate) multisig_address: AccountAddress,
}
32 changes: 32 additions & 0 deletions vm/aptos-vm/subnet/movement/src/common/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,7 @@ pub async fn chain_id(rest_client: &Client) -> CliTypedResult<ChainId> {
.into_inner();
Ok(ChainId::new(state.chain_id))
}

/// Error message for parsing a map
const PARSE_MAP_SYNTAX_MSG: &str = "Invalid syntax for map. Example: Name=Value,Name2=Value";

Expand Down Expand Up @@ -428,6 +429,37 @@ pub async fn fund_account(
}
}

/// Fund by public key (and possibly create it) from a faucet
pub async fn fund_pub_key(
faucet_url: Url,
pub_key: String,
) -> CliTypedResult<Vec<HashValue>> {
let url = format!(
"{}v1/mint?&pub_key={}",
faucet_url, pub_key
);
let response = reqwest::Client::new()
.post(url)
.body("{}")
.send()
.await
.map_err(|err| {
CliError::ApiError(format!("Failed to fund account with faucet: {:#}", err))
})?;
if response.status() == 200 {
let hashes: Vec<HashValue> = response
.json()
.await
.map_err(|err| CliError::UnexpectedError(err.to_string()))?;
Ok(hashes)
} else {
Err(CliError::ApiError(format!(
"Faucet issue: {}",
response.status()
)))
}
}

/// Wait for transactions, returning an error if any of them fail.
pub async fn wait_for_transactions(
client: &aptos_rest_client::Client,
Expand Down
41 changes: 41 additions & 0 deletions vm/aptos-vm/subnet/movement/src/faucet/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright © Aptos Foundation
// SPDX-License-Identifier: Apache-2.0

use crate::common::{
types::{CliCommand, CliTypedResult}
};
use async_trait::async_trait;
use crate::common::types::{FaucetOptions, ProfileOptions, RestOptions};
use crate::common::utils::{fund_pub_key, wait_for_transactions};
use clap::Parser;

#[derive(Debug, Parser)]
pub struct FaucetTool {
#[clap(long)]
pub_key: String,
#[clap(flatten)]
pub(crate) faucet_options: FaucetOptions,
#[clap(flatten)]
pub(crate) rest_options: RestOptions,
}

#[async_trait]
impl CliCommand<String> for FaucetTool {
fn command_name(&self) -> &'static str {
"Faucet"
}

async fn execute(self) -> CliTypedResult<String> {
let profile = ProfileOptions::default();
let hashes = fund_pub_key(
self.faucet_options.faucet_url(&profile)?,
self.pub_key.clone(),
).await?;
let client = self.rest_options.client_raw(self.faucet_options.faucet_url(&profile)?)?;
wait_for_transactions(&client, hashes).await?;
return Ok(format!(
"Added 1000_000_000 Octas to account {}", self.pub_key
));
}
}

3 changes: 3 additions & 0 deletions vm/aptos-vm/subnet/movement/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub mod stake;
#[cfg(any(test, feature = "fuzzing"))]
pub mod test;
pub mod update;
pub mod faucet;

use crate::common::{
types::{CliCommand, CliResult, CliTypedResult},
Expand Down Expand Up @@ -50,6 +51,7 @@ pub enum Tool {
#[clap(subcommand)]
Stake(stake::StakeTool),
Update(update::UpdateTool),
Faucet(faucet::FaucetTool),
}

impl Tool {
Expand All @@ -69,6 +71,7 @@ impl Tool {
Node(tool) => tool.execute().await,
Stake(tool) => tool.execute().await,
Update(tool) => tool.execute_serialized().await,
Faucet(tool) => tool.execute_serialized().await,
}
}
}
Expand Down

0 comments on commit 83b5c13

Please sign in to comment.