Skip to content

Commit ec48975

Browse files
authored
Add /debug/dumptables endpoint (#3049)
1 parent 6f581bc commit ec48975

3 files changed

Lines changed: 82 additions & 26 deletions

File tree

lib/ain-ocean/src/api/debug.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
use ain_macros::ocean_endpoint;
2+
use axum::{routing::get, Extension, Router};
3+
use std::sync::Arc;
4+
5+
use super::AppContext;
6+
use crate::{error::ApiError, Result};
7+
8+
#[ocean_endpoint]
9+
async fn dump_tables(Extension(ctx): Extension<Arc<AppContext>>) -> Result<()> {
10+
ctx.services.store.dump_table_sizes()
11+
}
12+
13+
pub fn router(ctx: Arc<AppContext>) -> Router {
14+
Router::new()
15+
.route("/dumptables", get(dump_tables))
16+
.layer(Extension(ctx))
17+
}

lib/ain-ocean/src/api/mod.rs

Lines changed: 61 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
use std::{str::FromStr, sync::Arc};
1+
use std::{net::SocketAddr, str::FromStr, sync::Arc};
22

33
use axum::{
4-
extract::Request,
4+
body::Body,
5+
extract::{ConnectInfo, Request},
56
http::{HeaderValue, StatusCode},
67
middleware::{from_fn, Next},
78
response::{IntoResponse, Response},
@@ -12,6 +13,7 @@ mod address;
1213
mod block;
1314
mod cache;
1415
pub mod common;
16+
mod debug;
1517
mod fee;
1618
mod governance;
1719
mod loan;
@@ -105,24 +107,62 @@ pub async fn ocean_router(
105107
services: services.clone(),
106108
network: Network::from_str(&network)?,
107109
});
110+
let main_router = Router::new()
111+
.nest("/address/", address::router(Arc::clone(&context)))
112+
.nest("/governance", governance::router(Arc::clone(&context)))
113+
.nest("/loans", loan::router(Arc::clone(&context)))
114+
.nest("/fee", fee::router(Arc::clone(&context)))
115+
.nest("/masternodes", masternode::router(Arc::clone(&context)))
116+
.nest("/oracles", oracle::router(Arc::clone(&context)))
117+
.nest("/poolpairs", pool_pair::router(Arc::clone(&context)))
118+
.nest("/prices", prices::router(Arc::clone(&context)))
119+
.nest("/rawtx", rawtx::router(Arc::clone(&context)))
120+
.nest("/stats", stats::router(Arc::clone(&context)))
121+
.nest("/tokens", tokens::router(Arc::clone(&context)))
122+
.nest("/transactions", transactions::router(Arc::clone(&context)))
123+
.nest("/blocks", block::router(Arc::clone(&context)))
124+
.fallback(not_found);
108125

109-
Ok(Router::new().nest(
110-
format!("/v0/{}", context.network).as_str(),
111-
Router::new()
112-
.nest("/address/", address::router(Arc::clone(&context)))
113-
.nest("/governance", governance::router(Arc::clone(&context)))
114-
.nest("/loans", loan::router(Arc::clone(&context)))
115-
.nest("/fee", fee::router(Arc::clone(&context)))
116-
.nest("/masternodes", masternode::router(Arc::clone(&context)))
117-
.nest("/oracles", oracle::router(Arc::clone(&context)))
118-
.nest("/poolpairs", pool_pair::router(Arc::clone(&context)))
119-
.nest("/prices", prices::router(Arc::clone(&context)))
120-
.nest("/rawtx", rawtx::router(Arc::clone(&context)))
121-
.nest("/stats", stats::router(Arc::clone(&context)))
122-
.nest("/tokens", tokens::router(Arc::clone(&context)))
123-
.nest("/transactions", transactions::router(Arc::clone(&context)))
124-
.nest("/blocks", block::router(Arc::clone(&context)))
125-
.fallback(not_found)
126-
.layer(from_fn(cors)), // NOTE(canonbrother): the `layer()` calls work in reverse order, hence cors layer must be at bottom
127-
))
126+
let debug_router = Router::new()
127+
.nest("/debug", debug::router(Arc::clone(&context)))
128+
.layer(from_fn(localhost_only));
129+
130+
Ok(Router::new()
131+
.nest(
132+
format!("/v0/{}", context.network).as_str(),
133+
main_router.merge(debug_router),
134+
)
135+
.layer(from_fn(cors)))
136+
}
137+
138+
async fn localhost_only(
139+
req: Request<Body>,
140+
next: Next,
141+
) -> std::result::Result<Response, StatusCode> {
142+
let is_localhost = req
143+
.extensions()
144+
.get::<ConnectInfo<SocketAddr>>()
145+
.map(|connect_info| connect_info.ip().is_loopback())
146+
.unwrap_or_else(|| {
147+
req.headers()
148+
.get("X-Forwarded-For")
149+
.and_then(|addr| addr.to_str().ok())
150+
.map(|addr| addr.split(',').next().unwrap_or("").trim() == "127.0.0.1")
151+
.or_else(|| {
152+
req.headers()
153+
.get("Host")
154+
.and_then(|host| host.to_str().ok())
155+
.map(|host| {
156+
host.starts_with("localhost:") || host.starts_with("127.0.0.1:")
157+
})
158+
})
159+
.unwrap_or(false)
160+
});
161+
162+
if is_localhost {
163+
Ok(next.run(req).await)
164+
} else {
165+
println!("Access denied: Request is not from localhost");
166+
Err(StatusCode::FORBIDDEN)
167+
}
128168
}

lib/ain-ocean/src/storage/ocean_store.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use ain_db::{Column, ColumnName, LedgerColumn, Rocks};
2-
use log::debug;
32
use rocksdb::{BlockBasedOptions, Cache, Options, SliceTransform};
43
use std::{fs, marker::PhantomData, path::Path, sync::Arc};
54

@@ -73,10 +72,6 @@ impl OceanStore {
7372
.collect::<Vec<_>>();
7473

7574
let backend = Arc::new(Rocks::open(&path, cf_with_opts, None)?);
76-
debug!("Dumping table size");
77-
if let Err(e) = backend.dump_table_sizes(&COLUMN_NAMES) {
78-
debug!("e dumping {e}");
79-
}
8075

8176
Ok(Self(backend))
8277
}
@@ -91,6 +86,10 @@ impl OceanStore {
9186
}
9287
}
9388

89+
pub fn dump_table_sizes(&self) -> Result<()> {
90+
Ok(self.0.dump_table_sizes(&COLUMN_NAMES)?)
91+
}
92+
9493
pub fn compact(&self) {
9594
self.0.compact();
9695
}

0 commit comments

Comments
 (0)