Skip to content

Commit 6e8648b

Browse files
committed
feat(rpc): getrawmempool supports mempool_sequence flag for ZMQ-style polling
Op: extend
1 parent 640ab38 commit 6e8648b

1 file changed

Lines changed: 79 additions & 14 deletions

File tree

crates/rpc/src/handlers/mempool.rs

Lines changed: 79 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -56,23 +56,38 @@ pub(crate) fn getmempoolentry(ctx: &Arc<Context>, params: &Value) -> Result<Valu
5656

5757
pub(crate) fn getrawmempool(ctx: &Arc<Context>, params: &Value) -> Result<Value, RpcError> {
5858
let verbose = optional_bool(params, 0, false)?;
59+
let include_sequence = optional_bool(params, 1, false)?;
5960
let pool = ctx.mempool.read();
60-
if !verbose {
61-
let txids = pool
62-
.entries
63-
.iter()
64-
.map(|(_id, entry)| entry.tx.compute_txid().to_string())
65-
.collect::<Vec<_>>();
66-
return Ok(json!(txids));
61+
let sequence = pool.sequence_number();
62+
if verbose {
63+
let mut object = serde_json::Map::new();
64+
for (_id, entry) in &pool.entries {
65+
object.insert(
66+
entry.tx.compute_txid().to_string(),
67+
entry_to_serde(entry, &pool),
68+
);
69+
}
70+
if include_sequence {
71+
object.insert(
72+
"mempool_sequence".to_owned(),
73+
serde_json::Value::Number(serde_json::Number::from(sequence)),
74+
);
75+
}
76+
return serde_to_sonic(&serde_json::Value::Object(object));
6777
}
68-
let mut object = serde_json::Map::new();
69-
for (_id, entry) in &pool.entries {
70-
object.insert(
71-
entry.tx.compute_txid().to_string(),
72-
entry_to_serde(entry, &pool),
73-
);
78+
79+
let txids: Vec<String> = pool
80+
.entries
81+
.iter()
82+
.map(|(_id, entry)| entry.tx.compute_txid().to_string())
83+
.collect();
84+
if include_sequence {
85+
return Ok(json!({
86+
"txids": txids,
87+
"mempool_sequence": sequence,
88+
}));
7489
}
75-
serde_to_sonic(&serde_json::Value::Object(object))
90+
Ok(json!(txids))
7691
}
7792

7893
pub(crate) fn getmempoolancestors(ctx: &Arc<Context>, params: &Value) -> Result<Value, RpcError> {
@@ -235,6 +250,56 @@ mod tests {
235250
);
236251
}
237252

253+
#[test]
254+
fn getrawmempool_with_sequence_flag_wraps_response() {
255+
let ctx = Arc::new(Context::new());
256+
let handler = crate::Handler::new(Arc::clone(&ctx));
257+
let result = handler
258+
.dispatch("getrawmempool", &json!([false, true]))
259+
.unwrap_or_else(|err| panic!("getrawmempool failed: {err}"));
260+
let Some(seq) = result
261+
.get("mempool_sequence")
262+
.and_then(JsonValueTrait::as_u64)
263+
else {
264+
panic!("mempool_sequence missing: {result:?}");
265+
};
266+
assert_eq!(seq, 0);
267+
let Some(txids) = result.get("txids").and_then(JsonContainerTrait::as_array) else {
268+
panic!("txids missing: {result:?}");
269+
};
270+
assert!(txids.is_empty());
271+
}
272+
273+
#[test]
274+
fn getrawmempool_without_sequence_flag_returns_bare_array() {
275+
let ctx = Arc::new(Context::new());
276+
let handler = crate::Handler::new(Arc::clone(&ctx));
277+
let result = handler
278+
.dispatch("getrawmempool", &json!([]))
279+
.unwrap_or_else(|err| panic!("getrawmempool failed: {err}"));
280+
assert!(result.is_array(), "expected bare array: {result:?}");
281+
}
282+
283+
#[test]
284+
fn getrawmempool_verbose_sequence_flag_flattens_response() {
285+
let ctx = Arc::new(Context::new());
286+
let handler = crate::Handler::new(Arc::clone(&ctx));
287+
let result = handler
288+
.dispatch("getrawmempool", &json!([true, true]))
289+
.unwrap_or_else(|err| panic!("getrawmempool failed: {err}"));
290+
let Some(seq) = result
291+
.get("mempool_sequence")
292+
.and_then(JsonValueTrait::as_u64)
293+
else {
294+
panic!("mempool_sequence missing: {result:?}");
295+
};
296+
assert_eq!(seq, 0);
297+
assert!(
298+
result.get("txids").is_none(),
299+
"verbose response must not use txids wrapper: {result:?}"
300+
);
301+
}
302+
238303
#[test]
239304
fn getmempooldescendants_walks_real_descendant_graph() -> Result<(), Box<dyn std::error::Error>>
240305
{

0 commit comments

Comments
 (0)