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

Search function blocks #460

Merged
merged 22 commits into from
Feb 3, 2025
Merged
Show file tree
Hide file tree
Changes from 16 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

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions backend-rust/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Database schema version: 2
- Add index over accounts that delegate stake to a given baker pool.
- Add `database_schema_version` and `api_supported_database_schema_version` to `versions` endpoint.
- Add database schema version 2 with index over blocks with no `cumulative_finalization_time`, to improve indexing performance.
- Implement `SearchResult::bakers` and add relevant index to database
lassemand marked this conversation as resolved.
Show resolved Hide resolved

### Changed

Expand Down
2 changes: 1 addition & 1 deletion backend-rust/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion backend-rust/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "concordium-scan"
version = "0.1.19"
version = "0.1.20"
edition = "2021"
description = "CCDScan: Indexer and API for the Concordium blockchain"
authors = ["Concordium <[email protected]>"]
Expand Down
88 changes: 83 additions & 5 deletions backend-rust/src/graphql_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -905,14 +905,92 @@ impl SearchResult {

async fn blocks(
lassemand marked this conversation as resolved.
Show resolved Hide resolved
&self,
#[graphql(desc = "Returns the first _n_ elements from the list.")] _first: Option<i32>,
ctx: &Context<'_>,
#[graphql(desc = "Returns the first _n_ elements from the list.")] first: Option<u64>,
#[graphql(desc = "Returns the elements in the list that come after the specified cursor.")]
_after: Option<String>,
#[graphql(desc = "Returns the last _n_ elements from the list.")] _last: Option<i32>,
after: Option<String>,
#[graphql(desc = "Returns the last _n_ elements from the list.")] last: Option<u64>,
#[graphql(desc = "Returns the elements in the list that come before the specified cursor.")]
_before: Option<String>,
before: Option<String>,
) -> ApiResult<connection::Connection<String, Block>> {
todo_api!()
let block_hash_regex: Regex = Regex::new(r"^[a-fA-F0-9]{1,64}$")
.map_err(|_| ApiError::InternalError("Invalid regex".to_string()))?;
let pool = get_pool(ctx)?;
let config = get_config(ctx)?;
let query =
ConnectionQuery::<i64>::new(first, after, last, before, config.block_connection_limit)?;
let mut connection = connection::Connection::new(false, false);
if !block_hash_regex.is_match(&self.query) {
return Ok(connection);
}
let lower_case_query = self.query.to_lowercase();
let rows = sqlx::query_as!(
Block,
"SELECT * FROM (
SELECT
hash,
height,
slot_time,
block_time,
finalization_time,
baker_id,
total_amount
FROM blocks
WHERE
height = $5
OR starts_with(hash, $6)
AND height > $1
AND height < $2
ORDER BY
(CASE WHEN $4 THEN height END) ASC,
(CASE WHEN NOT $4 THEN height END) DESC
LIMIT $3
) ORDER BY height DESC",
query.from,
query.to,
query.limit,
query.desc,
lower_case_query.parse::<i64>().ok(),
lower_case_query
)
.fetch_all(pool)
lassemand marked this conversation as resolved.
Show resolved Hide resolved
.await?;

let mut min_height = None;
let mut max_height = None;
for block in rows {
min_height = Some(match min_height {
None => block.height,
Some(current_min) => min(current_min, block.height),
});

max_height = Some(match max_height {
None => block.height,
Some(current_max) => max(current_max, block.height),
});
connection.edges.push(connection::Edge::new(block.height.to_string(), block));
}

if let (Some(page_min_height), Some(page_max_height)) = (min_height, max_height) {
lassemand marked this conversation as resolved.
Show resolved Hide resolved
let result = sqlx::query!(
r#"
SELECT MAX(height) as max_height, MIN(height) as min_height
FROM blocks
WHERE
height = $1
OR starts_with(hash, $2)
"#,
lower_case_query.parse::<i64>().ok(),
lower_case_query,
)
.fetch_one(pool)
.await?;
connection.has_previous_page =
result.max_height.map_or(false, |db_max| db_max > page_max_height);
lassemand marked this conversation as resolved.
Show resolved Hide resolved
connection.has_next_page =
result.min_height.map_or(false, |db_min| db_min < page_min_height);
}
Ok(connection)
}

async fn transactions(
Expand Down
14 changes: 7 additions & 7 deletions backend-rust/src/graphql_api/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,20 +106,20 @@ impl QueryBlocks {

#[derive(Debug, Clone)]
pub struct Block {
hash: BlockHash,
height: BlockHeight,
pub(crate) hash: BlockHash,
pub(crate) height: BlockHeight,
/// Time of the block being baked.
slot_time: DateTime,
pub(crate) slot_time: DateTime,
/// Number of milliseconds between the `slot_time` of this block and its
/// parent.
block_time: i32,
pub(crate) block_time: i32,
/// If this block is finalized, the number of milliseconds between the
/// `slot_time` of this block and the first block that contains a
/// finalization proof or quorum certificate that justifies this block
/// being finalized.
finalization_time: Option<i32>,
baker_id: Option<i64>,
total_amount: i64,
pub(crate) finalization_time: Option<i32>,
pub(crate) baker_id: Option<i64>,
pub(crate) total_amount: i64,
}

impl Block {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
CREATE INDEX blocks_height_null_cumulative_finalization_time ON blocks (height)
WHERE blocks.cumulative_finalization_time IS NULL
AND blocks.finalization_time IS NOT NULL;

-- Used to efficiently perform partial string matching on the `hash` column,
-- allowing fast lookups when searching for blocks by their hash prefix using `LIKE`.
CREATE INDEX blocks_hash_gin_trgm_idx ON blocks USING gin(hash gin_trgm_ops);
lassemand marked this conversation as resolved.
Show resolved Hide resolved
-- Important for quickly calculating the delegated stake to a baker pool.
CREATE INDEX delegated_target_baker_id_index ON accounts(delegated_target_baker_id);
Loading