diff --git a/ipc/cli/src/commands/checkpoint/list_checkpoints.rs b/ipc/cli/src/commands/checkpoint/list_checkpoints.rs index bf3eaca9..3ea5c95d 100644 --- a/ipc/cli/src/commands/checkpoint/list_checkpoints.rs +++ b/ipc/cli/src/commands/checkpoint/list_checkpoints.rs @@ -8,8 +8,6 @@ use async_trait::async_trait; use clap::Args; use fvm_shared::clock::ChainEpoch; -use crate::commands::get_ipc_agent_url; -use crate::sdk::IpcAgentClient; use crate::{CommandLineHandler, GlobalArguments}; /// The command to list checkpoints committed in a subnet actor. @@ -19,34 +17,15 @@ pub(crate) struct ListBottomUpCheckpoints; impl CommandLineHandler for ListBottomUpCheckpoints { type Arguments = ListBottomUpCheckpointsArgs; - async fn handle(global: &GlobalArguments, arguments: &Self::Arguments) -> anyhow::Result<()> { + async fn handle(_global: &GlobalArguments, arguments: &Self::Arguments) -> anyhow::Result<()> { log::debug!("list checkpoints with args: {:?}", arguments); - - let url = get_ipc_agent_url(&arguments.ipc_agent_url, global)?; - let client = IpcAgentClient::default_from_url(url); - let checkpoints = client - .list_bottom_up_checkpoints(&arguments.subnet, arguments.from_epoch, arguments.to_epoch) - .await?; - - for c in checkpoints.iter() { - log::info!( - "epoch {} - prev_check={}, cross_msgs={}, child_checks={}", - c["epoch"], - c["prev_check"], - c["cross_msgs"], - c["children"] - ); - } - - Ok(()) + todo!() } } #[derive(Debug, Args)] #[command(about = "List bottom-up checkpoints")] pub(crate) struct ListBottomUpCheckpointsArgs { - #[arg(long, short, help = "The JSON RPC server url for ipc agent")] - pub ipc_agent_url: Option, #[arg(long, short, help = "The subnet id of the checkpointing subnet")] pub subnet: String, #[arg(long, short, help = "Include checkpoints from this epoch")] diff --git a/ipc/cli/src/commands/checkpoint/topdown_executed.rs b/ipc/cli/src/commands/checkpoint/topdown_executed.rs index 1d395f53..503275ea 100644 --- a/ipc/cli/src/commands/checkpoint/topdown_executed.rs +++ b/ipc/cli/src/commands/checkpoint/topdown_executed.rs @@ -2,14 +2,13 @@ // SPDX-License-Identifier: MIT //! Last top-down checkpoint executed in subnet -use std::fmt::Debug; +use std::{fmt::Debug, str::FromStr}; use async_trait::async_trait; use clap::Args; +use ipc_sdk::subnet_id::SubnetID; -use crate::commands::get_ipc_agent_url; -use crate::sdk::IpcAgentClient; -use crate::{CommandLineHandler, GlobalArguments}; +use crate::{get_ipc_provider, require_fil_addr_from_str, CommandLineHandler, GlobalArguments}; /// The command to get the latest epoch executed for a top-down checkpoint pub(crate) struct LastTopDownExec; @@ -21,11 +20,20 @@ impl CommandLineHandler for LastTopDownExec { async fn handle(global: &GlobalArguments, arguments: &Self::Arguments) -> anyhow::Result<()> { log::debug!("last topdown exec with args: {:?}", arguments); - let url = get_ipc_agent_url(&arguments.ipc_agent_url, global)?; - let client = IpcAgentClient::default_from_url(url); - let epoch = client.last_top_down_executed(&arguments.subnet).await?; + let provider = get_ipc_provider(global)?; + let subnet = SubnetID::from_str(&arguments.subnet)?; - log::info!("Last top-down checkpoint executed in epoch: {epoch:}"); + let gateway_addr = match &arguments.gateway_address { + Some(address) => Some(require_fil_addr_from_str(address)?), + None => None, + }; + + println!( + "epoch: {:?}", + provider + .last_topdown_executed(&subnet, gateway_addr) + .await? + ); Ok(()) } @@ -34,8 +42,8 @@ impl CommandLineHandler for LastTopDownExec { #[derive(Debug, Args)] #[command(about = "Epoch of the last top-down checkpoint executed")] pub(crate) struct LastTopDownExecArgs { - #[arg(long, short, help = "The JSON RPC server url for ipc agent")] - pub ipc_agent_url: Option, + #[arg(long, short, help = "The gateway address to query subnets")] + pub gateway_address: Option, #[arg(long, short, help = "The subnet id of the checkpointing subnet")] pub subnet: String, } diff --git a/ipc/cli/src/commands/crossmsg/fund.rs b/ipc/cli/src/commands/crossmsg/fund.rs index 57eee65f..a2df865d 100644 --- a/ipc/cli/src/commands/crossmsg/fund.rs +++ b/ipc/cli/src/commands/crossmsg/fund.rs @@ -4,11 +4,14 @@ use async_trait::async_trait; use clap::Args; -use std::fmt::Debug; +use fvm_shared::address::Address; +use ipc_sdk::subnet_id::SubnetID; +use std::{fmt::Debug, str::FromStr}; -use crate::commands::get_ipc_agent_url; -use crate::sdk::IpcAgentClient; -use crate::{CommandLineHandler, GlobalArguments}; +use crate::{ + f64_to_token_amount, get_ipc_provider, require_fil_addr_from_str, CommandLineHandler, + GlobalArguments, +}; /// The command to send funds to a subnet from parent pub(crate) struct Fund; @@ -20,18 +23,33 @@ impl CommandLineHandler for Fund { async fn handle(global: &GlobalArguments, arguments: &Self::Arguments) -> anyhow::Result<()> { log::debug!("fund operation with args: {:?}", arguments); - let url = get_ipc_agent_url(&arguments.ipc_agent_url, global)?; - let client = IpcAgentClient::default_from_url(url); - let epoch = client - .fund( - &arguments.subnet, - arguments.from.clone(), - arguments.to.clone(), - arguments.amount, - ) - .await?; + let mut provider = get_ipc_provider(global)?; + let subnet = SubnetID::from_str(&arguments.subnet)?; + let from = match &arguments.from { + Some(address) => Some(Address::from_str(address)?), + None => None, + }; + let to = match &arguments.to { + Some(address) => Some(require_fil_addr_from_str(address)?), + None => None, + }; + let gateway_addr = match &arguments.gateway_address { + Some(address) => Some(Address::from_str(address)?), + None => None, + }; - log::info!("funded subnet: {:} at epoch: {epoch:}", arguments.subnet); + println!( + "fund performed in epoch: {:?}", + provider + .fund( + subnet, + gateway_addr, + from, + to, + f64_to_token_amount(arguments.amount)?, + ) + .await?, + ); Ok(()) } @@ -40,8 +58,8 @@ impl CommandLineHandler for Fund { #[derive(Debug, Args)] #[command(about = "Send funds from a parent to a child subnet")] pub(crate) struct FundArgs { - #[arg(long, short, help = "The JSON RPC server url for ipc agent")] - pub ipc_agent_url: Option, + #[arg(long, short, help = "The gateway address of the subnet")] + pub gateway_address: Option, #[arg(long, short, help = "The address to send funds from")] pub from: Option, #[arg( diff --git a/ipc/cli/src/commands/crossmsg/propagate.rs b/ipc/cli/src/commands/crossmsg/propagate.rs index b4da4ee8..4cfd0fda 100644 --- a/ipc/cli/src/commands/crossmsg/propagate.rs +++ b/ipc/cli/src/commands/crossmsg/propagate.rs @@ -3,15 +3,10 @@ //! Propagate cli command handler. use async_trait::async_trait; -use base64::Engine; use clap::Args; use std::fmt::Debug; -use crate::commands::get_ipc_agent_url; -use crate::config::json_rpc_methods; -use crate::server::propagate::PropagateParams; use crate::{CommandLineHandler, GlobalArguments}; -use ipc_provider::jsonrpc::{JsonRpcClient, JsonRpcClientImpl}; /// The command to propagate a message in the postbox. pub(crate) struct Propagate; @@ -20,26 +15,8 @@ pub(crate) struct Propagate; impl CommandLineHandler for Propagate { type Arguments = PropagateArgs; - async fn handle(global: &GlobalArguments, arguments: &Self::Arguments) -> anyhow::Result<()> { - log::debug!("propagate operation with args: {:?}", arguments); - - let url = get_ipc_agent_url(&arguments.ipc_agent_url, global)?; - let json_rpc_client = JsonRpcClientImpl::new(url, None); - - let postbox_msg_key = - base64::engine::general_purpose::STANDARD.decode(&arguments.postbox_msg_key)?; - let params = PropagateParams { - subnet: arguments.subnet.clone(), - from: arguments.from.clone(), - postbox_msg_key, - }; - json_rpc_client - .request::<()>(json_rpc_methods::PROPAGATE, serde_json::to_value(params)?) - .await?; - - log::info!("propagated subnet: {:}", arguments.subnet); - - Ok(()) + async fn handle(_global: &GlobalArguments, _arguments: &Self::Arguments) -> anyhow::Result<()> { + todo!() } } diff --git a/ipc/cli/src/commands/crossmsg/release.rs b/ipc/cli/src/commands/crossmsg/release.rs index db093c97..54836c78 100644 --- a/ipc/cli/src/commands/crossmsg/release.rs +++ b/ipc/cli/src/commands/crossmsg/release.rs @@ -4,11 +4,14 @@ use async_trait::async_trait; use clap::Args; -use std::fmt::Debug; +use fvm_shared::address::Address; +use ipc_sdk::subnet_id::SubnetID; +use std::{fmt::Debug, str::FromStr}; -use crate::commands::get_ipc_agent_url; -use crate::sdk::IpcAgentClient; -use crate::{CommandLineHandler, GlobalArguments}; +use crate::{ + f64_to_token_amount, get_ipc_provider, require_fil_addr_from_str, CommandLineHandler, + GlobalArguments, +}; /// The command to release funds from a child to a parent pub(crate) struct Release; @@ -20,18 +23,33 @@ impl CommandLineHandler for Release { async fn handle(global: &GlobalArguments, arguments: &Self::Arguments) -> anyhow::Result<()> { log::debug!("release operation with args: {:?}", arguments); - let url = get_ipc_agent_url(&arguments.ipc_agent_url, global)?; - let client = IpcAgentClient::default_from_url(url); - let epoch = client - .release( - &arguments.subnet, - arguments.from.clone(), - arguments.to.clone(), - arguments.amount, - ) - .await?; + let mut provider = get_ipc_provider(global)?; + let subnet = SubnetID::from_str(&arguments.subnet)?; + let from = match &arguments.from { + Some(address) => Some(Address::from_str(address)?), + None => None, + }; + let to = match &arguments.to { + Some(address) => Some(require_fil_addr_from_str(address)?), + None => None, + }; + let gateway_addr = match &arguments.gateway_address { + Some(address) => Some(require_fil_addr_from_str(address)?), + None => None, + }; - log::info!("released subnet: {:} at epoch {epoch:}", arguments.subnet); + println!( + "release performed in epoch: {:?}", + provider + .release( + subnet, + gateway_addr, + from, + to, + f64_to_token_amount(arguments.amount)?, + ) + .await?, + ); Ok(()) } @@ -40,8 +58,8 @@ impl CommandLineHandler for Release { #[derive(Debug, Args)] #[command(about = "Release operation in the gateway actor")] pub(crate) struct ReleaseArgs { - #[arg(long, short, help = "The JSON RPC server url for ipc agent")] - pub ipc_agent_url: Option, + #[arg(long, short, help = "The gateway address of the subnet")] + pub gateway_address: Option, #[arg(long, short, help = "The address that releases funds")] pub from: Option, #[arg( diff --git a/ipc/cli/src/commands/mod.rs b/ipc/cli/src/commands/mod.rs index 99286501..8861f01f 100644 --- a/ipc/cli/src/commands/mod.rs +++ b/ipc/cli/src/commands/mod.rs @@ -2,28 +2,29 @@ // SPDX-License-Identifier: MIT //! This mod contains the different command line implementations. -// mod checkpoint; +mod checkpoint; mod config; -// mod crossmsg; +mod crossmsg; // mod daemon; mod subnet; mod util; mod wallet; -// use crate::commands::checkpoint::CheckpointCommandsArgs; -// use crate::commands::crossmsg::CrossMsgsCommandsArgs; +use crate::commands::checkpoint::CheckpointCommandsArgs; +use crate::commands::crossmsg::CrossMsgsCommandsArgs; // use crate::commands::daemon::{LaunchDaemon, LaunchDaemonArgs}; use crate::commands::util::UtilCommandsArgs; -// use crate::server::{new_evm_keystore_from_path, new_keystore_from_path}; use crate::GlobalArguments; use anyhow::{Context, Result}; use clap::{Command, CommandFactory, Parser, Subcommand}; use clap_complete::{generate, Generator, Shell}; use fvm_shared::econ::TokenAmount; +use ipc_provider::manager::evm::ethers_address_to_fil_address; use std::fmt::Debug; use std::io; +use std::str::FromStr; use crate::commands::config::ConfigCommandsArgs; use crate::commands::wallet::WalletCommandsArgs; @@ -42,8 +43,8 @@ enum Commands { Config(ConfigCommandsArgs), Subnet(SubnetCommandsArgs), Wallet(WalletCommandsArgs), - // CrossMsg(CrossMsgsCommandsArgs), - // Checkpoint(CheckpointCommandsArgs), + CrossMsg(CrossMsgsCommandsArgs), + Checkpoint(CheckpointCommandsArgs), Util(UtilCommandsArgs), } @@ -107,9 +108,9 @@ pub async fn cli() -> anyhow::Result<()> { // Commands::Daemon(args) => LaunchDaemon::handle(global, args).await, Commands::Config(args) => args.handle(global).await, Commands::Subnet(args) => args.handle(global).await, - // Commands::CrossMsg(args) => args.handle(global).await, + Commands::CrossMsg(args) => args.handle(global).await, Commands::Wallet(args) => args.handle(global).await, - // Commands::Checkpoint(args) => args.handle(global).await, + Commands::Checkpoint(args) => args.handle(global).await, Commands::Util(args) => args.handle(global).await, }; @@ -134,12 +135,19 @@ pub(crate) fn f64_to_token_amount(f: f64) -> anyhow::Result { Ok(TokenAmount::from_nano(nano as u128)) } -// pub(crate) fn get_evm_keystore(path: &Option) -> Result> { -// match path { -// Some(p) => new_evm_keystore_from_path(p), -// None => new_evm_keystore_from_path(&default_repo_path()), -// } -// } +/// Receives a f/eth-address as an input and returns the corresponding +/// filecoin or delegated address, respectively +pub(crate) fn require_fil_addr_from_str(s: &str) -> anyhow::Result { + let addr = match fvm_shared::address::Address::from_str(s) { + Err(_) => { + // see if it is an eth address + let addr = ethers::types::Address::from_str(s)?; + ethers_address_to_fil_address(&addr)? + } + Ok(addr) => addr, + }; + Ok(addr) +} #[cfg(test)] mod tests { diff --git a/ipc/cli/src/commands/subnet/list_subnets.rs b/ipc/cli/src/commands/subnet/list_subnets.rs index f0b1a75d..ce23b557 100644 --- a/ipc/cli/src/commands/subnet/list_subnets.rs +++ b/ipc/cli/src/commands/subnet/list_subnets.rs @@ -4,12 +4,12 @@ use async_trait::async_trait; use clap::Args; -use fvm_shared::{address::Address, econ::TokenAmount}; +use fvm_shared::econ::TokenAmount; use ipc_sdk::subnet_id::SubnetID; use std::fmt::Debug; use std::str::FromStr; -use crate::{get_ipc_provider, CommandLineHandler, GlobalArguments}; +use crate::{get_ipc_provider, require_fil_addr_from_str, CommandLineHandler, GlobalArguments}; /// The command to create a new subnet actor. pub(crate) struct ListSubnets; @@ -25,7 +25,7 @@ impl CommandLineHandler for ListSubnets { let subnet = SubnetID::from_str(&arguments.subnet)?; let gateway_addr = match &arguments.gateway_address { - Some(address) => Some(Address::from_str(address)?), + Some(address) => Some(require_fil_addr_from_str(address)?), None => None, }; diff --git a/ipc/cli/src/commands/subnet/list_validators.rs b/ipc/cli/src/commands/subnet/list_validators.rs index e32e3d21..b0bf8138 100644 --- a/ipc/cli/src/commands/subnet/list_validators.rs +++ b/ipc/cli/src/commands/subnet/list_validators.rs @@ -4,11 +4,10 @@ use async_trait::async_trait; use clap::Args; -use fvm_shared::address::Address; use ipc_sdk::subnet_id::SubnetID; use std::{fmt::Debug, str::FromStr}; -use crate::{get_ipc_provider, CommandLineHandler, GlobalArguments}; +use crate::{get_ipc_provider, require_fil_addr_from_str, CommandLineHandler, GlobalArguments}; /// The command to create a new subnet actor. pub(crate) struct ListValidators; @@ -24,7 +23,7 @@ impl CommandLineHandler for ListValidators { let subnet = SubnetID::from_str(&arguments.subnet)?; let gateway_addr = match &arguments.gateway_address { - Some(address) => Some(Address::from_str(address)?), + Some(address) => Some(require_fil_addr_from_str(address)?), None => None, }; diff --git a/ipc/cli/src/commands/subnet/rpc.rs b/ipc/cli/src/commands/subnet/rpc.rs index 9d41f519..b6bbc25f 100644 --- a/ipc/cli/src/commands/subnet/rpc.rs +++ b/ipc/cli/src/commands/subnet/rpc.rs @@ -28,7 +28,7 @@ impl CommandLineHandler for RPCSubnet { }; println!("rpc: {:?}", conn.subnet().rpc_http().to_string()); - println!("chainID: {:?}", subnet.chain_id()); + println!("chainID: {:?}", conn.manager().get_chain_id().await?); Ok(()) } } diff --git a/ipc/cli/src/commands/subnet/send_value.rs b/ipc/cli/src/commands/subnet/send_value.rs index 8f96d48d..fa0869b1 100644 --- a/ipc/cli/src/commands/subnet/send_value.rs +++ b/ipc/cli/src/commands/subnet/send_value.rs @@ -5,11 +5,13 @@ use async_trait::async_trait; use clap::Args; use fvm_shared::address::Address; -use ipc_provider::manager::evm::ethers_address_to_fil_address; use ipc_sdk::subnet_id::SubnetID; use std::{fmt::Debug, str::FromStr}; -use crate::{f64_to_token_amount, get_ipc_provider, CommandLineHandler, GlobalArguments}; +use crate::{ + f64_to_token_amount, get_ipc_provider, require_fil_addr_from_str, CommandLineHandler, + GlobalArguments, +}; pub(crate) struct SendValue; @@ -27,20 +29,13 @@ impl CommandLineHandler for SendValue { None => None, }; - // try to get the `to` as an FVM address and an Eth - // address. We should include a wrapper type to make - // this easier through the whole code base. - let to = match Address::from_str(&arguments.to) { - Err(_) => { - // see if it is an eth address - let addr = ethers::types::Address::from_str(&arguments.to)?; - ethers_address_to_fil_address(&addr)? - } - Ok(addr) => addr, - }; - provider - .send_value(&subnet, from, to, f64_to_token_amount(arguments.amount)?) + .send_value( + &subnet, + from, + require_fil_addr_from_str(&arguments.to)?, + f64_to_token_amount(arguments.amount)?, + ) .await } } diff --git a/ipc/provider/src/lib.rs b/ipc/provider/src/lib.rs index fb6bcce7..f1dbf4e1 100644 --- a/ipc/provider/src/lib.rs +++ b/ipc/provider/src/lib.rs @@ -347,12 +347,14 @@ impl IpcProvider { conn.manager().list_child_subnets(gateway_addr).await } + /// Funds an account in a child subnet, if `to` is `None`, the self account + /// is funded. pub async fn fund( &mut self, subnet: SubnetID, gateway_addr: Option
, from: Option
, - to: Address, + to: Option
, amount: TokenAmount, ) -> anyhow::Result { let parent = subnet.parent().ok_or_else(|| anyhow!("no parent found"))?; @@ -371,16 +373,18 @@ impl IpcProvider { }; conn.manager() - .fund(subnet, gateway_addr, sender, to, amount) + .fund(subnet, gateway_addr, sender, to.unwrap_or(sender), amount) .await } + /// Release to an account in a child subnet, if `to` is `None`, the self account + /// is funded. pub async fn release( &mut self, subnet: SubnetID, gateway_addr: Option
, from: Option
, - to: Address, + to: Option
, amount: TokenAmount, ) -> anyhow::Result { let conn = match self.connection(&subnet) { @@ -398,7 +402,7 @@ impl IpcProvider { }; conn.manager() - .release(subnet, gateway_addr, sender, to, amount) + .release(subnet, gateway_addr, sender, to.unwrap_or(sender), amount) .await } @@ -620,6 +624,18 @@ impl IpcProvider { conn.manager().get_block_hash(height).await } + + pub async fn get_chain_id(&self, subnet: &SubnetID) -> anyhow::Result { + let conn = match self.connection(subnet) { + None => return Err(anyhow!("target subnet not found")), + Some(conn) => conn, + }; + + let subnet_config = conn.subnet(); + self.check_subnet(subnet_config)?; + + conn.manager().get_chain_id().await + } } /// Lotus JSON keytype format diff --git a/ipc/provider/src/manager/evm/manager.rs b/ipc/provider/src/manager/evm/manager.rs index 44df6cf9..017990dd 100644 --- a/ipc/provider/src/manager/evm/manager.rs +++ b/ipc/provider/src/manager/evm/manager.rs @@ -587,6 +587,15 @@ impl SubnetManager for EthSubnetManager { genesis_epoch, }) } + + async fn get_chain_id(&self) -> Result { + Ok(self + .ipc_contract_info + .provider + .get_chainid() + .await? + .to_string()) + } } #[async_trait] diff --git a/ipc/provider/src/manager/fevm.rs b/ipc/provider/src/manager/fevm.rs index 31c34591..159cfbf2 100644 --- a/ipc/provider/src/manager/fevm.rs +++ b/ipc/provider/src/manager/fevm.rs @@ -230,6 +230,10 @@ impl SubnetManager for FevmSubnetManager { .get_validator_set(subnet_id, gateway, epoch) .await } + + async fn get_chain_id(&self) -> anyhow::Result { + self.evm_subnet_manager.get_chain_id().await + } } #[async_trait] diff --git a/ipc/provider/src/manager/fvm/mod.rs b/ipc/provider/src/manager/fvm/mod.rs index bfc12c3a..9ac87d1d 100644 --- a/ipc/provider/src/manager/fvm/mod.rs +++ b/ipc/provider/src/manager/fvm/mod.rs @@ -395,6 +395,10 @@ impl SubnetManager for LotusSubnetManager { genesis_epoch, }) } + + async fn get_chain_id(&self) -> Result { + unimplemented!() + } } impl LotusSubnetManager { diff --git a/ipc/provider/src/manager/subnet.rs b/ipc/provider/src/manager/subnet.rs index c5c2162d..ac463636 100644 --- a/ipc/provider/src/manager/subnet.rs +++ b/ipc/provider/src/manager/subnet.rs @@ -129,6 +129,11 @@ pub trait SubnetManager: Send + Sync + TopDownCheckpointQuery { gateway: Option
, epoch: Option, ) -> Result; + + /// Get chainID for the network. + /// Returning as a `String` because the maximum value for an EVM + /// networks is a `U256` that wouldn't fit in an integer type. + async fn get_chain_id(&self) -> Result; } /// Trait to interact with a subnet to query the necessary information for top down checkpoint.