diff --git a/explorer/src/main.rs b/explorer/src/main.rs index b3e3fe2..a988696 100644 --- a/explorer/src/main.rs +++ b/explorer/src/main.rs @@ -1,7 +1,10 @@ mod service; use crate::service::api::Api; use crate::service::v2::asset::get_assets; -use crate::service::v2::block::{get_block_by_hash, get_block_by_num, get_blocks}; +use crate::service::v2::block::{ + get_block_by_hash, get_block_by_num, get_blocks, get_full_block_by_hash, + get_full_block_by_height, get_simple_block_by_hash, get_simple_block_by_height, +}; use crate::service::v2::claim::{get_claim_by_tx_hash, get_claims}; use crate::service::v2::delegation::{get_delegation_by_tx_hash, get_delegations}; use crate::service::v2::other::{get_address_count, get_statistics, get_tx_distribute}; @@ -53,6 +56,10 @@ async fn main() -> Result<()> { .allow_headers(Any); let addr = format!("{}:{}", config.server.addr, config.server.port); let app = Router::new() + .route("/api/block/hash/:hash", get(get_simple_block_by_hash)) + .route("/api/block/full/hash/:hash", get(get_full_block_by_hash)) + .route("/api/block/height/:num", get(get_simple_block_by_height)) + .route("/api/block/full/height/:num", get(get_full_block_by_height)) .route("/api/address/count", get(get_address_count)) .route("/api/chain/statistics", get(get_statistics)) .route("/api/txs/distribute", get(get_tx_distribute)) diff --git a/explorer/src/service/mod.rs b/explorer/src/service/mod.rs index ce8a7bf..7f176cb 100644 --- a/explorer/src/service/mod.rs +++ b/explorer/src/service/mod.rs @@ -1,4 +1,5 @@ use poem_openapi::Tags; +use serde::{Deserialize, Serialize}; pub mod api; pub mod error; @@ -24,3 +25,11 @@ enum ApiTags { /// Operations about staking Staking, } + +#[derive(Serialize, Deserialize, Debug)] +pub struct QueryResult { + pub total: i64, + pub page: i32, + pub page_size: i32, + pub data: T, +} diff --git a/explorer/src/service/v1/block.rs b/explorer/src/service/v1/block.rs index d1b03cd..f21f4f1 100644 --- a/explorer/src/service/v1/block.rs +++ b/explorer/src/service/v1/block.rs @@ -75,9 +75,9 @@ pub struct BlocksData { blocks: Vec, } -/// return full block by given height. +/// return full block by given height.a #[allow(dead_code)] -pub async fn get_full_block_by_height(api: &Api, height: Path) -> Result { +async fn get_full_block_by_height(api: &Api, height: Path) -> Result { let mut conn = api.storage.lock().await.acquire().await?; let str = format!("SELECT * FROM block WHERE height = {}", height.0); @@ -116,10 +116,7 @@ pub async fn get_full_block_by_height(api: &Api, height: Path) -> Result, -) -> Result { +async fn get_simple_block_by_height(api: &Api, height: Path) -> Result { let mut conn = api.storage.lock().await.acquire().await?; let str = format!("SELECT * FROM block WHERE height = {}", height.0); @@ -169,7 +166,7 @@ pub async fn get_simple_block_by_height( /// return full block by given block hash. #[allow(dead_code)] -pub async fn get_full_block_by_hash(api: &Api, hash: Path) -> Result { +async fn get_full_block_by_hash(api: &Api, hash: Path) -> Result { let mut conn = api.storage.lock().await.acquire().await?; let str = format!( @@ -193,10 +190,7 @@ pub async fn get_full_block_by_hash(api: &Api, hash: Path) -> Result, -) -> Result { +async fn get_simple_block_by_hash(api: &Api, hash: Path) -> Result { let mut conn = api.storage.lock().await.acquire().await?; let str = format!( @@ -232,7 +226,7 @@ pub async fn get_simple_block_by_hash( /// return simple blocks. #[allow(dead_code)] -pub async fn get_blocks( +async fn get_blocks( api: &Api, start_height: Query>, end_height: Query>, diff --git a/explorer/src/service/v2/asset.rs b/explorer/src/service/v2/asset.rs index 40aecf7..52872e9 100644 --- a/explorer/src/service/v2/asset.rs +++ b/explorer/src/service/v2/asset.rs @@ -1,5 +1,5 @@ use crate::service::error::{internal_error, Result}; -use crate::service::v2::QueryResult; +use crate::service::QueryResult; use crate::AppState; use axum::extract::{Query, State}; use axum::Json; diff --git a/explorer/src/service/v2/block.rs b/explorer/src/service/v2/block.rs index 4584252..9deefc0 100644 --- a/explorer/src/service/v2/block.rs +++ b/explorer/src/service/v2/block.rs @@ -1,9 +1,9 @@ use crate::service::error::{internal_error, Result}; -use crate::service::v2::QueryResult; +use crate::service::QueryResult; use crate::AppState; -use axum::extract::{Query, State}; +use axum::extract::{Path, Query, State}; use axum::Json; -use module::rpc::block::{BlockHeader, BlockId, BlockRPC}; +use module::rpc::block::{Block, BlockHeader, BlockId, BlockRPC}; use serde::{Deserialize, Serialize}; use serde_json::Value; use sqlx::Row; @@ -21,6 +21,127 @@ pub struct BlockResponse { pub block_header: BlockHeader, } +#[derive(Serialize, Deserialize, Debug)] +pub struct FullBlockResponse { + pub block_id: BlockId, + pub block: Block, +} + +pub async fn get_full_block_by_height( + State(state): State>, + Path(num): Path, +) -> Result> { + let mut conn = state.pool.acquire().await.map_err(internal_error)?; + + let sql_query = r#"SELECT block_data FROM block WHERE height=$1"#; + let row = sqlx::query(sql_query) + .bind(num) + .fetch_one(&mut *conn) + .await + .map_err(internal_error)?; + let block_data = row.try_get("block_data").map_err(internal_error)?; + let block_rpc: BlockRPC = serde_json::from_value(block_data).map_err(internal_error)?; + let full_block = FullBlockResponse { + block_id: block_rpc.block_id, + block: block_rpc.block, + }; + + Ok(Json(full_block)) +} + +pub async fn get_simple_block_by_height( + State(state): State>, + Path(num): Path, +) -> Result> { + let mut conn = state.pool.acquire().await.map_err(internal_error)?; + + let sql_query = + "SELECT block_hash,height,size,tx_count,time,app_hash,proposer,block_data FROM block WHERE height=$1"; + let row = sqlx::query(sql_query) + .bind(num) + .fetch_one(&mut *conn) + .await + .map_err(internal_error)?; + + let block_hash: String = row.try_get("block_hash").map_err(internal_error)?; + let block_num: i64 = row.try_get("height").map_err(internal_error)?; + let app_hash: String = row.try_get("app_hash").map_err(internal_error)?; + let proposer: String = row.try_get("proposer").map_err(internal_error)?; + let block_size: i64 = row.try_get("size").map_err(internal_error)?; + let num_txs: i64 = row.try_get("tx_count").map_err(internal_error)?; + let block_data: Value = row.try_get("block_data").map_err(internal_error)?; + let block_rpc: BlockRPC = serde_json::from_value(block_data).map_err(internal_error)?; + + let block = BlockResponse { + block_hash, + num_txs, + block_size, + app_hash, + proposer, + block_id: block_rpc.block_id, + block_header: block_rpc.block.header, + block_num, + }; + + Ok(Json(block)) +} + +pub async fn get_full_block_by_hash( + State(state): State>, + Path(hash): Path, +) -> Result> { + let mut conn = state.pool.acquire().await.map_err(internal_error)?; + + let sql_query = "SELECT block_data FROM block WHERE block_hash=$1"; + let row = sqlx::query(sql_query) + .bind(hash) + .fetch_one(&mut *conn) + .await + .map_err(internal_error)?; + let block_data = row.try_get("block_data").map_err(internal_error)?; + let block_rpc: BlockRPC = serde_json::from_value(block_data).map_err(internal_error)?; + let full_block = FullBlockResponse { + block_id: block_rpc.block_id, + block: block_rpc.block, + }; + + Ok(Json(full_block)) +} + +pub async fn get_simple_block_by_hash( + State(state): State>, + Path(hash): Path, +) -> Result> { + let mut conn = state.pool.acquire().await.map_err(internal_error)?; + + let sql_query = r#"SELECT block_hash,height,size,tx_count,time,app_hash,proposer,block_data FROM block WHERE block_hash=$1"#; + let row = sqlx::query(sql_query) + .bind(hash) + .fetch_one(&mut *conn) + .await + .map_err(internal_error)?; + let block_hash: String = row.try_get("block_hash").map_err(internal_error)?; + let block_num: i64 = row.try_get("height").map_err(internal_error)?; + let app_hash: String = row.try_get("app_hash").map_err(internal_error)?; + let proposer: String = row.try_get("proposer").map_err(internal_error)?; + let block_size: i64 = row.try_get("size").map_err(internal_error)?; + let num_txs: i64 = row.try_get("tx_count").map_err(internal_error)?; + let block_data: Value = row.try_get("block_data").map_err(internal_error)?; + let block_rpc: BlockRPC = serde_json::from_value(block_data).map_err(internal_error)?; + let block = BlockResponse { + block_hash, + num_txs, + block_size, + app_hash, + proposer, + block_id: block_rpc.block_id, + block_header: block_rpc.block.header, + block_num, + }; + + Ok(Json(block)) +} + #[derive(Serialize, Deserialize, Debug)] pub struct GetBlockByHeightParams { pub num: i64, diff --git a/explorer/src/service/v2/claim.rs b/explorer/src/service/v2/claim.rs index 2046043..71935b9 100644 --- a/explorer/src/service/v2/claim.rs +++ b/explorer/src/service/v2/claim.rs @@ -1,5 +1,5 @@ use crate::service::error::{internal_error, Result}; -use crate::service::v2::QueryResult; +use crate::service::QueryResult; use crate::AppState; use axum::extract::{Query, State}; use axum::Json; diff --git a/explorer/src/service/v2/delegation.rs b/explorer/src/service/v2/delegation.rs index 8faa843..13aa280 100644 --- a/explorer/src/service/v2/delegation.rs +++ b/explorer/src/service/v2/delegation.rs @@ -1,5 +1,5 @@ use crate::service::error::{internal_error, Result}; -use crate::service::v2::QueryResult; +use crate::service::QueryResult; use crate::AppState; use axum::extract::{Query, State}; use axum::Json; diff --git a/explorer/src/service/v2/mod.rs b/explorer/src/service/v2/mod.rs index 1cb9bc9..acd918a 100644 --- a/explorer/src/service/v2/mod.rs +++ b/explorer/src/service/v2/mod.rs @@ -29,11 +29,3 @@ pub enum TransactionType { DefineAsset, IssueAsset, } - -#[derive(Serialize, Deserialize, Debug)] -pub struct QueryResult { - pub total: i64, - pub page: i32, - pub page_size: i32, - pub data: T, -} diff --git a/explorer/src/service/v2/prism_evm_to_native.rs b/explorer/src/service/v2/prism_evm_to_native.rs index de920d5..bd6ba5f 100644 --- a/explorer/src/service/v2/prism_evm_to_native.rs +++ b/explorer/src/service/v2/prism_evm_to_native.rs @@ -1,5 +1,5 @@ use crate::service::error::{internal_error, Result}; -use crate::service::v2::QueryResult; +use crate::service::QueryResult; use crate::AppState; use axum::extract::{Query, State}; use axum::Json; diff --git a/explorer/src/service/v2/prism_native_to_evm.rs b/explorer/src/service/v2/prism_native_to_evm.rs index be662fa..a4e15fa 100644 --- a/explorer/src/service/v2/prism_native_to_evm.rs +++ b/explorer/src/service/v2/prism_native_to_evm.rs @@ -1,5 +1,5 @@ use crate::service::error::{internal_error, Result}; -use crate::service::v2::QueryResult; +use crate::service::QueryResult; use crate::AppState; use axum::extract::{Query, State}; use axum::Json; diff --git a/explorer/src/service/v2/transaction.rs b/explorer/src/service/v2/transaction.rs index 075a34e..b461486 100644 --- a/explorer/src/service/v2/transaction.rs +++ b/explorer/src/service/v2/transaction.rs @@ -1,5 +1,5 @@ use crate::service::error::{internal_error, Result}; -use crate::service::v2::QueryResult; +use crate::service::QueryResult; use crate::AppState; use axum::extract::{Query, State}; use axum::Json; diff --git a/explorer/src/service/v2/undelegation.rs b/explorer/src/service/v2/undelegation.rs index 607ffc0..921cb8c 100644 --- a/explorer/src/service/v2/undelegation.rs +++ b/explorer/src/service/v2/undelegation.rs @@ -1,5 +1,5 @@ use crate::service::error::{internal_error, Result}; -use crate::service::v2::QueryResult; +use crate::service::QueryResult; use crate::AppState; use axum::extract::{Query, State}; use axum::Json;