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

Optimize: get tx by hash. #248

Merged
merged 1 commit into from
Apr 7, 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
8 changes: 4 additions & 4 deletions docs/api_v2.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@

<h3 id="1.1">1.1 根据区块号获取区块</h3>

* `GET /api/v2/block/number`
* `GET /api/v2/number/block`

* 参数

| 参数(param) | 类型(type) | 必传(required) | 说明 |
|-----------|----------|--------------|-----|
| num | number | Y | 区块号 |

* Request: `http://localhost/api/v2/block/number?num=100`
* Request: `http://localhost/api/v2/number/block?num=100`
* Response:
```json
{
Expand Down Expand Up @@ -67,15 +67,15 @@

<h3 id="1.2">1.2 根据区块哈希获取区块</h3>

* `GET /api/v2/block/hash`
* `GET /api/v2/hash/block`

* 参数

| 参数(param) | 类型(type) | 必传(required) | 说明 |
|-----------|----------|--------------|------|
| hash | string | Y | 区块哈希 |

* Request: `http://localhost/api/v2/block/hash?hash=E8A4A1F0A6AE1EBAC0D8CA84106985DEFA47240A2AD4E045717CD304B8EDD985`
* Request: `http://localhost/api/v2/hash/block?hash=E8A4A1F0A6AE1EBAC0D8CA84106985DEFA47240A2AD4E045717CD304B8EDD985`
* Response:
```json
{
Expand Down
2 changes: 1 addition & 1 deletion explorer/src/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

[postgres]
account = "postgres"
password = "csq2400306"
password = "12345678"
addr = "localhost"
database = "postgres"

Expand Down
13 changes: 9 additions & 4 deletions explorer/src/main.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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 {
Expand All @@ -29,10 +31,12 @@ async fn main() -> Result<()> {
);

let pool: Pool<Postgres> = 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 });
Expand All @@ -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();
Expand Down
91 changes: 50 additions & 41 deletions explorer/src/service/v2/block.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -20,22 +19,23 @@ pub async fn get_block_by_num(
State(state): State<Arc<AppState>>,
Query(params): Query<GetBlockByHeightParams>,
) -> Result<Json<BlockResponse>> {
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,
Expand All @@ -58,22 +58,25 @@ pub async fn get_block_by_hash(
State(state): State<Arc<AppState>>,
Query(params): Query<GetBlockByHashParams>,
) -> Result<Json<BlockResponse>> {
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,
Expand All @@ -97,31 +100,37 @@ pub async fn get_blocks(
State(state): State<Arc<AppState>>,
Query(params): Query<GetBlocksParams>,
) -> Result<Json<QueryResult<Vec<BlockResponse>>>> {
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<BlockResponse> = 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,
Expand Down
75 changes: 6 additions & 69 deletions explorer/src/service/v2/error.rs
Original file line number Diff line number Diff line change
@@ -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<serde_json::Error> for ExplorerError {
fn from(e: serde_json::Error) -> Self {
ExplorerError::SerdeError(e)
}
}

impl From<String> for ExplorerError {
fn from(e: String) -> Self {
ExplorerError::Custom(e)
}
}

impl From<url::ParseError> for ExplorerError {
fn from(e: url::ParseError) -> Self {
ExplorerError::ParseUrlError(e)
}
}

impl From<rustc_hex::FromHexError> for ExplorerError {
fn from(e: rustc_hex::FromHexError) -> Self {
ExplorerError::HexError(e)
}
}

impl From<std::io::Error> for ExplorerError {
fn from(e: std::io::Error) -> Self {
ExplorerError::IOError(e)
}
}

impl From<toml::de::Error> for ExplorerError {
fn from(e: toml::de::Error) -> Self {
ExplorerError::TomlDeError(e)
}
}

impl From<sqlx::Error> for ExplorerError {
fn from(e: sqlx::Error) -> Self {
ExplorerError::DBError(e)
}
}

pub type Result<T> = core::result::Result<T, ExplorerError>;

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<T> = core::result::Result<T, (StatusCode, String)>;

(StatusCode::INTERNAL_SERVER_ERROR, err_msg).into_response()
}
pub fn internal_error<E>(err: E) -> (StatusCode, String)
where
E: std::error::Error,
{
(StatusCode::INTERNAL_SERVER_ERROR, err.to_string())
}
1 change: 1 addition & 0 deletions explorer/src/service/v2/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ pub struct QueryResult<T> {
pub page_size: i32,
pub data: T,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct BlockResponse {
pub block_hash: String,
Expand Down
Loading
Loading