diff --git a/docs/api_v2.md b/docs/api_v2.md
index 682d535..456da76 100644
--- a/docs/api_v2.md
+++ b/docs/api_v2.md
@@ -12,7 +12,7 @@
1.1 根据区块号获取区块
-* `GET /api/v2/block/number`
+* `GET /api/v2/number/block`
* 参数
@@ -20,7 +20,7 @@
|-----------|----------|--------------|-----|
| num | number | Y | 区块号 |
-* Request: `http://localhost/api/v2/block/number?num=100`
+* Request: `http://localhost/api/v2/number/block?num=100`
* Response:
```json
{
@@ -67,7 +67,7 @@
1.2 根据区块哈希获取区块
-* `GET /api/v2/block/hash`
+* `GET /api/v2/hash/block`
* 参数
@@ -75,7 +75,7 @@
|-----------|----------|--------------|------|
| hash | string | Y | 区块哈希 |
-* Request: `http://localhost/api/v2/block/hash?hash=E8A4A1F0A6AE1EBAC0D8CA84106985DEFA47240A2AD4E045717CD304B8EDD985`
+* Request: `http://localhost/api/v2/hash/block?hash=E8A4A1F0A6AE1EBAC0D8CA84106985DEFA47240A2AD4E045717CD304B8EDD985`
* Response:
```json
{
diff --git a/explorer/src/config.toml b/explorer/src/config.toml
index 039ec7c..8f5835e 100644
--- a/explorer/src/config.toml
+++ b/explorer/src/config.toml
@@ -4,7 +4,7 @@
[postgres]
account = "postgres"
- password = "csq2400306"
+ password = "12345678"
addr = "localhost"
database = "postgres"
diff --git a/explorer/src/main.rs b/explorer/src/main.rs
index 7798a18..12d635d 100644
--- a/explorer/src/main.rs
+++ b/explorer/src/main.rs
@@ -1,6 +1,7 @@
mod service;
use crate::service::api::Api;
use crate::service::v2::block::{get_block_by_hash, get_block_by_num, get_blocks};
+use crate::service::v2::transaction::get_tx_by_hash;
use anyhow::Result;
use axum::http::Method;
use axum::routing::get;
@@ -9,6 +10,7 @@ use log::info;
use sqlx::pool::PoolOptions;
use sqlx::{PgPool, Pool, Postgres};
use std::sync::Arc;
+use std::time::Duration;
use tower_http::cors::{Any, CorsLayer};
struct AppState {
@@ -29,10 +31,12 @@ async fn main() -> Result<()> {
);
let pool: Pool = PoolOptions::new()
- .max_connections(50)
+ .max_connections(20)
+ .acquire_timeout(Duration::from_secs(5))
.connect(&postgres_config)
.await
- .unwrap();
+ .expect("can't connect to database");
+
info!("Connecting DB...ok");
let app_state = Arc::new(AppState { pool });
@@ -42,9 +46,10 @@ async fn main() -> Result<()> {
.allow_headers(Any);
let addr = format!("{}:{}", config.server.addr, config.server.port);
let app = Router::new()
- .route("/api/v2/block/number", get(get_block_by_num))
- .route("/api/v2/block/hash", get(get_block_by_hash))
+ .route("/api/v2/number/block", get(get_block_by_num))
+ .route("/api/v2/hash/block", get(get_block_by_hash))
.route("/api/v2/blocks", get(get_blocks))
+ .route("/api/v2/hash/tx", get(get_tx_by_hash))
.layer(cors)
.with_state(app_state);
let listener = tokio::net::TcpListener::bind(&addr).await.unwrap();
diff --git a/explorer/src/service/v2/block.rs b/explorer/src/service/v2/block.rs
index 037e235..3377cdd 100644
--- a/explorer/src/service/v2/block.rs
+++ b/explorer/src/service/v2/block.rs
@@ -1,16 +1,15 @@
+use crate::service::v2::error::internal_error;
+use crate::service::v2::error::Result;
+use crate::service::v2::{BlockResponse, QueryResult};
use crate::AppState;
use axum::extract::{Query, State};
use axum::Json;
-
use module::rpc::block::BlockRPC;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use sqlx::Row;
use std::sync::Arc;
-use crate::service::v2::error::Result;
-use crate::service::v2::{BlockResponse, QueryResult};
-
#[derive(Serialize, Deserialize, Debug)]
pub struct GetBlockByHeightParams {
pub num: i64,
@@ -20,22 +19,23 @@ pub async fn get_block_by_num(
State(state): State>,
Query(params): Query,
) -> Result> {
- let mut pool = state.pool.acquire().await?;
+ let mut pool = 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 sql_query = r#"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(params.num)
.fetch_one(&mut *pool)
- .await?;
-
- let block_hash: String = row.try_get("block_hash")?;
- let block_num: i64 = row.try_get("height")?;
- let app_hash: String = row.try_get("app_hash")?;
- let proposer: String = row.try_get("proposer")?;
- let block_size: i64 = row.try_get("size")?;
- let num_txs: i64 = row.try_get("tx_count")?;
- let block_data: Value = row.try_get("block_data")?;
- let block_rpc: BlockRPC = serde_json::from_value(block_data)?;
+ .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)?;
Ok(Json(BlockResponse {
block_hash,
@@ -58,22 +58,25 @@ pub async fn get_block_by_hash(
State(state): State>,
Query(params): Query,
) -> Result> {
- let mut pool = state.pool.acquire().await?;
+ let mut pool = 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 sql_query = "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(params.hash.to_uppercase())
.fetch_one(&mut *pool)
- .await?;
-
- let block_hash: String = row.try_get("block_hash")?;
- let block_num: i64 = row.try_get("height")?;
- let app_hash: String = row.try_get("app_hash")?;
- let proposer: String = row.try_get("proposer")?;
- let block_size: i64 = row.try_get("size")?;
- let num_txs: i64 = row.try_get("tx_count")?;
- let block_data: Value = row.try_get("block_data")?;
- let block_rpc: BlockRPC = serde_json::from_value(block_data)?;
+ .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)?;
Ok(Json(BlockResponse {
block_hash,
@@ -97,31 +100,37 @@ pub async fn get_blocks(
State(state): State>,
Query(params): Query,
) -> Result>>> {
- let mut pool = state.pool.acquire().await?;
+ let mut pool = state.pool.acquire().await.map_err(internal_error)?;
let page = params.page.unwrap_or(1);
let page_size = params.page_size.unwrap_or(10);
let sql_total = "SELECT max(height) FROM block";
- let row = sqlx::query(sql_total).fetch_one(&mut *pool).await?;
- let total = row.try_get("max")?;
+ let row = sqlx::query(sql_total)
+ .fetch_one(&mut *pool)
+ .await
+ .map_err(internal_error)?;
+ let total = row.try_get("max").map_err(internal_error)?;
+
+ let sql_query = r#"SELECT block_hash,height,size,tx_count,time,app_hash,proposer,block_data
+ FROM block ORDER BY height DESC LIMIT $1 OFFSET $2"#;
- let sql_query = "SELECT block_hash,height,size,tx_count,time,app_hash,proposer,block_data FROM block ORDER BY height DESC LIMIT $1 OFFSET $2";
let rows = sqlx::query(sql_query)
.bind(page_size)
.bind((page - 1) * page_size)
.fetch_all(&mut *pool)
- .await?;
+ .await
+ .map_err(internal_error)?;
let mut blocks: Vec = vec![];
for row in rows {
- let block_hash: String = row.try_get("block_hash")?;
- let block_num: i64 = row.try_get("height")?;
- let app_hash: String = row.try_get("app_hash")?;
- let proposer: String = row.try_get("proposer")?;
- let block_size: i64 = row.try_get("size")?;
- let num_txs: i64 = row.try_get("tx_count")?;
- let block_data: Value = row.try_get("block_data")?;
- let block_rpc: BlockRPC = serde_json::from_value(block_data)?;
+ 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)?;
blocks.push(BlockResponse {
block_hash,
diff --git a/explorer/src/service/v2/error.rs b/explorer/src/service/v2/error.rs
index eccaa06..fb888eb 100644
--- a/explorer/src/service/v2/error.rs
+++ b/explorer/src/service/v2/error.rs
@@ -1,73 +1,10 @@
use axum::http::StatusCode;
-use axum::response::{IntoResponse, Response};
-#[derive(Debug)]
-pub enum ExplorerError {
- Custom(String),
- DBError(sqlx::Error),
- IOError(std::io::Error),
- TomlDeError(toml::de::Error),
- HexError(rustc_hex::FromHexError),
- ParseUrlError(url::ParseError),
- SerdeError(serde_json::Error),
-}
-
-impl From for ExplorerError {
- fn from(e: serde_json::Error) -> Self {
- ExplorerError::SerdeError(e)
- }
-}
-
-impl From for ExplorerError {
- fn from(e: String) -> Self {
- ExplorerError::Custom(e)
- }
-}
-
-impl From for ExplorerError {
- fn from(e: url::ParseError) -> Self {
- ExplorerError::ParseUrlError(e)
- }
-}
-
-impl From for ExplorerError {
- fn from(e: rustc_hex::FromHexError) -> Self {
- ExplorerError::HexError(e)
- }
-}
-
-impl From for ExplorerError {
- fn from(e: std::io::Error) -> Self {
- ExplorerError::IOError(e)
- }
-}
-
-impl From for ExplorerError {
- fn from(e: toml::de::Error) -> Self {
- ExplorerError::TomlDeError(e)
- }
-}
-
-impl From for ExplorerError {
- fn from(e: sqlx::Error) -> Self {
- ExplorerError::DBError(e)
- }
-}
-
-pub type Result = core::result::Result;
-
-impl IntoResponse for ExplorerError {
- fn into_response(self) -> Response {
- let err_msg = match self {
- ExplorerError::Custom(e) => e,
- ExplorerError::DBError(e) => e.to_string(),
- ExplorerError::IOError(e) => e.to_string(),
- ExplorerError::TomlDeError(e) => e.to_string(),
- ExplorerError::HexError(e) => e.to_string(),
- ExplorerError::ParseUrlError(e) => e.to_string(),
- ExplorerError::SerdeError(e) => e.to_string(),
- };
+pub type Result = core::result::Result;
- (StatusCode::INTERNAL_SERVER_ERROR, err_msg).into_response()
- }
+pub fn internal_error(err: E) -> (StatusCode, String)
+where
+ E: std::error::Error,
+{
+ (StatusCode::INTERNAL_SERVER_ERROR, err.to_string())
}
diff --git a/explorer/src/service/v2/mod.rs b/explorer/src/service/v2/mod.rs
index 79d63e0..d020a93 100644
--- a/explorer/src/service/v2/mod.rs
+++ b/explorer/src/service/v2/mod.rs
@@ -39,6 +39,7 @@ pub struct QueryResult {
pub page_size: i32,
pub data: T,
}
+
#[derive(Serialize, Deserialize, Debug)]
pub struct BlockResponse {
pub block_hash: String,
diff --git a/explorer/src/service/v2/transaction.rs b/explorer/src/service/v2/transaction.rs
index 7715fe2..6f0bba8 100644
--- a/explorer/src/service/v2/transaction.rs
+++ b/explorer/src/service/v2/transaction.rs
@@ -1,118 +1,58 @@
-use crate::service::v1::transaction::{TxsData, TxsRes, TxsResponse};
-use crate::Api;
-use anyhow::Result;
-use log::debug;
+use crate::service::v2::error::internal_error;
+use crate::service::v2::error::Result;
+use crate::AppState;
+use axum::extract::{Query, State};
+use axum::Json;
use module::schema::TransactionResponse;
-use poem_openapi::param::Query;
-use poem_openapi::payload::Json;
+use serde::{Deserialize, Serialize};
use serde_json::Value;
use sqlx::Row;
-use std::ops::Add;
-#[allow(dead_code)]
-#[allow(clippy::too_many_arguments)]
-pub async fn v2_get_txs(
- api: &Api,
- block_hash: Query