-
Notifications
You must be signed in to change notification settings - Fork 123
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add bevm-finality-rpc finalized tool (#697)
Co-authored-by: icodezjb <[email protected]>
- Loading branch information
Showing
7 changed files
with
170 additions
and
0 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
[package] | ||
name = "bevm-finality-rpc" | ||
description = "An experimental RPC to check for block and transaction finality in the bevm chain" | ||
version = "5.2.2" | ||
authors = ["The ChainX Authors"] | ||
edition = "2021" | ||
|
||
[dependencies] | ||
futures = { version = "0.3", features = [ "compat" ] } | ||
jsonrpc-core = "18.0.0" | ||
jsonrpc-derive = "18.0.0" | ||
parity-scale-codec = "3.0.0" | ||
tokio = { version = "1.12.0", features = [ "sync", "time" ] } | ||
|
||
fc-db = { git = "https://github.com/chainx-org/frontier", branch = "polkadot-v0.9.18-btc-fix2" } | ||
fc-rpc = { git = "https://github.com/chainx-org/frontier", branch = "polkadot-v0.9.18-btc-fix2" } | ||
sp-api = { git = "https://github.com/chainx-org/substrate", branch = "polkadot-v0.9.18-fix2" } | ||
sp-blockchain = { git = "https://github.com/chainx-org/substrate", branch = "polkadot-v0.9.18-fix2" } | ||
sp-core = { git = "https://github.com/chainx-org/substrate", branch = "polkadot-v0.9.18-fix2" } | ||
sp-runtime = { git = "https://github.com/chainx-org/substrate", branch = "polkadot-v0.9.18-fix2" } | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
# rpc | ||
|
||
```json | ||
"bevm": { | ||
"isBlockFinalized": { | ||
"description": "Returns whether an Ethereum block is finalized", | ||
"params": [{ "name": "blockHash", "type": "Hash" }], | ||
"type": "bool" | ||
}, | ||
"isTxFinalized": { | ||
"description": "Returns whether an Ethereum transaction is finalized", | ||
"params": [{ "name": "txHash", "type": "Hash" }], | ||
"type": "bool" | ||
} | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
// Copyright 2019-2023 ChainX Project Authors. Licensed under GPL-3.0. | ||
|
||
use fc_rpc::frontier_backend_client::{self, is_canon}; | ||
use futures::{future::BoxFuture, FutureExt as _}; | ||
use jsonrpc_core::Result as RpcResult; | ||
use jsonrpc_derive::rpc; | ||
use sp_core::H256; | ||
use std::{marker::PhantomData, sync::Arc}; | ||
//TODO ideally we wouldn't depend on BlockId here. Can we change frontier | ||
// so it's load_hash helper returns an H256 instead of wrapping it in a BlockId? | ||
use fc_db::Backend as FrontierBackend; | ||
use sp_api::BlockId; | ||
use sp_blockchain::HeaderBackend; | ||
use sp_runtime::traits::Block; | ||
|
||
/// An RPC endpoint to check for finality of blocks and transactions in Bevm | ||
#[rpc(server)] | ||
pub trait BevmFinalityApi { | ||
/// Reports whether a Substrate or Ethereum block is finalized. | ||
/// Returns false if the block is not found. | ||
#[rpc(name = "bevm_isBlockFinalized")] | ||
fn is_block_finalized(&self, block_hash: H256) -> BoxFuture<'static, RpcResult<bool>>; | ||
|
||
/// Reports whether an Ethereum transaction is finalized. | ||
/// Returns false if the transaction is not found | ||
#[rpc(name = "bevm_isTxFinalized")] | ||
fn is_tx_finalized(&self, tx_hash: H256) -> BoxFuture<'static, RpcResult<bool>>; | ||
} | ||
|
||
pub struct BevmFinality<B: Block, C> { | ||
pub backend: Arc<FrontierBackend<B>>, | ||
pub client: Arc<C>, | ||
_phdata: PhantomData<B>, | ||
} | ||
|
||
impl<B: Block, C> BevmFinality<B, C> { | ||
pub fn new(client: Arc<C>, backend: Arc<FrontierBackend<B>>) -> Self { | ||
Self { | ||
backend, | ||
client, | ||
_phdata: Default::default(), | ||
} | ||
} | ||
} | ||
|
||
impl<B, C> BevmFinalityApi for BevmFinality<B, C> | ||
where | ||
B: Block<Hash = H256>, | ||
C: HeaderBackend<B> + Send + Sync + 'static, | ||
{ | ||
fn is_block_finalized(&self, raw_hash: H256) -> BoxFuture<'static, RpcResult<bool>> { | ||
let backend = self.backend.clone(); | ||
let client = self.client.clone(); | ||
async move { is_block_finalized_inner::<B, C>(&backend, &client, raw_hash) }.boxed() | ||
} | ||
|
||
fn is_tx_finalized(&self, tx_hash: H256) -> BoxFuture<'static, RpcResult<bool>> { | ||
let backend = self.backend.clone(); | ||
let client = self.client.clone(); | ||
async move { | ||
if let Some((ethereum_block_hash, _ethereum_index)) = | ||
frontier_backend_client::load_transactions::<B, C>( | ||
&client, | ||
backend.as_ref(), | ||
tx_hash, | ||
true, | ||
)? | ||
{ | ||
is_block_finalized_inner::<B, C>(&backend, &client, ethereum_block_hash) | ||
} else { | ||
Ok(false) | ||
} | ||
} | ||
.boxed() | ||
} | ||
} | ||
|
||
fn is_block_finalized_inner<B: Block<Hash = H256>, C: HeaderBackend<B> + 'static>( | ||
backend: &FrontierBackend<B>, | ||
client: &C, | ||
raw_hash: H256, | ||
) -> RpcResult<bool> { | ||
let substrate_hash = match frontier_backend_client::load_hash::<B>(backend, raw_hash)? { | ||
// If we find this hash in the frontier data base, we know it is an eth hash | ||
Some(BlockId::Hash(hash)) => hash, | ||
Some(BlockId::Number(_)) => panic!("is_canon test only works with hashes."), | ||
// Otherwise, we assume this is a Substrate hash. | ||
None => raw_hash, | ||
}; | ||
|
||
// First check whether the block is in the best chain | ||
if !is_canon(client, substrate_hash) { | ||
return Ok(false); | ||
} | ||
|
||
// At this point we know the block in question is in the current best chain. | ||
// It's just a question of whether it is in the finalized prefix or not | ||
let query_height = client | ||
.number(substrate_hash) | ||
.expect("No sp_blockchain::Error should be thrown when looking up hash") | ||
.expect("Block is already known to be canon, so it must be in the chain"); | ||
let finalized_height = client.info().finalized_number; | ||
|
||
Ok(query_height <= finalized_height) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters