diff --git a/chronik/chronik-http/src/electrum.rs b/chronik/chronik-http/src/electrum.rs --- a/chronik/chronik-http/src/electrum.rs +++ b/chronik/chronik-http/src/electrum.rs @@ -280,41 +280,84 @@ } } -impl ChronikElectrumRPCBlockchainEndpoint { - async fn transaction_get(&self, params: Value) -> Result<Value, RPCError> { - let txid_hex: Value; - let verbose: Value; - match params { - Value::Array(arr) => { - txid_hex = arr - .first() - .ok_or(RPCError::InvalidParams( - "Missing mandatory 'txid' parameter", - ))? - .clone(); - verbose = match arr.get(1) { - Some(val) => val.clone(), - None => Value::Bool(false), - }; +macro_rules! get_positional_param { + ($arr:expr, $index:expr, $name:expr) => {{ + $arr.get($index) + .ok_or(RPCError::InvalidParams(concat!( + "Missing mandatory '", + $name, + "' parameter" + )))? + .clone() + }}; +} + +macro_rules! get_optional_positional_param { + ($arr:expr, $index:expr, $default:expr) => {{ + match $arr.get($index) { + Some(val) => val.clone(), + None => $default, + } + }}; +} + +macro_rules! get_named_param { + ($obj:expr, $key:expr) => {{ + match $obj.get($key) { + Some(value) => Ok(value.clone()), + None => Err(RPCError::InvalidParams(concat!( + "Missing mandatory '", + $key, + "' parameter" + ))), + }? + }}; +} + +macro_rules! get_optional_named_param { + ($obj:expr, $key:expr, $default:expr) => {{ + match $obj.get($key) { + Some(value) => value.clone(), + None => $default, + } + }}; +} + +macro_rules! get_param { + ($params:expr, $index:expr, $key:expr) => {{ + match $params { + Value::Array(ref arr) => { + Ok(get_positional_param!(arr, $index, $key)) } - Value::Object(obj) => { - txid_hex = match obj.get("txid") { - Some(txid) => Ok(txid.clone()), - None => Err(RPCError::InvalidParams( - "Missing mandatory 'txid' parameter", - )), - }?; - verbose = match obj.get("verbose") { - Some(verbose) => verbose.clone(), - None => Value::Bool(false), - }; + Value::Object(ref obj) => Ok(get_named_param!(obj, $key)), + _ => Err(RPCError::InvalidParams( + "'params' must be an array or an object", + )), + } + }}; +} + +macro_rules! get_optional_param { + ($params:expr, $index:expr, $key:expr, $default:expr) => {{ + match $params { + Value::Array(ref arr) => { + Ok(get_optional_positional_param!(arr, $index, $default)) } - _ => { - return Err(RPCError::InvalidParams( - "'params' must be an array or an object", - )) + Value::Object(ref obj) => { + Ok(get_optional_named_param!(obj, $key, $default)) } - }; + _ => Err(RPCError::InvalidParams( + "'params' must be an array or an object", + )), + } + }}; +} + +impl ChronikElectrumRPCBlockchainEndpoint { + async fn transaction_get(&self, params: Value) -> Result<Value, RPCError> { + let txid_hex = get_param!(params, 0, "txid")?; + let verbose = + get_optional_param!(params, 1, "verbose", Value::Bool(false))?; let txid_hex = match txid_hex { Value::String(s) => Ok(s), _ => Err(RPCError::InvalidParams(