diff --git a/src/cli/init.rs b/src/cli/init.rs index cbcdb77..e2f0b0d 100644 --- a/src/cli/init.rs +++ b/src/cli/init.rs @@ -18,8 +18,8 @@ use ckb_sdk::{ TransactionBuilderConfiguration, }, types::{ - Address as CkbAddress, AddressPayload as CkbAddressPayload, NetworkInfo, ScriptGroup, - TransactionWithScriptGroups, + Address as CkbAddress, AddressPayload as CkbAddressPayload, NetworkInfo, NetworkType, + ScriptGroup, TransactionWithScriptGroups, }, SECP256K1, }; @@ -75,9 +75,8 @@ pub struct Args { #[arg(long, value_parser = value_parsers::OutPointValueParser)] pub(crate) spv_contract_out_point: OutPoint, - /// The owner of Bitcoin SPV cells. - #[arg(long, value_parser = value_parsers::AddressValueParser)] - pub(crate) spv_owner: CkbAddress, + #[clap(flatten)] + pub(crate) spv_owner: super::SpvOwner, /// Disable the on-chain difficulty check. /// @@ -110,9 +109,14 @@ impl Args { pub fn execute(&self) -> Result<()> { log::info!("Try to initialize a Bitcoin SPV instance on CKB"); + if self.disable_difficulty_check && self.ckb.network == NetworkType::Mainnet { + let msg = "For safety, the option `self.disable_difficulty_check` \ + are not allowed on the mainnet"; + return Err(Error::other(msg)); + } + self.check_inputs()?; log::info!("The bitcoin start height is {}", self.bitcoin_start_height); - self.check_remotes()?; let btc_start_header = self .bitcoin @@ -228,7 +232,7 @@ impl Args { Error::other(msg) })?; let spv_cell = CellOutput::new_builder() - .lock((&self.spv_owner).into()) + .lock(self.spv_owner.lock_script()) .type_(Some(spv_type_script).pack()) .build(); let spv_info = spv_cell @@ -389,36 +393,7 @@ impl Args { } fn check_inputs(&self) -> Result<()> { - if self.spv_owner.network() != self.ckb.network { - let msg = "The input addresses and the selected network are not matched"; - return Err(Error::cli(msg)); - } - - if self.spv_clients_count < 3 { - let msg = format!( - "The Bitcoint SPV clients count should be 3 at least but got {}", - self.spv_clients_count - ); - return Err(Error::cli(msg)); - } - - if self.bitcoin_start_height % DIFFCHANGE_INTERVAL != 0 { - let msg = format!( - "invalid Bitcoint start height, expected multiples of \ - {DIFFCHANGE_INTERVAL} but got {}", - self.bitcoin_start_height - ); - return Err(Error::cli(msg)); - } - - Ok(()) - } - - fn check_remotes(&self) -> Result<()> { - if self.spv_owner.network() != self.ckb.network { - let msg = "The input addresses and the selected network are not matched"; - return Err(Error::cli(msg)); - } + self.spv_owner.check_network(self.ckb.network)?; if self.spv_clients_count < 3 { let msg = format!( diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 96f3d80..b3f506a 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -1,7 +1,10 @@ //! The command line argument. -use ckb_sdk::{rpc::CkbRpcClient, types::NetworkType}; -use ckb_types::core::FeeRate; +use ckb_sdk::{ + rpc::CkbRpcClient, + types::{Address, NetworkType}, +}; +use ckb_types::{core::FeeRate, packed::Script}; use clap::{Args, Parser, Subcommand}; use clap_verbosity_flag::{InfoLevel, Verbosity}; use url::Url; @@ -9,7 +12,7 @@ use url::Url; use crate::{ components::BitcoinClient, prelude::*, - result::Result, + result::{Error, Result}, utilities::{value_parsers, Key256Bits}, }; @@ -96,6 +99,55 @@ pub struct CkbRoArgs { pub(crate) network: NetworkType, } +#[derive(Parser)] +pub struct SpvOwner { + /// The owner of Bitcoin SPV cells. + /// + /// ### Warnings + /// + /// The owner should be an address which uses a ACP-like script. + /// + /// Current standard ACP lock isn't satisfied, because it's has the + /// following limits: + /// + /// > if 2 input cells are using the same type script, or are both missing + /// type scripts, the lock returns with an error state. + /// + /// > if 2 output cells are using the same type script, or are both missing + /// type scripts, the lock returns with an error state. + /// + /// ### References + /// + /// - [Anyone-Can-Pay Lock (a.k.a ACP)](https://github.com/nervosnetwork/rfcs/blob/198fc90ab7582953ed85a6655e88e51346857475/rfcs/0026-anyone-can-pay/0026-anyone-can-pay.md) + #[arg(long, value_parser = value_parsers::AddressValueParser)] + pub(crate) spv_owner: Address, +} + +#[derive(Parser)] +pub struct SpvOwnerOpt { + /// The owner of Bitcoin SPV cells. + /// If no owner is provided, the previous owner will be kept. + /// + /// ### Warnings + /// + /// The owner should be an address which uses a ACP-like script. + /// + /// Current standard ACP lock isn't satisfied, because it's has the + /// following limits: + /// + /// > if 2 input cells are using the same type script, or are both missing + /// type scripts, the lock returns with an error state. + /// + /// > if 2 output cells are using the same type script, or are both missing + /// type scripts, the lock returns with an error state. + /// + /// ### References + /// + /// - [Anyone-Can-Pay Lock (a.k.a ACP)](https://github.com/nervosnetwork/rfcs/blob/198fc90ab7582953ed85a6655e88e51346857475/rfcs/0026-anyone-can-pay/0026-anyone-can-pay.md) + #[arg(long, value_parser = value_parsers::AddressValueParser)] + pub(crate) spv_owner: Option
, +} + #[derive(Args)] #[group(multiple = false)] pub struct FeeRateArgs { @@ -110,16 +162,20 @@ pub struct FeeRateArgs { /// [Experimental] Enable dynamic fee rate for CKB transactions. /// - /// The actual fee rate will be the `median` fee rate which is fetched through the CKB RPC method `get_fee_rate_statistics`. + /// The actual fee rate will be the `median` fee rate which is fetched + /// through the CKB RPC method `get_fee_rate_statistics`. /// /// For security, a hard limit is required. - /// When the returned dynamic fee rate is larger than the hard limit, the hard limit will be used. + /// When the returned dynamic fee rate is larger than the hard limit, the + /// hard limit will be used. /// /// ### Warning /// /// Users have to make sure the remote CKB node they used are trustsed. /// - /// Ref: