Skip to content

Commit 640ab38

Browse files
committed
feat(rpc): getmininginfo currentblockweight+currentblocktx from fee-ordered mempool greedy fill
Op: extend
1 parent 356dc2c commit 640ab38

1 file changed

Lines changed: 65 additions & 2 deletions

File tree

crates/rpc/src/handlers/mining.rs

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use crate::error::RpcError;
88
use crate::handlers::{ensure_no_params, params_array, required_str};
99

1010
const NETWORK_HASHPS_WINDOW: u32 = 120;
11+
const MAX_BLOCK_WEIGHT: u64 = 4_000_000;
1112

1213
pub(crate) fn getblocktemplate(ctx: &Arc<Context>, params: &Value) -> Result<Value, RpcError> {
1314
if !params.is_null() {
@@ -51,6 +52,7 @@ pub(crate) fn getblocktemplate(ctx: &Arc<Context>, params: &Value) -> Result<Val
5152

5253
pub(crate) fn getmininginfo(ctx: &Arc<Context>, params: &Value) -> Result<Value, RpcError> {
5354
ensure_no_params(params)?;
55+
let (current_block_weight, current_block_tx) = estimate_current_block(ctx);
5456

5557
let blocks = ctx.applied_height();
5658
let pooledtx = ctx.mempool.read().stats().txs;
@@ -71,8 +73,8 @@ pub(crate) fn getmininginfo(ctx: &Arc<Context>, params: &Value) -> Result<Value,
7173

7274
Ok(json!({
7375
"blocks": blocks,
74-
"currentblockweight": 0_u64,
75-
"currentblocktx": 0_u64,
76+
"currentblockweight": current_block_weight,
77+
"currentblocktx": current_block_tx,
7678
"difficulty": difficulty,
7779
"networkhashps": estimate_network_hashps(ctx),
7880
"pooledtx": pooledtx,
@@ -81,6 +83,30 @@ pub(crate) fn getmininginfo(ctx: &Arc<Context>, params: &Value) -> Result<Value,
8183
}))
8284
}
8385

86+
fn estimate_current_block(ctx: &Context) -> (u64, u64) {
87+
let pool = ctx.mempool.read();
88+
let mut candidates: Vec<(u64, u64)> = Vec::with_capacity(pool.entries.len());
89+
for (_id, entry) in &pool.entries {
90+
let weight = u64::from(entry.vsize).saturating_mul(4);
91+
candidates.push((entry.fee_rate, weight));
92+
}
93+
94+
candidates.sort_by(|a, b| b.0.cmp(&a.0));
95+
96+
let mut total_weight: u64 = 0;
97+
let mut tx_count: u64 = 0;
98+
for (_rate, weight) in candidates {
99+
let next = total_weight.saturating_add(weight);
100+
if next > MAX_BLOCK_WEIGHT {
101+
break;
102+
}
103+
total_weight = next;
104+
tx_count = tx_count.saturating_add(1);
105+
}
106+
107+
(total_weight, tx_count)
108+
}
109+
84110
fn estimate_network_hashps(ctx: &Context) -> f64 {
85111
let tree = ctx.block_tree.read();
86112
let Some(tip_snapshot) = ctx.applied_tip.load_full() else {
@@ -215,6 +241,43 @@ mod getmininginfo_tests {
215241
assert_eq!(pooledtx, 0);
216242
}
217243

244+
#[test]
245+
fn getmininginfo_currentblockweight_reflects_mempool_when_populated() {
246+
use bitcoin_rs_mempool::MempoolEntry;
247+
248+
let ctx = Arc::new(Context::new());
249+
{
250+
let mut pool = ctx.mempool.write();
251+
let tx = bitcoin::Transaction {
252+
version: bitcoin::transaction::Version(2),
253+
lock_time: bitcoin::absolute::LockTime::ZERO,
254+
input: Vec::new(),
255+
output: Vec::new(),
256+
};
257+
let entry = MempoolEntry::new(Arc::new(tx), 250, 5_000, 1, 7);
258+
pool.insert_entry(entry)
259+
.unwrap_or_else(|err| panic!("insert_entry failed: {err}"));
260+
}
261+
262+
let result = getmininginfo(&ctx, &json!([]))
263+
.unwrap_or_else(|err| panic!("getmininginfo failed: {err}"));
264+
let Some(weight) = result
265+
.get("currentblockweight")
266+
.and_then(JsonValueTrait::as_u64)
267+
else {
268+
panic!("currentblockweight missing: {result:?}");
269+
};
270+
let Some(tx_count) = result
271+
.get("currentblocktx")
272+
.and_then(JsonValueTrait::as_u64)
273+
else {
274+
panic!("currentblocktx missing: {result:?}");
275+
};
276+
277+
assert_eq!(weight, 1_000);
278+
assert_eq!(tx_count, 1);
279+
}
280+
218281
#[test]
219282
fn getmininginfo_networkhashps_zero_when_no_applied_tip() {
220283
let ctx = Arc::new(Context::new());

0 commit comments

Comments
 (0)