From 079b9fa2fc8356cf6a65fb3be2ea23592c99ab76 Mon Sep 17 00:00:00 2001 From: canonbrother Date: Thu, 10 Oct 2024 19:39:35 +0800 Subject: [PATCH] Ocean: api rpc controller (#3090) * add rpc ctrl * update ocean ci * lint --- .github/workflows/tests-ocean.yml | 2 +- lib/ain-ocean/src/api/mod.rs | 2 + lib/ain-ocean/src/api/rpc.rs | 67 +++++++++++++++++++++++++++++++ lib/ain-ocean/src/error.rs | 5 +++ 4 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 lib/ain-ocean/src/api/rpc.rs diff --git a/.github/workflows/tests-ocean.yml b/.github/workflows/tests-ocean.yml index b737977b678..7f8f4ee1261 100644 --- a/.github/workflows/tests-ocean.yml +++ b/.github/workflows/tests-ocean.yml @@ -5,7 +5,7 @@ on: pull_request: branches: - master - - feature/ocean-archive # TODO(): remove before merge to master + - ocean-refinements # TODO(): remove before merge to master concurrency: group: ${{ github.workflow }}-${{ github.ref || github.run_id }} diff --git a/lib/ain-ocean/src/api/mod.rs b/lib/ain-ocean/src/api/mod.rs index a68638145b4..40f76d81959 100644 --- a/lib/ain-ocean/src/api/mod.rs +++ b/lib/ain-ocean/src/api/mod.rs @@ -25,6 +25,7 @@ pub mod prices; mod query; mod rawtx; mod response; +mod rpc; mod stats; mod tokens; mod transactions; @@ -121,6 +122,7 @@ pub async fn ocean_router( .nest("/tokens", tokens::router(Arc::clone(&context))) .nest("/transactions", transactions::router(Arc::clone(&context))) .nest("/blocks", block::router(Arc::clone(&context))) + .nest("/rpc", rpc::router(Arc::clone(&context))) .fallback(not_found); let debug_router = Router::new() diff --git a/lib/ain-ocean/src/api/rpc.rs b/lib/ain-ocean/src/api/rpc.rs new file mode 100644 index 00000000000..809f0853ec1 --- /dev/null +++ b/lib/ain-ocean/src/api/rpc.rs @@ -0,0 +1,67 @@ +use std::sync::Arc; + +use ain_macros::ocean_endpoint; +use axum::{routing::post, Extension, Json, Router}; +use defichain_rpc::RpcApi; +use serde::{Deserialize, Serialize}; + +use super::{response::Response, AppContext}; +use crate::{ + error::{ApiError, Error}, + Result, +}; + +#[derive(Serialize, Deserialize, Default, Clone)] +#[serde(rename_all = "camelCase")] +struct RpcDto { + method: String, + params: Vec, +} + +fn method_whitelist(method: &str) -> Result<()> { + let methods = [ + "getblockchaininfo", + "getblockhash", + "getblockcount", + "getblock", + "getblockstats", + "getgov", + "validateaddress", + "listcommunitybalances", + "getaccounthistory", + "getfutureswapblock", + "getpendingfutureswaps", + "sendrawtransaction", + "getrawtransaction", + "getgovproposal", + "listgovproposals", + "listgovproposalvotes", + "vmmap", + "gettxout", + ]; + + if !methods.contains(&method) { + log::debug!("forbidden"); + return Err(Error::Forbidden { + method: method.to_owned(), + }); + } + + Ok(()) +} + +#[ocean_endpoint] +async fn rpc( + Extension(ctx): Extension>, + Json(body): Json, +) -> Result> { + method_whitelist(&body.method)?; + + let res: serde_json::Value = ctx.client.call(&body.method, &body.params).await?; + + Ok(Response::new(res)) +} + +pub fn router(ctx: Arc) -> Router { + Router::new().route("/", post(rpc)).layer(Extension(ctx)) +} diff --git a/lib/ain-ocean/src/error.rs b/lib/ain-ocean/src/error.rs index 20f5c0febaa..907d9dd6fc1 100644 --- a/lib/ain-ocean/src/error.rs +++ b/lib/ain-ocean/src/error.rs @@ -108,6 +108,10 @@ pub enum Error { #[snafu(implicit)] location: Location, }, + #[snafu(display("Rpc {} method is not whitelisted", method))] + Forbidden { + method: String, + }, #[snafu(context(false))] IOError { #[snafu(source)] @@ -312,6 +316,7 @@ impl Error { } => (StatusCode::NOT_FOUND, e.message.to_string()), Self::NotFound { kind: _ } => (StatusCode::NOT_FOUND, format!("{self}")), Self::NotFoundMessage { msg } => (StatusCode::NOT_FOUND, msg.clone()), + Self::Forbidden { method: _ } => (StatusCode::FORBIDDEN, format!("{self}")), Self::BadRequest { msg } => (StatusCode::BAD_REQUEST, msg.clone()), Self::Other { msg } => (StatusCode::INTERNAL_SERVER_ERROR, msg.clone()), _ => (StatusCode::INTERNAL_SERVER_ERROR, self.to_string()),