@@ -37,6 +37,7 @@ use std::borrow::Cow;
3737use std:: thread;
3838use std:: collections:: HashMap ;
3939use std:: marker:: PhantomData ;
40+ use std:: cmp:: Ordering ;
4041use sc_client_api:: { BlockOf , backend:: AuxStore } ;
4142use sp_blockchain:: { HeaderBackend , ProvideCache , well_known_cache_keys:: Id as CacheKeyId } ;
4243use sp_block_builder:: BlockBuilder as BlockBuilderApi ;
@@ -170,6 +171,19 @@ pub trait PowAlgorithm<B: BlockT> {
170171 ) -> Result < Option < bool > , Error < B > > {
171172 Ok ( None )
172173 }
174+ /// Break a fork choice tie.
175+ ///
176+ /// By default this chooses the earliest block seen. Using uniform tie
177+ /// breaking algorithms will help to protect against selfish mining.
178+ ///
179+ /// Returns if the new seal should be considered best block.
180+ fn break_tie (
181+ & self ,
182+ _own_seal : & Seal ,
183+ _new_seal : & Seal ,
184+ ) -> bool {
185+ false
186+ }
173187 /// Verify that the difficulty is valid against given seal.
174188 fn verify (
175189 & self ,
@@ -194,7 +208,7 @@ pub trait PowAlgorithm<B: BlockT> {
194208pub struct PowBlockImport < B : BlockT , I , C , S , Algorithm , CAW > {
195209 algorithm : Algorithm ,
196210 inner : I ,
197- select_chain : Option < S > ,
211+ select_chain : S ,
198212 client : Arc < C > ,
199213 inherent_data_providers : sp_inherents:: InherentDataProviders ,
200214 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
232246 client : Arc < C > ,
233247 algorithm : Algorithm ,
234248 check_inherents_after : <<B as BlockT >:: Header as HeaderT >:: Number ,
235- select_chain : Option < S > ,
249+ select_chain : S ,
236250 inherent_data_providers : sp_inherents:: InherentDataProviders ,
237251 can_author_with : CAW ,
238252 ) -> Self {
@@ -324,12 +338,9 @@ impl<B, I, C, S, Algorithm, CAW> BlockImport<B> for PowBlockImport<B, I, C, S, A
324338 mut block : BlockImportParams < B , Self :: Transaction > ,
325339 new_cache : HashMap < CacheKeyId , Vec < u8 > > ,
326340 ) -> Result < ImportResult , Self :: Error > {
327- let best_hash = match self . select_chain . as_ref ( ) {
328- Some ( select_chain) => select_chain. best_chain ( )
329- . map_err ( |e| format ! ( "Fetch best chain failed via select chain: {:?}" , e) ) ?
330- . hash ( ) ,
331- None => self . client . info ( ) . best_hash ,
332- } ;
341+ let best_header = self . select_chain . best_chain ( )
342+ . map_err ( |e| format ! ( "Fetch best chain failed via select chain: {:?}" , e) ) ?;
343+ let best_hash = best_header. hash ( ) ;
333344
334345 let parent_hash = * block. header . parent_hash ( ) ;
335346 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
352363 block. body = Some ( check_block. deconstruct ( ) . 1 ) ;
353364 }
354365
355- let inner_seal = match block. post_digests . last ( ) {
356- Some ( DigestItem :: Seal ( id, seal) ) => {
357- if id == & POW_ENGINE_ID {
358- seal. clone ( )
359- } else {
360- return Err ( Error :: < B > :: WrongEngine ( * id) . into ( ) )
361- }
362- } ,
363- _ => return Err ( Error :: < B > :: HeaderUnsealed ( block. header . hash ( ) ) . into ( ) ) ,
364- } ;
366+ let inner_seal = fetch_seal :: < B > ( block. post_digests . last ( ) , block. header . hash ( ) ) ?;
365367
366368 let intermediate = block. take_intermediate :: < PowIntermediate :: < Algorithm :: Difficulty > > (
367369 INTERMEDIATE_KEY
@@ -391,7 +393,18 @@ impl<B, I, C, S, Algorithm, CAW> BlockImport<B> for PowBlockImport<B, I, C, S, A
391393 block. auxiliary . push ( ( key, Some ( aux. encode ( ) ) ) ) ;
392394 if block. fork_choice . is_none ( ) {
393395 block. fork_choice = Some ( ForkChoiceStrategy :: Custom (
394- aux. total_difficulty > best_aux. total_difficulty
396+ match aux. total_difficulty . cmp ( & best_aux. total_difficulty ) {
397+ Ordering :: Less => false ,
398+ Ordering :: Greater => true ,
399+ Ordering :: Equal => {
400+ let best_inner_seal = fetch_seal :: < B > (
401+ best_header. digest ( ) . logs . last ( ) ,
402+ best_hash,
403+ ) ?;
404+
405+ self . algorithm . break_tie ( & best_inner_seal, & inner_seal)
406+ } ,
407+ }
395408 ) ) ;
396409 }
397410
@@ -729,3 +742,20 @@ fn find_pre_digest<B: BlockT>(header: &B::Header) -> Result<Option<Vec<u8>>, Err
729742
730743 Ok ( pre_digest)
731744}
745+
746+ /// Fetch PoW seal.
747+ fn fetch_seal < B : BlockT > (
748+ digest : Option < & DigestItem < B :: Hash > > ,
749+ hash : B :: Hash ,
750+ ) -> Result < Vec < u8 > , Error < B > > {
751+ match digest {
752+ Some ( DigestItem :: Seal ( id, seal) ) => {
753+ if id == & POW_ENGINE_ID {
754+ Ok ( seal. clone ( ) )
755+ } else {
756+ return Err ( Error :: < B > :: WrongEngine ( * id) . into ( ) )
757+ }
758+ } ,
759+ _ => return Err ( Error :: < B > :: HeaderUnsealed ( hash) . into ( ) ) ,
760+ }
761+ }
0 commit comments