mirror of
https://github.com/logos-blockchain/lssa.git
synced 2026-01-05 06:43:08 +00:00
add get transaction by hash rpc method
This commit is contained in:
parent
cab71a0e00
commit
9d85ea234e
@ -39,6 +39,11 @@ pub struct GetAccountBalanceRequest {
|
||||
pub address: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct GetTransactionByHashRequest {
|
||||
pub hash: String,
|
||||
}
|
||||
|
||||
parse_request!(HelloRequest);
|
||||
parse_request!(RegisterAccountRequest);
|
||||
parse_request!(SendTxRequest);
|
||||
@ -46,6 +51,7 @@ parse_request!(GetBlockDataRequest);
|
||||
parse_request!(GetGenesisIdRequest);
|
||||
parse_request!(GetLastBlockRequest);
|
||||
parse_request!(GetAccountBalanceRequest);
|
||||
parse_request!(GetTransactionByHashRequest);
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct HelloResponse {
|
||||
@ -81,3 +87,8 @@ pub struct GetLastBlockResponse {
|
||||
pub struct GetAccountBalanceResponse {
|
||||
pub balance: u64,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct GetTransactionByHashResponse {
|
||||
pub transaction: Option<Transaction>,
|
||||
}
|
||||
|
||||
@ -1,11 +1,12 @@
|
||||
use std::path::Path;
|
||||
use std::{collections::HashMap, path::Path};
|
||||
|
||||
use anyhow::Result;
|
||||
use common::block::Block;
|
||||
use common::{block::Block, merkle_tree_public::TreeHashType, transaction::Transaction};
|
||||
use storage::RocksDBIO;
|
||||
|
||||
pub struct SequecerBlockStore {
|
||||
dbio: RocksDBIO,
|
||||
tx_hash_to_block_map: HashMap<TreeHashType, u64>,
|
||||
pub genesis_id: u64,
|
||||
}
|
||||
|
||||
@ -15,11 +16,21 @@ impl SequecerBlockStore {
|
||||
///
|
||||
/// ATTENTION: Will overwrite genesis block.
|
||||
pub fn open_db_with_genesis(location: &Path, genesis_block: Option<Block>) -> Result<Self> {
|
||||
let tx_hash_to_block_map = if let Some(block) = &genesis_block {
|
||||
block_to_transactions_map(block)
|
||||
} else {
|
||||
HashMap::new()
|
||||
};
|
||||
|
||||
let dbio = RocksDBIO::new(location, genesis_block)?;
|
||||
|
||||
let genesis_id = dbio.get_meta_first_block_in_db()?;
|
||||
|
||||
Ok(Self { dbio, genesis_id })
|
||||
Ok(Self {
|
||||
dbio,
|
||||
genesis_id,
|
||||
tx_hash_to_block_map,
|
||||
})
|
||||
}
|
||||
|
||||
///Reopening existing database
|
||||
@ -31,7 +42,31 @@ impl SequecerBlockStore {
|
||||
Ok(self.dbio.get_block(id)?)
|
||||
}
|
||||
|
||||
pub fn put_block_at_id(&self, block: Block) -> Result<()> {
|
||||
Ok(self.dbio.put_block(block, false)?)
|
||||
pub fn put_block_at_id(&mut self, block: Block) -> Result<()> {
|
||||
let new_transactions_map = block_to_transactions_map(&block);
|
||||
self.dbio.put_block(block, false)?;
|
||||
self.tx_hash_to_block_map.extend(new_transactions_map);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_transaction_by_hash(&self, hash: TreeHashType) -> Option<Transaction> {
|
||||
let block_id = self.tx_hash_to_block_map.get(&hash);
|
||||
let block = block_id.map(|&id| self.get_block_at_id(id));
|
||||
if let Some(Ok(block)) = block {
|
||||
for transaction in block.transactions.into_iter() {
|
||||
if transaction.hash() == hash {
|
||||
return Some(transaction);
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn block_to_transactions_map(block: &Block) -> HashMap<TreeHashType, u64> {
|
||||
block
|
||||
.transactions
|
||||
.iter()
|
||||
.map(|transaction| (transaction.hash(), block.block_id))
|
||||
.collect()
|
||||
}
|
||||
|
||||
@ -1,11 +1,17 @@
|
||||
use actix_web::Error as HttpError;
|
||||
use serde_json::Value;
|
||||
|
||||
use common::rpc_primitives::{
|
||||
errors::{RpcError, RpcParseError},
|
||||
message::{Message, Request},
|
||||
parser::RpcRequest,
|
||||
requests::{GetAccountBalanceRequest, GetAccountBalanceResponse},
|
||||
use common::{
|
||||
merkle_tree_public::TreeHashType,
|
||||
rpc_primitives::{
|
||||
errors::{RpcError, RpcParseError},
|
||||
message::{Message, Request},
|
||||
parser::RpcRequest,
|
||||
requests::{
|
||||
GetAccountBalanceRequest, GetAccountBalanceResponse, GetTransactionByHashRequest,
|
||||
GetTransactionByHashResponse,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
use common::rpc_primitives::requests::{
|
||||
@ -23,6 +29,7 @@ pub const GET_BLOCK: &str = "get_block";
|
||||
pub const GET_GENESIS: &str = "get_genesis";
|
||||
pub const GET_LAST_BLOCK: &str = "get_last_block";
|
||||
pub const GET_ACCOUNT_BALANCE: &str = "get_account_balance";
|
||||
pub const GET_TRANSACTION_BY_HASH: &str = "get_transaction_by_hash";
|
||||
|
||||
pub const HELLO_FROM_SEQUENCER: &str = "HELLO_FROM_SEQUENCER";
|
||||
|
||||
@ -156,6 +163,21 @@ impl JsonHandler {
|
||||
|
||||
respond(helperstruct)
|
||||
}
|
||||
async fn process_get_transaction_by_hash(&self, request: Request) -> Result<Value, RpcErr> {
|
||||
let get_transaction_req = GetTransactionByHashRequest::parse(Some(request.params))?;
|
||||
let bytes: Vec<u8> = hex::decode(get_transaction_req.hash)
|
||||
.map_err(|_| RpcParseError("invalid hash".to_string()))?;
|
||||
let hash: TreeHashType = bytes
|
||||
.try_into()
|
||||
.map_err(|_| RpcParseError("invalid hash".to_string()))?;
|
||||
|
||||
let transaction = {
|
||||
let state = self.sequencer_state.lock().await;
|
||||
state.store.block_store.get_transaction_by_hash(hash)
|
||||
};
|
||||
let helperstruct = GetTransactionByHashResponse { transaction };
|
||||
respond(helperstruct)
|
||||
}
|
||||
|
||||
pub async fn process_request_internal(&self, request: Request) -> Result<Value, RpcErr> {
|
||||
match request.method.as_ref() {
|
||||
@ -166,6 +188,7 @@ impl JsonHandler {
|
||||
GET_GENESIS => self.process_get_genesis(request).await,
|
||||
GET_LAST_BLOCK => self.process_get_last_block(request).await,
|
||||
GET_ACCOUNT_BALANCE => self.process_get_account_balance(request).await,
|
||||
GET_TRANSACTION_BY_HASH => self.process_get_transaction_by_hash(request).await,
|
||||
_ => Err(RpcErr(RpcError::method_not_found(request.method))),
|
||||
}
|
||||
}
|
||||
@ -315,4 +338,26 @@ mod tests {
|
||||
|
||||
assert_eq!(response, expected_response);
|
||||
}
|
||||
|
||||
#[actix_web::test]
|
||||
async fn test_get_transaction_by_hash_for_non_existent_hash() {
|
||||
let json_handler = json_handler_for_tests();
|
||||
let request = serde_json::json!({
|
||||
"jsonrpc": "2.0",
|
||||
"method": "get_transaction_by_hash",
|
||||
"params": { "hash": "cafe".repeat(16) },
|
||||
"id": 1
|
||||
});
|
||||
let expected_response = serde_json::json!({
|
||||
"id": 1,
|
||||
"jsonrpc": "2.0",
|
||||
"result": {
|
||||
"transaction": Value::Null
|
||||
}
|
||||
});
|
||||
|
||||
let response = call_rpc_handler_with_json(json_handler, request).await;
|
||||
|
||||
assert_eq!(response, expected_response);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user