diff --git a/src/data_source/extension.rs b/src/data_source/extension.rs index 6285af6d4..d9b286970 100644 --- a/src/data_source/extension.rs +++ b/src/data_source/extension.rs @@ -31,6 +31,7 @@ use async_trait::async_trait; use hotshot_types::traits::node_implementation::NodeType; use jf_merkle_tree::prelude::MerkleProof; use std::ops::RangeBounds; +use tagged_base64::TaggedBase64; /// Wrapper to add extensibility to an existing data source. /// @@ -403,7 +404,7 @@ where async fn get_search_results( &self, - query: String, + query: TaggedBase64, ) -> Result< explorer::query_data::SearchResult, explorer::query_data::GetSearchResultsError, diff --git a/src/data_source/fetching.rs b/src/data_source/fetching.rs index cd5a9a2f9..e7563345d 100644 --- a/src/data_source/fetching.rs +++ b/src/data_source/fetching.rs @@ -117,6 +117,7 @@ use std::{ ops::{Bound, Range, RangeBounds}, time::Duration, }; +use tagged_base64::TaggedBase64; use tracing::Instrument; mod block; @@ -1202,7 +1203,7 @@ where async fn get_search_results( &self, - query: String, + query: TaggedBase64, ) -> Result< explorer::query_data::SearchResult, explorer::query_data::GetSearchResultsError, diff --git a/src/data_source/fetching/notify_storage.rs b/src/data_source/fetching/notify_storage.rs index 157f711d1..0b23f463d 100644 --- a/src/data_source/fetching/notify_storage.rs +++ b/src/data_source/fetching/notify_storage.rs @@ -36,6 +36,7 @@ use futures::future::Future; use hotshot_types::traits::node_implementation::NodeType; use jf_merkle_tree::{prelude::MerkleProof, MerkleTreeScheme}; use std::ops::RangeBounds; +use tagged_base64::TaggedBase64; #[derive(Debug)] pub(super) struct NotifyStorage @@ -513,7 +514,7 @@ where async fn get_search_results( &mut self, - query: String, + query: TaggedBase64, ) -> Result< explorer::query_data::SearchResult, explorer::query_data::GetSearchResultsError, diff --git a/src/data_source/storage.rs b/src/data_source/storage.rs index 4133ce26c..d7fce9d58 100644 --- a/src/data_source/storage.rs +++ b/src/data_source/storage.rs @@ -80,6 +80,7 @@ use async_trait::async_trait; use hotshot_types::traits::node_implementation::NodeType; use jf_merkle_tree::prelude::MerkleProof; use std::ops::RangeBounds; +use tagged_base64::TaggedBase64; pub mod fs; mod ledger_log; @@ -233,7 +234,7 @@ where /// query string. async fn get_search_results( &mut self, - query: String, + query: TaggedBase64, ) -> Result, GetSearchResultsError>; } diff --git a/src/data_source/storage/sql/queries/explorer.rs b/src/data_source/storage/sql/queries/explorer.rs index 2d90ad28b..8a5908ba7 100644 --- a/src/data_source/storage/sql/queries/explorer.rs +++ b/src/data_source/storage/sql/queries/explorer.rs @@ -20,7 +20,10 @@ use crate::{ availability::{BlockQueryData, QueryableHeader, QueryablePayload, TransactionIndex}, data_source::storage::ExplorerStorage, explorer::{ - self, errors::NotFound, query_data::TransactionDetailResponse, traits::ExplorerHeader, + self, + errors::{self, NotFound}, + query_data::TransactionDetailResponse, + traits::ExplorerHeader, BalanceAmount, BlockDetail, BlockIdentifier, BlockRange, BlockSummary, ExplorerHistograms, ExplorerSummary, GenesisOverview, GetBlockDetailError, GetBlockSummariesError, GetBlockSummariesRequest, GetExplorerSummaryError, GetSearchResultsError, @@ -28,15 +31,16 @@ use crate::{ MonetaryValue, SearchResult, TransactionIdentifier, TransactionRange, TransactionSummary, TransactionSummaryFilter, }, - Header, Payload, QueryError, QueryResult, + Header, Payload, QueryError, QueryResult, Transaction as HotshotTransaction, }; use async_trait::async_trait; -use committable::Committable; +use committable::{Commitment, Committable}; use futures::stream::{self, StreamExt, TryStreamExt}; use hotshot_types::traits::node_implementation::NodeType; use itertools::Itertools; use sqlx::{types::Json, FromRow, Row}; use std::num::NonZeroUsize; +use tagged_base64::{Tagged, TaggedBase64}; impl From for GetExplorerSummaryError { fn from(err: sqlx::Error) -> Self { @@ -509,61 +513,77 @@ where async fn get_search_results( &mut self, - search_query: String, + search_query: TaggedBase64, ) -> Result, GetSearchResultsError> { - let block_query = format!( - "SELECT {BLOCK_COLUMNS} - FROM header AS h - JOIN payload AS p ON h.height = p.height - WHERE h.hash LIKE $1 || '%' - ORDER BY h.height DESC - LIMIT 5" - ); - let block_query_rows = query(block_query.as_str()) - .bind(&search_query) - .fetch(self.as_mut()); - let block_query_result: Vec> = block_query_rows - .map(|row| BlockSummary::from_row(&row?)) - .try_collect() - .await?; + let search_tag = search_query.tag(); + let header_tag = Commitment::>::tag(); + let tx_tag = Commitment::>::tag(); - let transactions_query = format!( - "SELECT {BLOCK_COLUMNS} - FROM header AS h - JOIN payload AS p ON h.height = p.height - JOIN transaction AS t ON h.height = t.block_height - WHERE t.hash LIKE $1 || '%' - ORDER BY h.height DESC - LIMIT 5" - ); - let transactions_query_rows = query(transactions_query.as_str()) - .bind(&search_query) - .fetch(self.as_mut()); - let transactions_query_result: Vec> = transactions_query_rows - .map(|row| -> Result>, QueryError>{ - let block = BlockQueryData::::from_row(&row?)?; - let transactions = block - .enumerate() - .enumerate() - .filter(|(_, (_, txn))| txn.commit().to_string().starts_with(&search_query)) - .map(|(offset, (_, txn))| { - Ok(TransactionSummary::try_from(( - &block, offset, txn, - ))?) - }) - .try_collect::, Vec>, QueryError>()?; + let search_query_string = search_query.to_string(); - Ok(transactions) + if search_tag != header_tag && search_tag != tx_tag { + return Err(GetSearchResultsError::InvalidQuery(errors::BadQuery {})); + } + + if search_tag == header_tag { + let block_query = format!( + "SELECT {BLOCK_COLUMNS} + FROM header AS h + JOIN payload AS p ON h.height = p.height + WHERE h.hash = $1 + ORDER BY h.height DESC + LIMIT 5" + ); + let block_query_rows = query(block_query.as_str()) + .bind(&search_query_string) + .fetch(self.as_mut()); + let block_query_result: Vec> = block_query_rows + .map(|row| BlockSummary::from_row(&row?)) + .try_collect() + .await?; + + Ok(SearchResult { + blocks: block_query_result, + transactions: Vec::new(), }) - .try_collect::>>>() - .await? - .into_iter() - .flatten() - .collect(); + } else { + let transactions_query = format!( + "SELECT {BLOCK_COLUMNS} + FROM header AS h + JOIN payload AS p ON h.height = p.height + JOIN transaction AS t ON h.height = t.block_height + WHERE t.hash = $1 + ORDER BY h.height DESC + LIMIT 5" + ); + let transactions_query_rows = query(transactions_query.as_str()) + .bind(&search_query_string) + .fetch(self.as_mut()); + let transactions_query_result: Vec> = transactions_query_rows + .map(|row| -> Result>, QueryError>{ + let block = BlockQueryData::::from_row(&row?)?; + let transactions = block + .enumerate() + .enumerate() + .filter(|(_, (_, txn))| txn.commit().to_string().starts_with(&search_query_string)) + .map(|(offset, (_, txn))| { + Ok(TransactionSummary::try_from(( + &block, offset, txn, + ))?) + }) + .try_collect::, Vec>, QueryError>()?; + Ok(transactions) + }) + .try_collect::>>>() + .await? + .into_iter() + .flatten() + .collect(); - Ok(SearchResult { - blocks: block_query_result, - transactions: transactions_query_result, - }) + Ok(SearchResult { + blocks: Vec::new(), + transactions: transactions_query_result, + }) + } } } diff --git a/src/explorer.rs b/src/explorer.rs index ed3ca5a6f..5c2a00268 100644 --- a/src/explorer.rs +++ b/src/explorer.rs @@ -373,16 +373,15 @@ where .get("get_search_result", move |req, state| { async move { let query = req - .string_param("query") + .tagged_base64_param("query") .map_err(|err| { tracing::error!("query param error: {}", err); GetSearchResultsError::InvalidQuery(errors::BadQuery {}) }) - .map_err(Error::GetSearchResults)? - .to_string(); + .map_err(Error::GetSearchResults)?; state - .get_search_results(query) + .get_search_results(query.clone()) .await .map(SearchResultResponse::from) .map_err(Error::GetSearchResults) diff --git a/src/explorer/data_source.rs b/src/explorer/data_source.rs index c236f56ba..aa5613e9b 100644 --- a/src/explorer/data_source.rs +++ b/src/explorer/data_source.rs @@ -26,6 +26,7 @@ use crate::{ }; use async_trait::async_trait; use hotshot_types::traits::node_implementation::NodeType; +use tagged_base64::TaggedBase64; /// An interface for querying Data and Statistics from the HotShot Blockchain. /// @@ -87,6 +88,6 @@ where /// query string. async fn get_search_results( &self, - query: String, + query: TaggedBase64, ) -> Result, GetSearchResultsError>; }