Skip to content

Commit

Permalink
eth_getBlockByNumber rpc implementation (#3994)
Browse files Browse the repository at this point in the history
  • Loading branch information
Mr-Leshiy authored May 19, 2022
1 parent 04e2143 commit 69132bd
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 21 deletions.
23 changes: 23 additions & 0 deletions jormungandr/src/blockchain/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,29 @@ impl Storage {
})
}

pub fn get_nth_ancestor(
&self,
header_hash: HeaderHash,
distance: u32,
) -> Result<Option<Block>, 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()
Expand Down
67 changes: 51 additions & 16 deletions jormungandr/src/jrpc/eth_block_info/logic.rs
Original file line number Diff line number Diff line change
@@ -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<Ref>,
) -> Result<Option<JorBlock>, 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,
Expand All @@ -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<Option<Block>, 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<Option<Number>, 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<Option<Number>, 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<Option<Number>, Error> {
Expand All @@ -56,7 +91,7 @@ pub fn get_uncle_count_by_number(_: BlockNumber, _: &Context) -> Result<Option<N
Ok(Some(0.into()))
}

pub fn get_block_number(_: &Context) -> Result<Number, Error> {
// TODO implement
Ok(0.into())
pub async fn get_block_number(context: &Context) -> Result<Number, Error> {
let blockchain_tip = context.blockchain_tip()?.get_ref().await;
Ok((Into::<u32>::into(blockchain_tip.chain_length()) as u64).into())
}
3 changes: 2 additions & 1 deletion jormungandr/src/jrpc/eth_block_info/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ pub fn eth_block_info_module(context: ContextLock) -> RpcModule<ContextLock> {
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()))
},
)
Expand Down Expand Up @@ -85,8 +86,8 @@ pub fn eth_block_info_module(context: ContextLock) -> RpcModule<ContextLock> {
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();
Expand Down
9 changes: 9 additions & 0 deletions jormungandr/src/jrpc/eth_types/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
8 changes: 4 additions & 4 deletions jormungandr/src/jrpc/eth_types/block_number.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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::<u64>().map(BlockNumber::Num).map_err(|_| {
_ => value.parse::<u32>().map(BlockNumber::Num).map_err(|_| {
Error::custom("Invalid block number: non-decimal or missing 0x prefix".to_string())
}),
}
Expand All @@ -68,7 +68,7 @@ impl<'a> Visitor<'a> for BlockNumberVisitor {
self.visit_str(value.as_ref())
}

fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
fn visit_u32<E>(self, value: u32) -> Result<Self::Value, E>
where
E: Error,
{
Expand Down

0 comments on commit 69132bd

Please sign in to comment.