diff --git a/consensus/src/aux_schema.rs b/consensus/src/aux_schema.rs index 354c40b8c..7b4f7a3b6 100644 --- a/consensus/src/aux_schema.rs +++ b/consensus/src/aux_schema.rs @@ -43,13 +43,14 @@ pub fn block_hash_key(ethereum_block_hash: H256) -> Vec { pub fn load_block_hash( backend: &B, hash: H256, -) -> ClientResult> { +) -> ClientResult>> { let key = block_hash_key(hash); load_decode(backend, &key) } /// Update Aux block hash. -pub fn write_block_hash( +pub fn write_block_hash( + client: &Backend, ethereum_hash: H256, block_hash: Hash, write_aux: F, @@ -57,7 +58,15 @@ pub fn write_block_hash( F: FnOnce(&[(&[u8], &[u8])]) -> R, { let key = block_hash_key(ethereum_hash); - write_aux(&[(&key, &block_hash.encode()[..])]) + + let mut data: Vec = match load_decode(client, &key) + { + Ok(Some(hashes)) => hashes, + _ => Vec::new(), + }; + data.push(block_hash); + + write_aux(&[(&key, &data.encode()[..])]) } /// Map an Ethereum transaction hash into its corresponding Ethereum block hash and index. diff --git a/consensus/src/lib.rs b/consensus/src/lib.rs index cee102bd6..0ba336320 100644 --- a/consensus/src/lib.rs +++ b/consensus/src/lib.rs @@ -126,6 +126,8 @@ impl BlockImport for FrontierBlockImport where ) } + let client = self.client.clone(); + if self.enabled { let log = find_frontier_log::(&block.header)?; let hash = block.post_hash(); @@ -134,7 +136,7 @@ impl BlockImport for FrontierBlockImport where ConsensusLog::EndBlock { block_hash, transaction_hashes, } => { - aux_schema::write_block_hash(block_hash, hash, insert_closure!()); + aux_schema::write_block_hash(client.as_ref(), block_hash, hash, insert_closure!()); for (index, transaction_hash) in transaction_hashes.into_iter().enumerate() { aux_schema::write_transaction_metadata( diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index 1f29d55cd..08de41d1a 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -16,6 +16,7 @@ frontier-rpc-core = { path = "core" } frontier-rpc-primitives = { path = "primitives" } sp-io = { git = "https://github.com/paritytech/substrate.git", branch = "frontier" } sp-runtime = { git = "https://github.com/paritytech/substrate.git", branch = "frontier" } +sp-blockchain = { git = "https://github.com/paritytech/substrate.git", branch = "frontier" } sp-api = { git = "https://github.com/paritytech/substrate.git", branch = "frontier" } sp-consensus = { git = "https://github.com/paritytech/substrate.git", branch = "frontier" } sp-transaction-pool = { git = "https://github.com/paritytech/substrate.git", branch = "frontier" } diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index c9e84a973..dabc1e2c1 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -28,6 +28,7 @@ use sp_transaction_pool::TransactionPool; use sc_client_api::backend::{StorageProvider, Backend, StateBackend, AuxStore}; use sha3::{Keccak256, Digest}; use sp_runtime::traits::BlakeTwo256; +use sp_blockchain::{Error as BlockChainError, HeaderMetadata, HeaderBackend}; use frontier_rpc_core::{EthApi as EthApiT, NetApi as NetApiT}; use frontier_rpc_core::types::{ BlockNumber, Bytes, CallRequest, Filter, Index, Log, Receipt, RichBlock, @@ -179,6 +180,7 @@ fn transaction_build( impl EthApi where C: ProvideRuntimeApi + StorageProvider + AuxStore, + C: HeaderBackend + HeaderMetadata + 'static, C::Api: EthereumRuntimeRPCApi, BE: Backend + 'static, BE::State: StateBackend, @@ -191,10 +193,7 @@ impl EthApi where fn native_block_id(&self, number: Option) -> Result>> { Ok(match number.unwrap_or(BlockNumber::Latest) { BlockNumber::Hash { hash, .. } => { - let hash = frontier_consensus::load_block_hash::(self.client.as_ref(), hash) - .map_err(|err| internal_err(format!("fetch aux store failed: {:?}", err)))?; - - hash.map(|h| BlockId::Hash(h)) + self.load_hash(hash).unwrap_or(None) }, BlockNumber::Num(number) => { Some(BlockId::Number(number.unique_saturated_into())) @@ -214,10 +213,36 @@ impl EthApi where } }) } + + // Asumes there is only one mapped canonical block in the AuxStore, otherwise something is wrong + fn load_hash(&self, hash: H256) -> Result>> { + let hashes = match frontier_consensus::load_block_hash::(self.client.as_ref(), hash) + .map_err(|err| internal_err(format!("fetch aux store failed: {:?}", err)))? + { + Some(hashes) => hashes, + None => return Ok(None), + }; + let out: Vec = hashes.into_iter() + .filter_map(|h| { + if let Ok(Some(_)) = self.client.header(BlockId::Hash(h)) { + Some(h) + } else { + None + } + }).collect(); + + if out.len() == 1 { + return Ok(Some( + BlockId::Hash(out[0]) + )); + } + Ok(None) + } } impl EthApiT for EthApi where C: ProvideRuntimeApi + StorageProvider + AuxStore, + C: HeaderBackend + HeaderMetadata + 'static, C::Api: EthereumRuntimeRPCApi, BE: Backend + 'static, BE::State: StateBackend, @@ -329,11 +354,11 @@ impl EthApiT for EthApi where } fn block_by_hash(&self, hash: H256, full: bool) -> Result> { - let id = match frontier_consensus::load_block_hash::(self.client.as_ref(), hash) - .map_err(|err| internal_err(format!("fetch aux store failed: {:?}", err)))? + let id = match self.load_hash(hash) + .map_err(|err| internal_err(format!("{:?}", err)))? { - Some(hash) => BlockId::Hash(hash), - None => return Ok(None), + Some(hash) => hash, + _ => return Ok(None), }; let block = self.client.runtime_api().current_block(&id) @@ -401,11 +426,11 @@ impl EthApiT for EthApi where } fn block_transaction_count_by_hash(&self, hash: H256) -> Result> { - let id = match frontier_consensus::load_block_hash::(self.client.as_ref(), hash) - .map_err(|err| internal_err(format!("fetch aux store failed: {:?}", err)))? + let id = match self.load_hash(hash) + .map_err(|err| internal_err(format!("{:?}", err)))? { - Some(hash) => BlockId::Hash(hash), - None => return Ok(None), + Some(hash) => hash, + _ => return Ok(None), }; let block = self.client.runtime_api() @@ -558,11 +583,11 @@ impl EthApiT for EthApi where None => return Ok(None), }; - let id = match frontier_consensus::load_block_hash::(self.client.as_ref(), hash) - .map_err(|err| internal_err(format!("fetch aux store failed: {:?}", err)))? + let id = match self.load_hash(hash) + .map_err(|err| internal_err(format!("{:?}", err)))? { - Some(hash) => BlockId::Hash(hash), - None => return Ok(None), + Some(hash) => hash, + _ => return Ok(None), }; let block = self.client.runtime_api().current_block(&id) @@ -587,11 +612,11 @@ impl EthApiT for EthApi where hash: H256, index: Index, ) -> Result> { - let id = match frontier_consensus::load_block_hash::(self.client.as_ref(), hash) - .map_err(|err| internal_err(format!("fetch aux store failed: {:?}", err)))? + let id = match self.load_hash(hash) + .map_err(|err| internal_err(format!("{:?}", err)))? { - Some(hash) => BlockId::Hash(hash), - None => return Ok(None), + Some(hash) => hash, + _ => return Ok(None), }; let index = index.value(); @@ -649,11 +674,11 @@ impl EthApiT for EthApi where None => return Ok(None), }; - let id = match frontier_consensus::load_block_hash::(self.client.as_ref(), hash) - .map_err(|err| internal_err(format!("fetch aux store failed: {:?}", err)))? + let id = match self.load_hash(hash) + .map_err(|err| internal_err(format!("{:?}", err)))? { - Some(hash) => BlockId::Hash(hash), - None => return Ok(None), + Some(hash) => hash, + _ => return Ok(None), }; let block = self.client.runtime_api().current_block(&id) @@ -739,11 +764,11 @@ impl EthApiT for EthApi where let mut ret = Vec::new(); if let Some(hash) = filter.block_hash { - let id = match frontier_consensus::load_block_hash::(self.client.as_ref(), hash) - .map_err(|err| internal_err(format!("fetch aux store failed: {:?}", err)))? + let id = match self.load_hash(hash) + .map_err(|err| internal_err(format!("{:?}", err)))? { - Some(hash) => BlockId::Hash(hash), - None => return Ok(ret), + Some(hash) => hash, + _ => return Ok(Vec::new()), }; let block = self.client.runtime_api()