mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-12 14:41:11 +00:00
pow: support uniform tie breaking in fork choice (#7073)
* pow: support uniform tie breaking in fork choice * Update client/consensus/pow/src/lib.rs Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com> * Refactor fetch seal Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>
This commit is contained in:
@@ -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;
|
||||
@@ -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,
|
||||
@@ -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,
|
||||
@@ -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 {
|
||||
@@ -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)?;
|
||||
@@ -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
|
||||
@@ -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)
|
||||
},
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
@@ -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()),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user