Skip to content
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

feat: (experimental) optional fee estimator with different algorithms #4477

13 changes: 13 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ members = [
"util/dao/utils",
"traits",
"spec",
"util/fee-estimator",
"util/proposal-table",
"script",
"util/app-config",
Expand Down
7 changes: 7 additions & 0 deletions chain/src/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,7 @@ impl ChainService {
// is_better_than
let new_best_block = cannon_total_difficulty > current_total_difficulty;

let in_ibd = self.shared.is_initial_block_download();
if new_best_block {
debug!(
"Newly found best block : {} => {:#x}, difficulty diff = {:#x}",
Expand Down Expand Up @@ -517,6 +518,9 @@ impl ChainService {
) {
error!("Notify update_tx_pool_for_reorg error {}", e);
}
if let Err(e) = tx_pool_controller.update_ibd_state(in_ibd) {
error!("Notify update_ibd_state error {}", e);
}
}

let block_ref: &BlockView = █
Expand Down Expand Up @@ -546,6 +550,9 @@ impl ChainService {
if let Err(e) = tx_pool_controller.notify_new_uncle(block_ref.as_uncle()) {
error!("Notify new_uncle error {}", e);
}
if let Err(e) = tx_pool_controller.update_ibd_state(in_ibd) {
error!("Notify update_ibd_state error {}", e);
}
}
}

Expand Down
4 changes: 4 additions & 0 deletions resource/ckb.toml
Original file line number Diff line number Diff line change
Expand Up @@ -218,3 +218,7 @@ block_uncles_cache_size = 30
# db_port = 5432
# db_user = "postgres"
# db_password = "123456"
#
# # [fee_estimator]
# # Specifies the fee estimates algorithm. Current algorithms: ConfirmationFraction, WeightUnitsFlow.
# # algorithm = "WeightUnitsFlow"
67 changes: 67 additions & 0 deletions rpc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ The crate `ckb-rpc`'s minimum supported rustc version is 1.71.1.

* [Method `dry_run_transaction`](#experiment-dry_run_transaction)
* [Method `calculate_dao_maximum_withdraw`](#experiment-calculate_dao_maximum_withdraw)
* [Method `estimate_fee_rate`](#experiment-estimate_fee_rate)
* [Module Indexer](#module-indexer) [👉 OpenRPC spec](http://playground.open-rpc.org/?uiSchema[appBar][ui:title]=CKB-Indexer&uiSchema[appBar][ui:splitView]=false&uiSchema[appBar][ui:examplesDropdown]=false&uiSchema[appBar][ui:logoUrl]=https://raw.githubusercontent.com/nervosnetwork/ckb-rpc-resources/develop/ckb-logo.jpg&schemaUrl=https://raw.githubusercontent.com/nervosnetwork/ckb-rpc-resources/develop/json/indexer_rpc_doc.json)

* [Method `get_indexer_tip`](#indexer-get_indexer_tip)
Expand Down Expand Up @@ -169,6 +170,7 @@ The crate `ckb-rpc`'s minimum supported rustc version is 1.71.1.
* [Type `EpochNumberWithFraction`](#type-epochnumberwithfraction)
* [Type `EpochView`](#type-epochview)
* [Type `EstimateCycles`](#type-estimatecycles)
* [Type `EstimateMode`](#type-estimatemode)
* [Type `ExtraLoggerConfig`](#type-extraloggerconfig)
* [Type `FeeRateStatistics`](#type-feeratestatistics)
* [Type `H256`](#type-h256)
Expand Down Expand Up @@ -2164,6 +2166,62 @@ Response
}
```

<a id="experiment-estimate_fee_rate"></a>
#### Method `estimate_fee_rate`
* `estimate_fee_rate(estimate_mode, enable_fallback)`
* `estimate_mode`: [`EstimateMode`](#type-estimatemode) `|` `null`
* `enable_fallback`: `boolean` `|` `null`
* result: [`Uint64`](#type-uint64)

Get fee estimates.

###### Params

* `estimate_mode` - True to enable a simple fallback algorithm, when lack of historical empirical data to estimate fee rates with configured algorithm.

Default: `no_priority`.

* `enable_fallback` - True to enable a simple fallback algorithm, when lack of historical empirical data to estimate fee rates with configured algorithm.

Default: `true`.

####### The fallback algorithm

Since CKB transaction confirmation involves a two-step process—1) propose and 2) commit, it is complex to
predict the transaction fee accurately with the expectation that it will be included within a certain block height.

This algorithm relies on two assumptions and uses a simple strategy to estimate the transaction fee: 1) all transactions
in the pool are waiting to be proposed, and 2) no new transactions will be added to the pool.

In practice, this simple algorithm should achieve good accuracy fee rate and running performance.

###### Returns

The estimated fee rate in shannons per kilobyte.

###### Examples

Request

```json
{
"id": 42,
"jsonrpc": "2.0",
"method": "estimate_fee_rate",
"params": []
}
```

Response

```json
{
"id": 42,
"jsonrpc": "2.0",
"result": "0x3e8"
}
```

### Module `Indexer`
- [👉 OpenRPC spec](http://playground.open-rpc.org/?uiSchema[appBar][ui:title]=CKB-Indexer&uiSchema[appBar][ui:splitView]=false&uiSchema[appBar][ui:examplesDropdown]=false&uiSchema[appBar][ui:logoUrl]=https://raw.githubusercontent.com/nervosnetwork/ckb-rpc-resources/develop/ckb-logo.jpg&schemaUrl=https://raw.githubusercontent.com/nervosnetwork/ckb-rpc-resources/develop/json/indexer_rpc_doc.json)

Expand Down Expand Up @@ -5936,6 +5994,15 @@ Response result of the RPC method `estimate_cycles`.

* `cycles`: [`Uint64`](#type-uint64) - The count of cycles that the VM has consumed to verify this transaction.

### Type `EstimateMode`
The fee estimate mode.

It's an enum value from one of:
- no_priority : No priority, expect the transaction to be committed in 1 hour.
- low_priority : Low priority, expect the transaction to be committed in 30 minutes.
- medium_priority : Medium priority, expect the transaction to be committed in 10 minutes.
- high_priority : High priority, expect the transaction to be committed as soon as possible.

### Type `ExtraLoggerConfig`
Runtime logger config for extra loggers.

Expand Down
74 changes: 73 additions & 1 deletion rpc/src/module/experiment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ use crate::module::chain::CyclesEstimator;
use async_trait::async_trait;
use ckb_dao::DaoCalculator;
use ckb_jsonrpc_types::{
Capacity, DaoWithdrawingCalculationKind, EstimateCycles, OutPoint, Transaction,
Capacity, DaoWithdrawingCalculationKind, EstimateCycles, EstimateMode, OutPoint, Transaction,
Uint64,
};
use ckb_shared::{shared::Shared, Snapshot};
use ckb_store::ChainStore;
Expand Down Expand Up @@ -162,6 +163,61 @@ pub trait ExperimentRpc {
out_point: OutPoint,
kind: DaoWithdrawingCalculationKind,
) -> Result<Capacity>;

/// Get fee estimates.
///
/// ## Params
///
/// * `estimate_mode` - True to enable a simple fallback algorithm, when lack of historical empirical data to estimate fee rates with configured algorithm.
///
/// Default: `no_priority`.
///
/// * `enable_fallback` - True to enable a simple fallback algorithm, when lack of historical empirical data to estimate fee rates with configured algorithm.
///
/// Default: `true`.
///
/// ### The fallback algorithm
///
/// Since CKB transaction confirmation involves a two-step process—1) propose and 2) commit, it is complex to
/// predict the transaction fee accurately with the expectation that it will be included within a certain block height.
///
/// This algorithm relies on two assumptions and uses a simple strategy to estimate the transaction fee: 1) all transactions
/// in the pool are waiting to be proposed, and 2) no new transactions will be added to the pool.
///
/// In practice, this simple algorithm should achieve good accuracy fee rate and running performance.
///
/// ## Returns
///
/// The estimated fee rate in shannons per kilobyte.
///
/// ## Examples
///
/// Request
///
/// ```json
/// {
/// "id": 42,
/// "jsonrpc": "2.0",
/// "method": "estimate_fee_rate",
/// "params": []
/// }
/// ```
///
/// Response
///
/// ```json
/// {
/// "id": 42,
/// "jsonrpc": "2.0",
/// "result": "0x3e8"
/// }
/// ```
#[rpc(name = "estimate_fee_rate")]
fn estimate_fee_rate(
&self,
estimate_mode: Option<EstimateMode>,
enable_fallback: Option<bool>,
) -> Result<Uint64>;
}

#[derive(Clone)]
Expand Down Expand Up @@ -241,4 +297,20 @@ impl ExperimentRpc for ExperimentRpcImpl {
}
}
}

fn estimate_fee_rate(
&self,
estimate_mode: Option<EstimateMode>,
enable_fallback: Option<bool>,
) -> Result<Uint64> {
let estimate_mode = estimate_mode.unwrap_or_default();
let enable_fallback = enable_fallback.unwrap_or(true);
self.shared
.tx_pool_controller()
.estimate_fee_rate(estimate_mode.into(), enable_fallback)
.map_err(|err| RPCError::custom(RPCError::CKBInternalError, err.to_string()))?
.map_err(RPCError::from_any_error)
.map(core::FeeRate::as_u64)
.map(Into::into)
}
}
1 change: 1 addition & 0 deletions rpc/src/tests/examples.rs
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,7 @@ fn mock_rpc_response(example: &RpcTestExample, response: &mut RpcTestResponse) {
"get_pool_tx_detail_info" => {
response.result["timestamp"] = example.response.result["timestamp"].clone()
}
"estimate_fee_rate" => replace_rpc_response::<Uint64>(example, response),
_ => {}
}
}
Expand Down
1 change: 1 addition & 0 deletions shared/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ ckb-systemtime = { path = "../util/systemtime", version = "= 0.117.0-pre" }
ckb-channel = { path = "../util/channel", version = "= 0.117.0-pre" }
ckb-app-config = {path = "../util/app-config", version = "= 0.117.0-pre"}
ckb-migrate = { path = "../util/migrate", version = "= 0.117.0-pre" }
ckb-fee-estimator = {path = "../util/fee-estimator", version = "= 0.117.0-pre"}
once_cell = "1.8.0"
tempfile.workspace = true

Expand Down
Loading
Loading