Skip to content

Commit

Permalink
feat: support dynamic CKB fee rate
Browse files Browse the repository at this point in the history
  • Loading branch information
yangby-cryptape committed Apr 10, 2024
1 parent fc5b5b8 commit 03bd8ff
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 10 deletions.
2 changes: 1 addition & 1 deletion src/cli/deploy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ impl Args {
NetworkInfo::new(self.ckb.network, self.ckb.ckb_endpoint.as_str().to_owned());
let configuration = {
let mut tmp = TransactionBuilderConfiguration::new_with_network(network_info.clone())?;
tmp.fee_rate = self.ckb.fee_rate;
tmp.fee_rate = self.ckb.fee_rate()?;
tmp
};

Expand Down
2 changes: 1 addition & 1 deletion src/cli/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ impl Args {
NetworkInfo::new(self.ckb.network, self.ckb.ckb_endpoint.as_str().to_owned());
let configuration = {
let mut tmp = TransactionBuilderConfiguration::new_with_network(network_info.clone())?;
tmp.fee_rate = self.ckb.fee_rate;
tmp.fee_rate = self.ckb.fee_rate()?;
tmp
};

Expand Down
68 changes: 62 additions & 6 deletions src/cli/mod.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
//! The command line argument.
use ckb_sdk::{rpc::CkbRpcClient, types::NetworkType};
use clap::{Parser, Subcommand};
use ckb_types::core::FeeRate;
use clap::{Args, Parser, Subcommand};
use clap_verbosity_flag::{InfoLevel, Verbosity};
use url::Url;

use crate::{
components::BitcoinClient,
prelude::*,
result::Result,
utilities::{value_parsers, Key256Bits},
};
Expand Down Expand Up @@ -66,11 +68,10 @@ pub struct CkbArgs {
value_parser = value_parsers::NetworkTypeValueParser,
default_value = "testnet"
)]
pub network: NetworkType,
pub(crate) network: NetworkType,

/// The fee rate for CKB transactions.
#[arg(long = "ckb-fee-rate", default_value = "1000")]
pub(crate) fee_rate: u64,
#[command(flatten)]
pub(crate) fee_rate: FeeRateArgs,

/// A binary file, which contains a secp256k1 private key.
/// This private key will be used to provide all CKBytes.
Expand All @@ -92,7 +93,39 @@ pub struct CkbRoArgs {
value_parser = value_parsers::NetworkTypeValueParser,
default_value = "testnet"
)]
pub network: NetworkType,
pub(crate) network: NetworkType,
}

#[derive(Args)]
#[group(multiple = false)]
pub struct FeeRateArgs {
/// The fixed fee rate for CKB transactions.
#[arg(
group = "fixed-fee-rate",
conflicts_with = "dynamic-fee-rate",
long = "ckb-fee-rate",
default_value = "1000"
)]
fixed_value: u64,

/// [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`.
///
/// 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.
///
/// ### Warning
///
/// Users have to make sure the remote CKB node they used are trustsed.
///
/// Ref: <https://github.com/nervosnetwork/ckb/tree/v0.114.0/rpc#method-get_fee_rate_statistics>
#[arg(
group = "dynamic-fee-rate",
conflicts_with = "fixed-fee-rate",
long = "enable-dynamic-ckb-fee-rate-with-limit"
)]
limit_for_dynamic: Option<u64>,
}

#[derive(Parser)]
Expand Down Expand Up @@ -160,6 +193,29 @@ impl CkbArgs {
pub fn client(&self) -> CkbRpcClient {
CkbRpcClient::new(self.ckb_endpoint.as_str())
}

pub fn fee_rate(&self) -> Result<u64> {
let value = if let Some(limit) = self.fee_rate.limit_for_dynamic {
let dynamic = self.client().dynamic_fee_rate()?;
log::info!("CKB fee rate: {} (dynamic)", FeeRate(dynamic));
if dynamic > limit {
log::warn!(
"dynamic CKB fee rate {} is too large, it seems unreasonable;\
so the upper limit {} will be used",
FeeRate(dynamic),
FeeRate(limit)
);
limit
} else {
dynamic
}
} else {
let fixed = self.fee_rate.fixed_value;
log::info!("CKB fee rate: {} (fixed)", FeeRate(fixed));
fixed
};
Ok(value)
}
}

impl CkbRoArgs {
Expand Down
4 changes: 2 additions & 2 deletions src/cli/serve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ impl Args {
NetworkInfo::new(self.ckb.network, self.ckb.ckb_endpoint.as_str().to_owned());
let configuration = {
let mut tmp = TransactionBuilderConfiguration::new_with_network(network_info.clone())?;
tmp.fee_rate = self.ckb.fee_rate;
tmp.fee_rate = self.ckb.fee_rate()?;
tmp
};

Expand Down Expand Up @@ -357,7 +357,7 @@ impl Args {
NetworkInfo::new(self.ckb.network, self.ckb.ckb_endpoint.as_str().to_owned());
let configuration = {
let mut tmp = TransactionBuilderConfiguration::new_with_network(network_info.clone())?;
tmp.fee_rate = self.ckb.fee_rate;
tmp.fee_rate = self.ckb.fee_rate()?;
tmp
};

Expand Down
14 changes: 14 additions & 0 deletions src/components/ckb_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ impl SpvInfoCell {
}

pub trait CkbRpcClientExtension {
fn dynamic_fee_rate(&self) -> Result<u64>;
fn send_transaction_ext(&self, tx_json: TransactionView, dry_run: bool) -> Result<H256>;
fn find_raw_spv_cells(&self, spv_type_script: Script) -> Result<Vec<LiveCell>>;

Expand Down Expand Up @@ -109,6 +110,17 @@ pub trait CkbRpcClientExtension {
}

impl CkbRpcClientExtension for CkbRpcClient {
fn dynamic_fee_rate(&self) -> Result<u64> {
self.get_fee_rate_statistics(None)?
.ok_or_else(|| {
let msg = "remote server replied null for \
RPC method get_fee_rate_statistics(null)";
Error::other(msg)
})
.map(|resp| resp.median)
.map(Into::into)
}

fn send_transaction_ext(&self, tx_json: TransactionView, dry_run: bool) -> Result<H256> {
if log::log_enabled!(log::Level::Trace) {
match serde_json::to_string_pretty(&tx_json) {
Expand Down Expand Up @@ -147,6 +159,8 @@ impl CkbRpcClientExtension for CkbRpcClient {
})?
.unpack();

log::trace!("the type script of SPV cell is {spv_type_script}");

let query = CellQueryOptions::new(spv_type_script, PrimaryScriptType::Type);
let order = Order::Desc;
let search_key = SearchKey::from(query);
Expand Down

0 comments on commit 03bd8ff

Please sign in to comment.