From 69132bda6b489e395f53954e148b915fc5977e34 Mon Sep 17 00:00:00 2001 From: Alex Pozhylenkov Date: Thu, 19 May 2022 12:28:40 +0300 Subject: [PATCH] eth_getBlockByNumber rpc implementation (#3994) --- jormungandr/src/blockchain/storage.rs | 23 +++++++ jormungandr/src/jrpc/eth_block_info/logic.rs | 67 ++++++++++++++----- jormungandr/src/jrpc/eth_block_info/mod.rs | 3 +- jormungandr/src/jrpc/eth_types/block.rs | 9 +++ .../src/jrpc/eth_types/block_number.rs | 8 +-- 5 files changed, 89 insertions(+), 21 deletions(-) diff --git a/jormungandr/src/blockchain/storage.rs b/jormungandr/src/blockchain/storage.rs index 6b41cbe5a9..27720ae606 100644 --- a/jormungandr/src/blockchain/storage.rs +++ b/jormungandr/src/blockchain/storage.rs @@ -135,6 +135,29 @@ impl Storage { }) } + pub fn get_nth_ancestor( + &self, + header_hash: HeaderHash, + distance: u32, + ) -> Result, Error> { + match self + .storage + .get_nth_ancestor(header_hash.as_bytes(), distance) + { + Ok(block) => { + let block = self + .storage + .get_block(block.id().as_ref()) + .expect("already found this block, it must exists inside the storage"); + Block::deserialize(&mut Codec::new(block.as_ref())) + .map(Some) + .map_err(Error::Deserialize) + } + Err(StorageError::BlockNotFound) => Ok(None), + Err(e) => Err(Error::BackendError(e)), + } + } + pub fn put_block(&self, block: &Block) -> Result<(), Error> { let id = block .header() diff --git a/jormungandr/src/jrpc/eth_block_info/logic.rs b/jormungandr/src/jrpc/eth_block_info/logic.rs index eda30b1bb6..0fc74d9a44 100644 --- a/jormungandr/src/jrpc/eth_block_info/logic.rs +++ b/jormungandr/src/jrpc/eth_block_info/logic.rs @@ -1,9 +1,38 @@ use super::Error; use crate::{ + blockchain::{Blockchain, Ref}, context::Context, jrpc::eth_types::{block::Block, block_number::BlockNumber, number::Number}, }; use chain_evm::ethereum_types::H256; +use chain_impl_mockchain::block::Block as JorBlock; +use std::sync::Arc; + +fn get_block_by_number_from_context( + number: BlockNumber, + blockchain: &Blockchain, + blockchain_tip: Arc, +) -> Result, Error> { + match number { + BlockNumber::Latest => { + let block = blockchain.storage().get(blockchain_tip.hash())?; + Ok(block) + } + BlockNumber::Earliest => { + let block = blockchain.storage().get(*blockchain.block0())?; + Ok(block) + } + BlockNumber::Pending => Ok(None), + BlockNumber::Num(number) if number <= blockchain_tip.chain_length().into() => { + let distance = u32::from(blockchain_tip.chain_length()) - number; + let block = blockchain + .storage() + .get_nth_ancestor(blockchain_tip.hash(), distance)?; + Ok(block) + } + BlockNumber::Num(_) => Ok(None), + } +} pub async fn get_block_by_hash( hash: H256, @@ -18,32 +47,38 @@ pub async fn get_block_by_hash( } pub async fn get_block_by_number( - _number: BlockNumber, + number: BlockNumber, full: bool, context: &Context, ) -> Result, Error> { - // TODO implement - let block = context.blockchain()?.storage().get([0; 32].into())?; + let blockchain = context.blockchain()?; let blockchain_tip = context.blockchain_tip()?.get_ref().await; let gas_limit = blockchain_tip.ledger().evm_block_gas_limit(); let gas_price = blockchain_tip.ledger().evm_gas_price(); - Ok(block.map(|block| Block::build(block, full, gas_limit, gas_price))) + Ok( + get_block_by_number_from_context(number, blockchain, blockchain_tip)? + .map(|block| Block::build(block, full, gas_limit, gas_price)), + ) } pub fn get_transaction_count_by_hash( - _hash: H256, - _context: &Context, + hash: H256, + context: &Context, ) -> Result, Error> { - // TODO implement - Ok(Some(0.into())) + let block = context.blockchain()?.storage().get(hash.0.into())?; + Ok(block.map(Block::calc_transactions_count)) } -pub fn get_transaction_count_by_number( - _number: BlockNumber, - _context: &Context, +pub async fn get_transaction_count_by_number( + number: BlockNumber, + context: &Context, ) -> Result, Error> { - // TODO implement - Ok(Some(0.into())) + let blockchain = context.blockchain()?; + let blockchain_tip = context.blockchain_tip()?.get_ref().await; + Ok( + get_block_by_number_from_context(number, blockchain, blockchain_tip)? + .map(Block::calc_transactions_count), + ) } pub fn get_uncle_count_by_hash(_: H256, _: &Context) -> Result, Error> { @@ -56,7 +91,7 @@ pub fn get_uncle_count_by_number(_: BlockNumber, _: &Context) -> Result Result { - // TODO implement - Ok(0.into()) +pub async fn get_block_number(context: &Context) -> Result { + let blockchain_tip = context.blockchain_tip()?.get_ref().await; + Ok((Into::::into(blockchain_tip.chain_length()) as u64).into()) } diff --git a/jormungandr/src/jrpc/eth_block_info/mod.rs b/jormungandr/src/jrpc/eth_block_info/mod.rs index 67a0c29be4..81e020be78 100644 --- a/jormungandr/src/jrpc/eth_block_info/mod.rs +++ b/jormungandr/src/jrpc/eth_block_info/mod.rs @@ -53,6 +53,7 @@ pub fn eth_block_info_module(context: ContextLock) -> RpcModule { let context = context.read().await; let block_number = params.parse()?; logic::get_transaction_count_by_number(block_number, &context) + .await .map_err(|err| jsonrpsee_core::Error::Custom(err.to_string())) }, ) @@ -85,8 +86,8 @@ pub fn eth_block_info_module(context: ContextLock) -> RpcModule { module .register_async_method("eth_blockNumber", |_, context| async move { let context = context.read().await; - logic::get_block_number(&context) + .await .map_err(|err| jsonrpsee_core::Error::Custom(err.to_string())) }) .unwrap(); diff --git a/jormungandr/src/jrpc/eth_types/block.rs b/jormungandr/src/jrpc/eth_types/block.rs index 8503883e96..8ec612b840 100644 --- a/jormungandr/src/jrpc/eth_types/block.rs +++ b/jormungandr/src/jrpc/eth_types/block.rs @@ -137,6 +137,15 @@ impl Block { base_fee_per_gas: Some(1.into()), } } + + pub fn calc_transactions_count(block: JorBlock) -> Number { + (block + .contents() + .iter() + .filter(|fragment| matches!(fragment, Fragment::Evm(_))) + .count() as u64) + .into() + } } #[cfg(test)] diff --git a/jormungandr/src/jrpc/eth_types/block_number.rs b/jormungandr/src/jrpc/eth_types/block_number.rs index 5ab3c99ed4..dd8aabc7fd 100644 --- a/jormungandr/src/jrpc/eth_types/block_number.rs +++ b/jormungandr/src/jrpc/eth_types/block_number.rs @@ -8,7 +8,7 @@ use std::fmt; #[derive(Debug, PartialEq, Eq)] pub enum BlockNumber { /// Number - Num(u64), + Num(u32), /// Latest block Latest, /// Earliest block (genesis) @@ -52,10 +52,10 @@ impl<'a> Visitor<'a> for BlockNumberVisitor { "latest" => Ok(BlockNumber::Latest), "earliest" => Ok(BlockNumber::Earliest), "pending" => Ok(BlockNumber::Pending), - _ if value.starts_with("0x") => u64::from_str_radix(&value[2..], 16) + _ if value.starts_with("0x") => u32::from_str_radix(&value[2..], 16) .map(BlockNumber::Num) .map_err(|e| Error::custom(format!("Invalid block number: {}", e))), - _ => value.parse::().map(BlockNumber::Num).map_err(|_| { + _ => value.parse::().map(BlockNumber::Num).map_err(|_| { Error::custom("Invalid block number: non-decimal or missing 0x prefix".to_string()) }), } @@ -68,7 +68,7 @@ impl<'a> Visitor<'a> for BlockNumberVisitor { self.visit_str(value.as_ref()) } - fn visit_u64(self, value: u64) -> Result + fn visit_u32(self, value: u32) -> Result where E: Error, {