Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Commit

Permalink
pow: support uniform tie breaking in fork choice (#7073)
Browse files Browse the repository at this point in the history
* pow: support uniform tie breaking in fork choice

* Update client/consensus/pow/src/lib.rs

Co-authored-by: Bastian Köcher <[email protected]>

* Refactor fetch seal

Co-authored-by: Bastian Köcher <[email protected]>
  • Loading branch information
sorpaas and bkchr committed Sep 18, 2020
1 parent 5f6987a commit c071d06
Showing 1 changed file with 49 additions and 19 deletions.
68 changes: 49 additions & 19 deletions client/consensus/pow/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ use std::borrow::Cow;
use std::thread;
use std::collections::HashMap;
use std::marker::PhantomData;
use std::cmp::Ordering;
use sc_client_api::{BlockOf, backend::AuxStore};
use sp_blockchain::{HeaderBackend, ProvideCache, well_known_cache_keys::Id as CacheKeyId};
use sp_block_builder::BlockBuilder as BlockBuilderApi;
Expand Down Expand Up @@ -170,6 +171,19 @@ pub trait PowAlgorithm<B: BlockT> {
) -> Result<Option<bool>, Error<B>> {
Ok(None)
}
/// Break a fork choice tie.
///
/// By default this chooses the earliest block seen. Using uniform tie
/// breaking algorithms will help to protect against selfish mining.
///
/// Returns if the new seal should be considered best block.
fn break_tie(
&self,
_own_seal: &Seal,
_new_seal: &Seal,
) -> bool {
false
}
/// Verify that the difficulty is valid against given seal.
fn verify(
&self,
Expand All @@ -194,7 +208,7 @@ pub trait PowAlgorithm<B: BlockT> {
pub struct PowBlockImport<B: BlockT, I, C, S, Algorithm, CAW> {
algorithm: Algorithm,
inner: I,
select_chain: Option<S>,
select_chain: S,
client: Arc<C>,
inherent_data_providers: sp_inherents::InherentDataProviders,
check_inherents_after: <<B as BlockT>::Header as HeaderT>::Number,
Expand Down Expand Up @@ -232,7 +246,7 @@ impl<B, I, C, S, Algorithm, CAW> PowBlockImport<B, I, C, S, Algorithm, CAW> wher
client: Arc<C>,
algorithm: Algorithm,
check_inherents_after: <<B as BlockT>::Header as HeaderT>::Number,
select_chain: Option<S>,
select_chain: S,
inherent_data_providers: sp_inherents::InherentDataProviders,
can_author_with: CAW,
) -> Self {
Expand Down Expand Up @@ -324,12 +338,9 @@ impl<B, I, C, S, Algorithm, CAW> BlockImport<B> for PowBlockImport<B, I, C, S, A
mut block: BlockImportParams<B, Self::Transaction>,
new_cache: HashMap<CacheKeyId, Vec<u8>>,
) -> Result<ImportResult, Self::Error> {
let best_hash = match self.select_chain.as_ref() {
Some(select_chain) => select_chain.best_chain()
.map_err(|e| format!("Fetch best chain failed via select chain: {:?}", e))?
.hash(),
None => self.client.info().best_hash,
};
let best_header = self.select_chain.best_chain()
.map_err(|e| format!("Fetch best chain failed via select chain: {:?}", e))?;
let best_hash = best_header.hash();

let parent_hash = *block.header.parent_hash();
let best_aux = PowAux::read::<_, B>(self.client.as_ref(), &best_hash)?;
Expand All @@ -352,16 +363,7 @@ impl<B, I, C, S, Algorithm, CAW> BlockImport<B> for PowBlockImport<B, I, C, S, A
block.body = Some(check_block.deconstruct().1);
}

let inner_seal = match block.post_digests.last() {
Some(DigestItem::Seal(id, seal)) => {
if id == &POW_ENGINE_ID {
seal.clone()
} else {
return Err(Error::<B>::WrongEngine(*id).into())
}
},
_ => return Err(Error::<B>::HeaderUnsealed(block.header.hash()).into()),
};
let inner_seal = fetch_seal::<B>(block.post_digests.last(), block.header.hash())?;

let intermediate = block.take_intermediate::<PowIntermediate::<Algorithm::Difficulty>>(
INTERMEDIATE_KEY
Expand Down Expand Up @@ -391,7 +393,18 @@ impl<B, I, C, S, Algorithm, CAW> BlockImport<B> for PowBlockImport<B, I, C, S, A
block.auxiliary.push((key, Some(aux.encode())));
if block.fork_choice.is_none() {
block.fork_choice = Some(ForkChoiceStrategy::Custom(
aux.total_difficulty > best_aux.total_difficulty
match aux.total_difficulty.cmp(&best_aux.total_difficulty) {
Ordering::Less => false,
Ordering::Greater => true,
Ordering::Equal => {
let best_inner_seal = fetch_seal::<B>(
best_header.digest().logs.last(),
best_hash,
)?;

self.algorithm.break_tie(&best_inner_seal, &inner_seal)
},
}
));
}

Expand Down Expand Up @@ -729,3 +742,20 @@ fn find_pre_digest<B: BlockT>(header: &B::Header) -> Result<Option<Vec<u8>>, Err

Ok(pre_digest)
}

/// Fetch PoW seal.
fn fetch_seal<B: BlockT>(
digest: Option<&DigestItem<B::Hash>>,
hash: B::Hash,
) -> Result<Vec<u8>, Error<B>> {
match digest {
Some(DigestItem::Seal(id, seal)) => {
if id == &POW_ENGINE_ID {
Ok(seal.clone())
} else {
return Err(Error::<B>::WrongEngine(*id).into())
}
},
_ => return Err(Error::<B>::HeaderUnsealed(hash).into()),
}
}

0 comments on commit c071d06

Please sign in to comment.