Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ocean: Fixes LW support #3079

Merged
merged 10 commits into from
Oct 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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: 1 addition & 1 deletion lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ hex-literal = "0.4"
bincode = "1.3"
serde_with = "3.0"
heck = "0.4"
tower-http = { version = "0.4.0", features = ["full"] }
tower-http = { version = "0.4", features = ["full"] }
tower = "0.4.13"
hyper = "0.14.20"

Expand Down
2 changes: 2 additions & 0 deletions lib/ain-ocean/src/api/address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ struct History {
txno: u32,
}

#[skip_serializing_none]
#[derive(Debug, Serialize)]
struct AddressHistory {
owner: String,
Expand Down Expand Up @@ -426,6 +427,7 @@ pub struct ScriptUnspentScriptResponse {
pub hex: String,
}

#[skip_serializing_none]
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ScriptUnspentVoutResponse {
Expand Down
2 changes: 2 additions & 0 deletions lib/ain-ocean/src/api/governance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use axum::{routing::get, Extension, Router};
use bitcoin::Txid;
use defichain_rpc::{json::governance::*, GovernanceRPC};
use serde::Deserialize;
use serde_with::skip_serializing_none;

use super::{
path::Path,
Expand All @@ -14,6 +15,7 @@ use super::{
};
use crate::{error::ApiError, model::ApiProposalInfo, Result};

#[skip_serializing_none]
#[derive(Deserialize, Default)]
pub struct GovernanceQuery {
#[serde(flatten)]
Expand Down
6 changes: 6 additions & 0 deletions lib/ain-ocean/src/api/loan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use defichain_rpc::{
use futures::future::try_join_all;
use log::trace;
use serde::{Serialize, Serializer};
use serde_with::skip_serializing_none;
use snafu::OptionExt;

use super::{
Expand Down Expand Up @@ -95,6 +96,7 @@ async fn get_scheme(
Ok(Response::new(scheme.into()))
}

#[skip_serializing_none]
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct CollateralToken {
Expand Down Expand Up @@ -219,6 +221,7 @@ async fn get_collateral_token(
)))
}

#[skip_serializing_none]
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct LoanToken {
Expand Down Expand Up @@ -571,13 +574,15 @@ pub struct VaultLiquidatedResponse {
pub batches: Vec<VaultLiquidatedBatchResponse>,
}

#[skip_serializing_none]
#[derive(Serialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct HighestBidResponse {
pub owner: String,
pub amount: Option<VaultTokenAmountResponse>,
}

#[skip_serializing_none]
#[derive(Serialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct VaultLiquidatedBatchResponse {
Expand All @@ -588,6 +593,7 @@ pub struct VaultLiquidatedBatchResponse {
froms: Vec<String>,
}

#[skip_serializing_none]
#[derive(Serialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct VaultTokenAmountResponse {
Expand Down
83 changes: 77 additions & 6 deletions lib/ain-ocean/src/api/mod.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
use std::{net::SocketAddr, str::FromStr, sync::Arc};
use std::{net::SocketAddr, str::FromStr, sync::Arc, time::Instant};

use axum::{
body::Body,
extract::{ConnectInfo, Request},
http::{HeaderValue, StatusCode},
middleware::{from_fn, Next},
body::{to_bytes, Body},
extract::{ConnectInfo, OriginalUri, Request},
http::{HeaderMap, HeaderValue, StatusCode},
middleware::{self, from_fn, Next},
response::{IntoResponse, Response},
Json, Router,
};
use log::{debug, log_enabled, trace, Level};

mod address;
mod block;
Expand All @@ -25,12 +26,14 @@ pub mod prices;
mod query;
mod rawtx;
mod response;
mod rpc;
mod stats;
mod tokens;
mod transactions;

use defichain_rpc::Client;
use serde::{Deserialize, Serialize};
use serde_json::json;

use crate::{network::Network, Result, Services};

Expand Down Expand Up @@ -121,6 +124,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 All @@ -132,7 +136,8 @@ pub async fn ocean_router(
format!("/v0/{}", context.network).as_str(),
main_router.merge(debug_router),
)
.layer(from_fn(cors)))
.layer(from_fn(cors))
.layer(middleware::from_fn(logging_middleware)))
}

async fn localhost_only(
Expand Down Expand Up @@ -166,3 +171,69 @@ async fn localhost_only(
Err(StatusCode::FORBIDDEN)
}
}

const MAX_BODY_SIZE: usize = 1024 * 1024 * 16; // 16MB limit for body logging

async fn logging_middleware(
OriginalUri(original_uri): OriginalUri,
req: Request<Body>,
next: Next,
) -> std::result::Result<impl IntoResponse, StatusCode> {
let method = req.method().clone();
let path = req.uri().path().to_owned();
let query = req.uri().query().unwrap_or("").to_owned();

debug!("Request: {} {}", method, path);

if log_enabled!(Level::Trace) {
let headers = format_headers(req.headers());
let request_log = json!({
"method": method.as_str(),
"path": path,
"query": query,
"headers": headers,
"original_uri": original_uri.to_string(),
});
if let Ok(json) = serde_json::to_string(&request_log) {
trace!("Request: {json}");
}
}

let start = Instant::now();
let res = next.run(req).await;
let latency = start.elapsed();

debug!("Response: {} {} {:?}", method, path, latency);

if log_enabled!(Level::Trace) {
let (parts, body) = res.into_parts();
let bytes = to_bytes(body, MAX_BODY_SIZE).await.unwrap_or_default();
let body_str = String::from_utf8_lossy(&bytes);

let response_log = json!({
"status": parts.status.as_u16(),
"headers": format_headers(&parts.headers),
"body": body_str,
});
if let Ok(json) = serde_json::to_string(&response_log) {
trace!("Response: {json}",);
}

Ok(Response::from_parts(parts, Body::from(bytes)))
} else {
Ok(res)
}
}

fn format_headers(headers: &HeaderMap) -> serde_json::Value {
let mut map = serde_json::Map::new();
for (key, value) in headers.iter() {
if let Ok(v) = value.to_str() {
map.insert(
key.as_str().to_owned(),
serde_json::Value::String(v.to_owned()),
);
}
}
serde_json::Value::Object(map)
}
3 changes: 3 additions & 0 deletions lib/ain-ocean/src/api/pool_pair/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ impl From<PoolSwap> for PoolSwapResponse {
}
}

#[skip_serializing_none]
#[derive(Serialize, Debug, Clone, Default)]
#[serde(rename_all = "camelCase")]
struct PoolPairFeeResponse {
Expand All @@ -136,6 +137,7 @@ struct PoolPairFeeResponse {
out_pct: Option<String>,
}

#[skip_serializing_none]
#[derive(Serialize, Debug, Clone, Default)]
#[serde(rename_all = "camelCase")]
struct PoolPairTokenResponse {
Expand Down Expand Up @@ -173,6 +175,7 @@ pub struct PoolPairAprResponse {
pub commission: Decimal,
}

#[skip_serializing_none]
#[derive(Serialize, Debug, Clone, Default)]
#[serde(rename_all = "camelCase")]
pub struct PoolPairResponse {
Expand Down
2 changes: 2 additions & 0 deletions lib/ain-ocean/src/api/prices.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use bitcoin::{hashes::Hash, Txid};
use indexmap::IndexSet;
use rust_decimal::{prelude::ToPrimitive, Decimal};
use serde::{Deserialize, Serialize};
use serde_with::skip_serializing_none;
use snafu::OptionExt;

use super::{
Expand Down Expand Up @@ -352,6 +353,7 @@ async fn get_feed_with_interval(
}))
}

#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct PriceOracleResponse {
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))
}
3 changes: 2 additions & 1 deletion lib/ain-ocean/src/api/tokens.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use defichain_rpc::{
};
use serde::Serialize;
use serde_json::json;
use serde_with::{serde_as, DisplayFromStr};
use serde_with::{serde_as, skip_serializing_none, DisplayFromStr};

use super::{
common::parse_display_symbol,
Expand All @@ -28,6 +28,7 @@ pub struct TxHeight {
height: i64,
}

#[skip_serializing_none]
#[serde_as]
#[derive(Serialize, Debug, Clone, Default)]
#[serde(rename_all = "camelCase")]
Expand Down
3 changes: 3 additions & 0 deletions lib/ain-ocean/src/api/transactions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use ain_macros::ocean_endpoint;
use axum::{extract::Query, routing::get, Extension, Router};
use bitcoin::Txid;
use serde::{Deserialize, Serialize};
use serde_with::skip_serializing_none;

use super::{path::Path, query::PaginationQuery, response::ApiPagedResponse, AppContext};
use crate::{
Expand Down Expand Up @@ -33,6 +34,7 @@ async fn get_transaction(
Ok(Response::new(transactions))
}

#[skip_serializing_none]
#[derive(Debug, Serialize)]
struct TransactionVinResponse {
pub id: String,
Expand Down Expand Up @@ -96,6 +98,7 @@ async fn get_vins(
}))
}

#[skip_serializing_none]
#[derive(Debug, Serialize)]
struct TransactionVoutResponse {
pub id: String,
Expand Down
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
Loading
Loading