Skip to content
This repository has been archived by the owner on Jun 19, 2024. It is now read-only.

Commit

Permalink
feat: get latest blocks with only one sql query (#203)
Browse files Browse the repository at this point in the history
With this PR we optimize the SQL query to get the lastest blocks and
with the transactions hash and type.
  • Loading branch information
rllola authored Apr 24, 2024
1 parent 0e84ce7 commit f8b68b0
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 52 deletions.
17 changes: 6 additions & 11 deletions src/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1084,11 +1084,8 @@ impl Database {

#[instrument(skip(self, block_id))]
pub async fn block_by_id(&self, block_id: &[u8]) -> Result<Option<Row>, Error> {
// query for the block if it exists
let str = format!(
"SELECT * FROM {}.{BLOCKS_TABLE_NAME} WHERE block_id=$1",
self.network
);
let str = format!("SELECT b.*, txs FROM {0}.blocks b LEFT JOIN (SELECT block_id, JSON_AGG(JSON_BUILD_OBJECT('hash_id', encode(t.hash, 'hex'), 'tx_type', t.tx_type)) AS txs FROM {0}.transactions t GROUP BY t.block_id) t ON b.block_id = t.block_id WHERE b.block_id = $1;", self.network);

query(&str)
.bind(block_id)
.fetch_optional(&*self.pool)
Expand All @@ -1099,12 +1096,10 @@ impl Database {
/// Returns the block at `block_height` if present, otherwise returns an Error.
#[instrument(skip(self))]
pub async fn block_by_height(&self, block_height: u32) -> Result<Option<Row>, Error> {
let str = format!(
"SELECT * FROM {}.{BLOCKS_TABLE_NAME} WHERE header_height={block_height}",
self.network
);
let str = format!("SELECT b.*, txs FROM {0}.blocks b LEFT JOIN (SELECT block_id, JSON_AGG(JSON_BUILD_OBJECT('hash_id', encode(t.hash, 'hex'), 'tx_type', t.tx_type)) AS txs FROM {0}.transactions t GROUP BY t.block_id) t ON b.block_id = t.block_id WHERE b.header_height = $1;", self.network);

query(&str)
.bind(block_height as i32)
.fetch_optional(&*self.pool)
.await
.map_err(Error::from)
Expand All @@ -1113,7 +1108,7 @@ impl Database {
#[instrument(skip(self))]
/// Returns the latest block, otherwise returns an Error.
pub async fn get_last_block(&self) -> Result<Row, Error> {
let str = format!("SELECT * FROM {0}.{BLOCKS_TABLE_NAME} WHERE header_height = (SELECT MAX(header_height) FROM {0}.{BLOCKS_TABLE_NAME})", self.network);
let str = format!("SELECT b.*, txs FROM {0}.blocks b LEFT JOIN (SELECT block_id, JSON_AGG(JSON_BUILD_OBJECT('hash_id', encode(t.hash, 'hex'), 'tx_type', t.tx_type)) AS txs FROM {0}.transactions t GROUP BY t.block_id) t ON b.block_id = t.block_id WHERE b.header_height = (SELECT MAX(header_height) FROM {0}.blocks);", self.network);

// use query_one as the row matching max height is unique.
query(&str)
Expand Down Expand Up @@ -1406,7 +1401,7 @@ impl Database {
num: &i32,
offset: Option<&i32>,
) -> Result<Vec<Row>, Error> {
let str = format!("SELECT * FROM {0}.{BLOCKS_TABLE_NAME} ORDER BY header_height DESC LIMIT {1} OFFSET {2};", self.network, num, offset.unwrap_or(& 0));
let str = format!("SELECT b.*, t.txs FROM {0}.blocks b LEFT JOIN (SELECT block_id, JSON_AGG(JSON_BUILD_OBJECT('hash_id', encode(t.hash, 'hex'), 'tx_type', t.tx_type)) AS txs FROM {0}.transactions t GROUP BY t.block_id) t ON b.block_id = t.block_id ORDER BY b.header_height DESC LIMIT {1} OFFSET {2};", self.network, num, offset.unwrap_or(& 0));

// use query_one as the row matching max height is unique.
query(&str)
Expand Down
10 changes: 9 additions & 1 deletion src/server/blocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,14 @@ impl TryFrom<&Row> for BlockInfo {

let last_commit = LastCommitInfo::read_from(row)?;

// tx hashes
let txs: Option<serde_json::Value> = row.try_get("txs")?;
let tx_hashes: Vec<TxShort> = if let Some(txs) = txs {
serde_json::from_value(txs)?
} else {
vec![]
};

let header = Header {
version,
chain_id,
Expand All @@ -241,7 +249,7 @@ impl TryFrom<&Row> for BlockInfo {
block_id: HashID(block_id),
header,
last_commit,
tx_hashes: vec![],
tx_hashes,
})
}
}
45 changes: 5 additions & 40 deletions src/server/endpoints/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,10 @@ use axum::{
Json,
};
use serde::{Deserialize, Serialize};
use sqlx::Row as TRow;
use std::collections::HashMap;
use tracing::info;

use crate::{
server::{blocks::HashID, blocks::TxShort, ServerState},
BlockInfo, Error,
};
use crate::{server::ServerState, BlockInfo, Error};

#[derive(Debug, Serialize, Deserialize, PartialEq)]
#[serde(untagged)]
Expand All @@ -24,25 +20,6 @@ pub struct LatestBlocks {
pub blocks: Vec<BlockInfo>,
}

async fn get_tx_hashes(
state: &ServerState,
block: &mut BlockInfo,
hash: &[u8],
) -> Result<(), Error> {
let rows = state.db.get_tx_hashes_block(hash).await?;

let mut tx_hashes: Vec<TxShort> = vec![];
for row in rows.iter() {
let hash_id = HashID(row.try_get("hash")?);
let tx_type: String = row.try_get("tx_type")?;
tx_hashes.push(TxShort { tx_type, hash_id });
}

block.tx_hashes = tx_hashes;

Ok(())
}

pub async fn get_block_by_hash(
State(state): State<ServerState>,
Path(hash): Path<String>,
Expand All @@ -55,10 +32,7 @@ pub async fn get_block_by_hash(
let Some(row) = row else {
return Ok(Json(None));
};
let mut block = BlockInfo::try_from(&row)?;

let block_id: Vec<u8> = row.try_get("block_id")?;
get_tx_hashes(&state, &mut block, &block_id).await?;
let block = BlockInfo::try_from(&row)?;

Ok(Json(Some(block)))
}
Expand All @@ -74,10 +48,7 @@ pub async fn get_block_by_height(
return Ok(Json(None));
};

let mut block = BlockInfo::try_from(&row)?;

let block_id: Vec<u8> = row.try_get("block_id")?;
get_tx_hashes(&state, &mut block, &block_id).await?;
let block = BlockInfo::try_from(&row)?;

Ok(Json(Some(block)))
}
Expand All @@ -96,10 +67,7 @@ pub async fn get_last_block(
let mut blocks: LatestBlocks = LatestBlocks { blocks: vec![] };

for row in rows {
let mut block = BlockInfo::try_from(&row)?;

let block_id: Vec<u8> = row.try_get("block_id")?;
get_tx_hashes(&state, &mut block, &block_id).await?;
let block = BlockInfo::try_from(&row)?;

blocks.blocks.push(block);
}
Expand All @@ -108,10 +76,7 @@ pub async fn get_last_block(
} else {
let row = state.db.get_last_block().await?;

let mut block = BlockInfo::try_from(&row)?;

let block_id: Vec<u8> = row.try_get("block_id")?;
get_tx_hashes(&state, &mut block, &block_id).await?;
let block = BlockInfo::try_from(&row)?;

Ok(Json(LatestBlock::LastBlock(Box::new(block))))
}
Expand Down

0 comments on commit f8b68b0

Please sign in to comment.