diff --git a/mm2src/mm2_main/src/rpc.rs b/mm2src/mm2_main/src/rpc.rs index d3df2042db..9720d935eb 100644 --- a/mm2src/mm2_main/src/rpc.rs +++ b/mm2src/mm2_main/src/rpc.rs @@ -175,12 +175,25 @@ fn response_from_dispatcher_error( response.serialize_http_response() } -async fn process_single_request(ctx: MmArc, req: Json, client: SocketAddr) -> Result>, String> { +async fn process_single_request(ctx: MmArc, mut req: Json, client: SocketAddr) -> Result>, String> { let local_only = ctx.conf["rpc_local_only"].as_bool().unwrap_or(true); if req["mmrpc"].is_null() { - return dispatcher_legacy::process_single_request(ctx, req, client, local_only) - .await - .map_err(|e| ERRL!("{}", e)); + match dispatcher_legacy::process_single_request(ctx.clone(), req.clone(), client, local_only).await { + Ok(t) => return Ok(t), + + Err(dispatcher_legacy::LegacyRequestProcessError::NoMatch) => { + // Try the v2 implementation + req["mmrpc"] = json!("2.0"); + info!( + "Couldn't resolve '{}' RPC using the legacy API, trying v2 (mmrpc: 2.0) instead.", + req["method"] + ); + }, + + Err(e) => { + return ERR!("{}", e); + }, + }; } let id = req["id"].as_u64().map(|id| id as usize); diff --git a/mm2src/mm2_main/src/rpc/dispatcher/dispatcher_legacy.rs b/mm2src/mm2_main/src/rpc/dispatcher/dispatcher_legacy.rs index 5f4b14f8b4..8d1a71db85 100644 --- a/mm2src/mm2_main/src/rpc/dispatcher/dispatcher_legacy.rs +++ b/mm2src/mm2_main/src/rpc/dispatcher/dispatcher_legacy.rs @@ -117,27 +117,49 @@ pub fn dispatcher(req: Json, ctx: MmArc) -> DispatcherRes { }) } +#[derive(Debug, Display)] +pub enum LegacyRequestProcessError { + #[display(fmt = "Selected method is not allowed: {reason}")] + NotAllowed { reason: String }, + #[display(fmt = "No such method")] + NoMatch, + #[display(fmt = "RPC call failed: {reason}")] + Failed { reason: String }, +} + pub async fn process_single_request( ctx: MmArc, req: Json, client: SocketAddr, local_only: bool, -) -> Result>, String> { +) -> Result>, LegacyRequestProcessError> { // https://github.com/artemii235/SuperNET/issues/368 if local_only && !client.ip().is_loopback() && !PUBLIC_METHODS.contains(&req["method"].as_str()) { - return ERR!("Selected method can be called from localhost only!"); + return Err(LegacyRequestProcessError::NotAllowed { + reason: "Selected method can only be called from localhost.".to_owned(), + }); } let rate_limit_ctx = RateLimitContext::from_ctx(&ctx).unwrap(); if rate_limit_ctx.is_banned(client.ip()).await { - return ERR!("Your ip is banned."); + return Err(LegacyRequestProcessError::NotAllowed { + reason: "Your IP is banned.".to_owned(), + }); } - try_s!(auth(&req, &ctx, &client).await); + auth(&req, &ctx, &client) + .await + .map_err(|reason| LegacyRequestProcessError::Failed { reason })?; let handler = match dispatcher(req, ctx.clone()) { DispatcherRes::Match(handler) => handler, - DispatcherRes::NoMatch(_) => return ERR!("No such method."), + DispatcherRes::NoMatch(_) => { + return Err(LegacyRequestProcessError::NoMatch); + }, }; - Ok(try_s!(handler.compat().await)) + + handler + .compat() + .await + .map_err(|reason| LegacyRequestProcessError::Failed { reason }) } /// The set of functions that convert the result of the updated handlers into the legacy format. diff --git a/mm2src/mm2_main/tests/mm2_tests/lightning_tests.rs b/mm2src/mm2_main/tests/mm2_tests/lightning_tests.rs index 4fde665bd6..cbd3853d25 100644 --- a/mm2src/mm2_main/tests/mm2_tests/lightning_tests.rs +++ b/mm2src/mm2_main/tests/mm2_tests/lightning_tests.rs @@ -163,7 +163,6 @@ async fn open_channel( let request = mm .rpc(&json!({ "userpass": mm.userpass, - "mmrpc": "2.0", "method": "lightning::channels::open_channel", "params": { "coin": coin, @@ -197,7 +196,6 @@ async fn close_channel(mm: &MarketMakerIt, uuid: &str, force_close: bool) -> Jso let request = mm .rpc(&json!({ "userpass": mm.userpass, - "mmrpc": "2.0", "method": "lightning::channels::close_channel", "params": { "coin": "tBTC-TEST-lightning", @@ -221,7 +219,6 @@ async fn add_trusted_node(mm: &MarketMakerIt, node_id: &str) -> Json { let request = mm .rpc(&json!({ "userpass": mm.userpass, - "mmrpc": "2.0", "method": "lightning::nodes::add_trusted_node", "params": { "coin": "tBTC-TEST-lightning", @@ -243,7 +240,6 @@ async fn generate_invoice(mm: &MarketMakerIt, amount_in_msat: u64) -> Json { let request = mm .rpc(&json!({ "userpass": mm.userpass, - "mmrpc": "2.0", "method": "lightning::payments::generate_invoice", "params": { "coin": "tBTC-TEST-lightning", @@ -267,7 +263,6 @@ async fn pay_invoice(mm: &MarketMakerIt, invoice: &str) -> Json { let request = mm .rpc(&json!({ "userpass": mm.userpass, - "mmrpc": "2.0", "method": "lightning::payments::send_payment", "params": { "coin": "tBTC-TEST-lightning", @@ -293,7 +288,6 @@ async fn get_payment_details(mm: &MarketMakerIt, payment_hash: &str) -> Json { let request = mm .rpc(&json!({ "userpass": mm.userpass, - "mmrpc": "2.0", "method": "lightning::payments::get_payment_details", "params": { "coin": "tBTC-TEST-lightning", @@ -428,7 +422,6 @@ fn test_connect_to_node() { let connect = block_on(mm_node_2.rpc(&json!({ "userpass": mm_node_2.userpass, - "mmrpc": "2.0", "method": "lightning::nodes::connect_to_node", "params": { "coin": "tBTC-TEST-lightning", @@ -468,7 +461,6 @@ fn test_open_channel() { let list_channels_node_1 = block_on(mm_node_1.rpc(&json!({ "userpass": mm_node_1.userpass, - "mmrpc": "2.0", "method": "lightning::channels::list_open_channels_by_filter", "params": { "coin": "tBTC-TEST-lightning", @@ -497,7 +489,6 @@ fn test_open_channel() { let list_channels_node_2 = block_on(mm_node_2.rpc(&json!({ "userpass": mm_node_2.userpass, - "mmrpc": "2.0", "method": "lightning::channels::list_open_channels_by_filter", "params": { "coin": "tBTC-TEST-lightning", @@ -547,7 +538,6 @@ fn test_send_payment() { let send_payment = block_on(mm_node_2.rpc(&json!({ "userpass": mm_node_2.userpass, - "mmrpc": "2.0", "method": "lightning::payments::send_payment", "params": { "coin": "tBTC-TEST-lightning", diff --git a/mm2src/mm2_main/tests/mm2_tests/mm2_tests_inner.rs b/mm2src/mm2_main/tests/mm2_tests/mm2_tests_inner.rs index a2451ac362..48aa48d4b6 100644 --- a/mm2src/mm2_main/tests/mm2_tests/mm2_tests_inner.rs +++ b/mm2src/mm2_main/tests/mm2_tests/mm2_tests_inner.rs @@ -53,16 +53,6 @@ cfg_wasm32! { fn test_rpc() { let (_, mm, _dump_log, _dump_dashboard) = mm_spat(); - let no_method = block_on(mm.rpc(&json! ({ - "userpass": mm.userpass, - "coin": "RICK", - "ipaddr": "electrum1.cipig.net", - "port": 10017 - }))) - .unwrap(); - assert!(no_method.0.is_server_error()); - assert_eq!((no_method.2)[ACCESS_CONTROL_ALLOW_ORIGIN], "http://localhost:4000"); - let not_json = mm.rpc_str("It's just a string").unwrap(); assert!(not_json.0.is_server_error()); assert_eq!((not_json.2)[ACCESS_CONTROL_ALLOW_ORIGIN], "http://localhost:4000");