Skip to content

Commit

Permalink
Ocean: api rpc controller (#3090)
Browse files Browse the repository at this point in the history
* add rpc ctrl

* update ocean ci

* lint
  • Loading branch information
canonbrother authored Oct 10, 2024
1 parent b8ad8c3 commit 079b9fa
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 1 deletion.
2 changes: 1 addition & 1 deletion .github/workflows/tests-ocean.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }}
Expand Down
2 changes: 2 additions & 0 deletions lib/ain-ocean/src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ pub mod prices;
mod query;
mod rawtx;
mod response;
mod rpc;
mod stats;
mod tokens;
mod transactions;
Expand Down Expand Up @@ -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()
Expand Down
67 changes: 67 additions & 0 deletions lib/ain-ocean/src/api/rpc.rs
Original file line number Diff line number Diff line change
@@ -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<serde_json::Value>,
}

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<Arc<AppContext>>,
Json(body): Json<RpcDto>,
) -> Result<Response<serde_json::Value>> {
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<AppContext>) -> Router {
Router::new().route("/", post(rpc)).layer(Extension(ctx))
}
5 changes: 5 additions & 0 deletions lib/ain-ocean/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -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()),
Expand Down

0 comments on commit 079b9fa

Please sign in to comment.