Skip to content

Commit

Permalink
Frontier consensus one-to-many mapping (#133)
Browse files Browse the repository at this point in the history
* Frontier consensus one-to-many mapping

* Cleanup

* Checker fix
  • Loading branch information
tgmichel authored Sep 28, 2020
1 parent 98f9ce8 commit 8f7f0f9
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 32 deletions.
15 changes: 12 additions & 3 deletions consensus/src/aux_schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,21 +43,30 @@ pub fn block_hash_key(ethereum_block_hash: H256) -> Vec<u8> {
pub fn load_block_hash<Block: BlockT, B: AuxStore>(
backend: &B,
hash: H256,
) -> ClientResult<Option<Block::Hash>> {
) -> ClientResult<Option<Vec<Block::Hash>>> {
let key = block_hash_key(hash);
load_decode(backend, &key)
}

/// Update Aux block hash.
pub fn write_block_hash<Hash: Encode, F, R>(
pub fn write_block_hash<Hash: Encode + Decode, F, R, Backend: AuxStore>(
client: &Backend,
ethereum_hash: H256,
block_hash: Hash,
write_aux: F,
) -> R where
F: FnOnce(&[(&[u8], &[u8])]) -> R,
{
let key = block_hash_key(ethereum_hash);
write_aux(&[(&key, &block_hash.encode()[..])])

let mut data: Vec<Hash> = 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.
Expand Down
4 changes: 3 additions & 1 deletion consensus/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@ impl<B, I, C> BlockImport<B> for FrontierBlockImport<B, I, C> where
)
}

let client = self.client.clone();

if self.enabled {
let log = find_frontier_log::<B>(&block.header)?;
let hash = block.post_hash();
Expand All @@ -134,7 +136,7 @@ impl<B, I, C> BlockImport<B> for FrontierBlockImport<B, I, C> 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(
Expand Down
1 change: 1 addition & 0 deletions rpc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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" }
Expand Down
81 changes: 53 additions & 28 deletions rpc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -179,6 +180,7 @@ fn transaction_build(

impl<B, C, SC, P, CT, BE> EthApi<B, C, SC, P, CT, BE> where
C: ProvideRuntimeApi<B> + StorageProvider<B, BE> + AuxStore,
C: HeaderBackend<B> + HeaderMetadata<B, Error=BlockChainError> + 'static,
C::Api: EthereumRuntimeRPCApi<B>,
BE: Backend<B> + 'static,
BE::State: StateBackend<BlakeTwo256>,
Expand All @@ -191,10 +193,7 @@ impl<B, C, SC, P, CT, BE> EthApi<B, C, SC, P, CT, BE> where
fn native_block_id(&self, number: Option<BlockNumber>) -> Result<Option<BlockId<B>>> {
Ok(match number.unwrap_or(BlockNumber::Latest) {
BlockNumber::Hash { hash, .. } => {
let hash = frontier_consensus::load_block_hash::<B, _>(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()))
Expand All @@ -214,10 +213,36 @@ impl<B, C, SC, P, CT, BE> EthApi<B, C, SC, P, CT, BE> where
}
})
}

// Asumes there is only one mapped canonical block in the AuxStore, otherwise something is wrong
fn load_hash(&self, hash: H256) -> Result<Option<BlockId<B>>> {
let hashes = match frontier_consensus::load_block_hash::<B, _>(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<H256> = 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<B, C, SC, P, CT, BE> EthApiT for EthApi<B, C, SC, P, CT, BE> where
C: ProvideRuntimeApi<B> + StorageProvider<B, BE> + AuxStore,
C: HeaderBackend<B> + HeaderMetadata<B, Error=BlockChainError> + 'static,
C::Api: EthereumRuntimeRPCApi<B>,
BE: Backend<B> + 'static,
BE::State: StateBackend<BlakeTwo256>,
Expand Down Expand Up @@ -329,11 +354,11 @@ impl<B, C, SC, P, CT, BE> EthApiT for EthApi<B, C, SC, P, CT, BE> where
}

fn block_by_hash(&self, hash: H256, full: bool) -> Result<Option<RichBlock>> {
let id = match frontier_consensus::load_block_hash::<B, _>(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)
Expand Down Expand Up @@ -401,11 +426,11 @@ impl<B, C, SC, P, CT, BE> EthApiT for EthApi<B, C, SC, P, CT, BE> where
}

fn block_transaction_count_by_hash(&self, hash: H256) -> Result<Option<U256>> {
let id = match frontier_consensus::load_block_hash::<B, _>(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()
Expand Down Expand Up @@ -558,11 +583,11 @@ impl<B, C, SC, P, CT, BE> EthApiT for EthApi<B, C, SC, P, CT, BE> where
None => return Ok(None),
};

let id = match frontier_consensus::load_block_hash::<B, _>(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)
Expand All @@ -587,11 +612,11 @@ impl<B, C, SC, P, CT, BE> EthApiT for EthApi<B, C, SC, P, CT, BE> where
hash: H256,
index: Index,
) -> Result<Option<Transaction>> {
let id = match frontier_consensus::load_block_hash::<B, _>(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();

Expand Down Expand Up @@ -649,11 +674,11 @@ impl<B, C, SC, P, CT, BE> EthApiT for EthApi<B, C, SC, P, CT, BE> where
None => return Ok(None),
};

let id = match frontier_consensus::load_block_hash::<B, _>(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)
Expand Down Expand Up @@ -739,11 +764,11 @@ impl<B, C, SC, P, CT, BE> EthApiT for EthApi<B, C, SC, P, CT, BE> where
let mut ret = Vec::new();

if let Some(hash) = filter.block_hash {
let id = match frontier_consensus::load_block_hash::<B, _>(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()
Expand Down

0 comments on commit 8f7f0f9

Please sign in to comment.