Skip to content

Commit c6a7fbd

Browse files
authored
Merge pull request Blockstream#103 from mempool/junderw/json-rpc-2
Fix JSON-RPC v2 errors
2 parents e5c1587 + 66c76bc commit c6a7fbd

File tree

1 file changed

+49
-18
lines changed

1 file changed

+49
-18
lines changed

src/electrum/server.rs

Lines changed: 49 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,21 @@ fn get_status_hash(txs: Vec<(Txid, Option<BlockId>)>, query: &Query) -> Option<F
9999
}
100100
}
101101

102+
#[repr(i16)]
103+
#[derive(Clone, Copy, PartialEq, Eq)]
104+
enum JsonRpcV2Error {
105+
ParseError = -32700,
106+
InvalidRequest = -32600,
107+
MethodNotFound = -32601,
108+
InternalError = -32603,
109+
}
110+
impl JsonRpcV2Error {
111+
#[inline]
112+
fn into_i16(self) -> i16 {
113+
self as i16
114+
}
115+
}
116+
102117
struct Connection {
103118
query: Arc<Query>,
104119
last_header_entry: Option<HeaderEntry>,
@@ -447,7 +462,14 @@ impl Connection {
447462
#[cfg(feature = "electrum-discovery")]
448463
"server.add_peer" => self.server_add_peer(params),
449464

450-
&_ => bail!("unknown method {} {:?}", method, params),
465+
&_ => {
466+
warn!("rpc unknown method #{} {} {:?}", id, method, params);
467+
return Ok(json_rpc_error(
468+
format!("Method {method} not found"),
469+
Some(id),
470+
JsonRpcV2Error::MethodNotFound,
471+
));
472+
}
451473
};
452474
timer.observe_duration();
453475
// TODO: return application errors should be sent to the client
@@ -461,7 +483,7 @@ impl Connection {
461483
params,
462484
e.display_chain()
463485
);
464-
json!({"jsonrpc": "2.0", "id": id, "error": format!("{}", e)})
486+
json_rpc_error(e, Some(id), JsonRpcV2Error::InternalError)
465487
}
466488
})
467489
}
@@ -558,7 +580,11 @@ impl Connection {
558580
}
559581
} else {
560582
// serde_json was unable to parse
561-
invalid_json_rpc(line)
583+
json_rpc_error(
584+
format!("Invalid JSON: {line}"),
585+
None,
586+
JsonRpcV2Error::ParseError,
587+
)
562588
}
563589
}
564590

@@ -572,16 +598,14 @@ impl Connection {
572598
(Some(Value::String(method)), Value::Array(params), Some(id)) => self
573599
.handle_command(method, params, id)
574600
.unwrap_or_else(|err| {
575-
json!({
576-
"error": {
577-
"code": 1,
578-
"message": format!("{method} RPC error: {err}")
579-
},
580-
"id": id,
581-
"jsonrpc": "2.0"
582-
})
601+
json_rpc_error(
602+
format!("{method} RPC error: {err}"),
603+
Some(id),
604+
JsonRpcV2Error::InternalError,
605+
)
583606
}),
584-
_ => invalid_json_rpc(value),
607+
(_, _, Some(id)) => json_rpc_error(value, Some(id), JsonRpcV2Error::InvalidRequest),
608+
_ => json_rpc_error(value, None, JsonRpcV2Error::InvalidRequest),
585609
}
586610
}
587611

@@ -661,15 +685,22 @@ impl Connection {
661685
}
662686

663687
#[inline]
664-
fn invalid_json_rpc(input: impl core::fmt::Display) -> Value {
665-
json!({
688+
fn json_rpc_error(
689+
input: impl core::fmt::Display,
690+
id: Option<&Value>,
691+
code: JsonRpcV2Error,
692+
) -> Value {
693+
let mut ret = json!({
666694
"error": {
667-
"code": -32600,
668-
"message": format!("invalid request: {input}")
695+
"code": code.into_i16(),
696+
"message": format!("{input}")
669697
},
670-
"id": null,
671698
"jsonrpc": "2.0"
672-
})
699+
});
700+
if let (Some(id), Some(obj)) = (id, ret.as_object_mut()) {
701+
obj.insert(String::from("id"), id.clone());
702+
}
703+
ret
673704
}
674705

675706
fn get_history(

0 commit comments

Comments
 (0)