Repository: nervosnetwork/ckb (language: rust)

Issue:
[BUG] `fee_rate_statistics` returns a feeRate median lower than 1000
Currently `fee_rate_statistics` returns an apparently impossible median feeRate: `0x3b2` (946 < 1000)

To reproduce this feel free to use:

```bash
$ curl -X POST https://rpc.ankr.com/nervos_ckb -d '{"jsonrpc":"2.0","method":"get_fee_rate_statistics","params":[],"id":42}'
{"id":42,"jsonrpc":"2.0","result":{"mean":"0x25580","median":"0x3b2"}}
```

How is this possible?

Love & Peace, Phroi


Discussion / hints:
This node's version is `v0.118.0-rc2`, investigating...
```bash
❯ curl -s -X POST https://rpc.ankr.com/nervos_ckb -d '{"jsonrpc":"2.0","method":"local_node_info","params":[],"id":42}' | jq .result.version
"0.118.0-rc2 (921868e 2024-09-04)"
```
A couple minutes ago I also got this one, so it's not limited to that node/version:

```bash
$ curl -X POST https://mainnet.ckbapp.dev/ -d '{"jsonrpc":"2.0","method":"get_fee_rate_statistics","params":[],"id":42}';
{"jsonrpc":"2.0","result":{"mean":"0x25a65","median":"0x3b2"},"id":42}
```
By the way, in the past I got other issues with this method, so maybe it's related: https://github.com/nervosnetwork/ckb/issues/4350

Fix patch:
diff --git a/rpc/src/util/fee_rate.rs b/rpc/src/util/fee_rate.rs
index ceeb6ab730..2cea14ba15 100644
--- a/rpc/src/util/fee_rate.rs
+++ b/rpc/src/util/fee_rate.rs
@@ -83,15 +83,19 @@ where
         target = std::cmp::min(self.provider.max_target(), target);
 
         let mut fee_rates = self.provider.collect(target, |mut fee_rates, block_ext| {
-            if !block_ext.txs_fees.is_empty()
+            if block_ext.txs_fees.len() > 1
                 && block_ext.cycles.is_some()
                 && block_ext.txs_sizes.is_some()
             {
+                // block_ext.txs_fees, cycles, txs_sizes length is same
                 for (fee, cycles, size) in itertools::izip!(
                     block_ext.txs_fees,
                     block_ext.cycles.expect("checked"),
                     block_ext.txs_sizes.expect("checked")
-                ) {
+                )
+                // skip cellbase (first element in the Vec)
+                .skip(1)
+                {
                     let weight = get_transaction_weight(size as usize, cycles);
                     if weight > 0 {
                         fee_rates.push(FeeRate::calculate(fee, weight).as_u64());


Test patch:
diff --git a/rpc/src/tests/fee_rate.rs b/rpc/src/tests/fee_rate.rs
index 44f37b4771..e4d41ebbef 100644
--- a/rpc/src/tests/fee_rate.rs
+++ b/rpc/src/tests/fee_rate.rs
@@ -53,9 +53,16 @@ fn test_fee_rate_statics() {
             total_difficulty: 0u64.into(),
             total_uncles_count: 0,
             verified: None,
-            txs_fees: vec![Capacity::shannons(i * i * 100)],
-            cycles: Some(vec![i * 100]),
-            txs_sizes: Some(vec![i * 100]),
+
+            // first element in txs_fees is belong to cellbase
+            txs_fees: vec![
+                Capacity::shannons(i * 1234),
+                Capacity::shannons(i * i * 100),
+            ],
+            // first element in cycles is belong to cellbase
+            cycles: Some(vec![0, i * 100]),
+            // first element in txs_sizes is belong to cellbase
+            txs_sizes: Some(vec![i * 5678, i * 100]),
         };
         provider.append(i, ext);
     }