@@ -1199,8 +1199,17 @@ impl<Block: BlockT> Backend<Block> {
11991199 let mut enacted = Vec :: default ( ) ;
12001200 let mut retracted = Vec :: default ( ) ;
12011201
1202+ let ( best_number, best_hash) = best_to;
1203+
12021204 let meta = self . blockchain . meta . read ( ) ;
12031205
1206+ if meta. best_number > best_number &&
1207+ ( meta. best_number - best_number) . saturated_into :: < u64 > ( ) >
1208+ self . canonicalization_delay
1209+ {
1210+ return Err ( sp_blockchain:: Error :: SetHeadTooOld . into ( ) )
1211+ }
1212+
12041213 // cannot find tree route with empty DB.
12051214 if meta. best_hash != Default :: default ( ) {
12061215 let tree_route = sp_blockchain:: tree_route ( & self . blockchain , meta. best_hash , route_to) ?;
@@ -1233,13 +1242,13 @@ impl<Block: BlockT> Backend<Block> {
12331242 }
12341243 }
12351244
1236- let lookup_key = utils:: number_and_hash_to_lookup_key ( best_to . 0 , & best_to . 1 ) ?;
1245+ let lookup_key = utils:: number_and_hash_to_lookup_key ( best_number , & best_hash ) ?;
12371246 transaction. set_from_vec ( columns:: META , meta_keys:: BEST_BLOCK , lookup_key) ;
12381247 utils:: insert_number_to_key_mapping (
12391248 transaction,
12401249 columns:: KEY_LOOKUP ,
1241- best_to . 0 ,
1242- best_to . 1 ,
1250+ best_number ,
1251+ best_hash ,
12431252 ) ?;
12441253
12451254 Ok ( ( enacted, retracted) )
@@ -1534,6 +1543,27 @@ impl<Block: BlockT> Backend<Block> {
15341543 hash, number, is_best, operation. commit_state, existing_header,
15351544 ) ;
15361545
1546+ self . state_usage . merge_sm ( operation. old_state . usage_info ( ) ) ;
1547+ // release state reference so that it can be finalized
1548+ let cache = operation. old_state . into_cache_changes ( ) ;
1549+
1550+ if finalized {
1551+ // TODO: ensure best chain contains this block.
1552+ self . ensure_sequential_finalization ( header, Some ( last_finalized_hash) ) ?;
1553+ self . note_finalized (
1554+ & mut transaction,
1555+ true ,
1556+ header,
1557+ hash,
1558+ & mut changes_trie_cache_ops,
1559+ & mut finalization_displaced_leaves,
1560+ operation. commit_state ,
1561+ ) ?;
1562+ } else {
1563+ // canonicalize blocks which are old enough, regardless of finality.
1564+ self . force_delayed_canonicalize ( & mut transaction, hash, * header. number ( ) ) ?
1565+ }
1566+
15371567 if !existing_header {
15381568 let changes_trie_config_update = operation. changes_trie_config_update ;
15391569 changes_trie_cache_ops = Some ( self . changes_tries_storage . commit (
@@ -1550,37 +1580,14 @@ impl<Block: BlockT> Backend<Block> {
15501580 changes_trie_cache_ops,
15511581 ) ?) ;
15521582
1553- self . state_usage . merge_sm ( operation. old_state . usage_info ( ) ) ;
1554- // release state reference so that it can be finalized
1555- let cache = operation. old_state . into_cache_changes ( ) ;
1556-
1557- if finalized {
1558- // TODO: ensure best chain contains this block.
1559- self . ensure_sequential_finalization ( header, Some ( last_finalized_hash) ) ?;
1560- self . note_finalized (
1561- & mut transaction,
1562- true ,
1563- header,
1564- hash,
1565- & mut changes_trie_cache_ops,
1566- & mut finalization_displaced_leaves,
1567- operation. commit_state ,
1568- ) ?;
1569- } else {
1570- // canonicalize blocks which are old enough, regardless of finality.
1571- self . force_delayed_canonicalize ( & mut transaction, hash, * header. number ( ) ) ?
1572- }
1573-
1574- let displaced_leaf = {
1583+ {
15751584 let mut leaves = self . blockchain . leaves . write ( ) ;
1576- let displaced_leaf = leaves. import ( hash, number, parent_hash) ;
1585+ leaves. import ( hash, number, parent_hash) ;
15771586 leaves. prepare_transaction (
15781587 & mut transaction,
15791588 columns:: META ,
15801589 meta_keys:: LEAF_PREFIX ,
15811590 ) ;
1582-
1583- displaced_leaf
15841591 } ;
15851592
15861593 let mut children = children:: read_children (
@@ -1599,28 +1606,17 @@ impl<Block: BlockT> Backend<Block> {
15991606 parent_hash,
16001607 children,
16011608 ) ;
1609+ }
16021610
1603- meta_updates. push ( MetaUpdate {
1604- hash,
1605- number,
1606- is_best : pending_block. leaf_state . is_best ( ) ,
1607- is_finalized : finalized,
1608- with_state : operation. commit_state ,
1609- } ) ;
1611+ meta_updates. push ( MetaUpdate {
1612+ hash,
1613+ number,
1614+ is_best : pending_block. leaf_state . is_best ( ) ,
1615+ is_finalized : finalized,
1616+ with_state : operation. commit_state ,
1617+ } ) ;
16101618
1611- Some ( (
1612- pending_block. header ,
1613- number,
1614- hash,
1615- enacted,
1616- retracted,
1617- displaced_leaf,
1618- is_best,
1619- cache,
1620- ) )
1621- } else {
1622- None
1623- }
1619+ Some ( ( pending_block. header , number, hash, enacted, retracted, is_best, cache) )
16241620 } else {
16251621 None
16261622 } ;
@@ -1660,17 +1656,7 @@ impl<Block: BlockT> Backend<Block> {
16601656 // Apply all in-memory state changes.
16611657 // Code beyond this point can't fail.
16621658
1663- if let Some ( (
1664- header,
1665- number,
1666- hash,
1667- enacted,
1668- retracted,
1669- _displaced_leaf,
1670- is_best,
1671- mut cache,
1672- ) ) = imported
1673- {
1659+ if let Some ( ( header, number, hash, enacted, retracted, is_best, mut cache) ) = imported {
16741660 trace ! ( target: "db" , "DB Commit done {:?}" , hash) ;
16751661 let header_metadata = CachedHeaderMetadata :: from ( & header) ;
16761662 self . blockchain . insert_header_metadata ( header_metadata. hash , header_metadata) ;
@@ -3390,4 +3376,66 @@ pub(crate) mod tests {
33903376 assert_eq ! ( None , backend. blockchain( ) . header( BlockId :: hash( prev_hash. clone( ) ) ) . unwrap( ) ) ;
33913377 assert ! ( !backend. have_state_at( & prev_hash, 1 ) ) ;
33923378 }
3379+
3380+ #[ test]
3381+ fn test_import_existing_block_as_new_head ( ) {
3382+ let backend: Backend < Block > = Backend :: new_test ( 10 , 3 ) ;
3383+ let block0 = insert_header ( & backend, 0 , Default :: default ( ) , None , Default :: default ( ) ) ;
3384+ let block1 = insert_header ( & backend, 1 , block0, None , Default :: default ( ) ) ;
3385+ let block2 = insert_header ( & backend, 2 , block1, None , Default :: default ( ) ) ;
3386+ let block3 = insert_header ( & backend, 3 , block2, None , Default :: default ( ) ) ;
3387+ let block4 = insert_header ( & backend, 4 , block3, None , Default :: default ( ) ) ;
3388+ let block5 = insert_header ( & backend, 5 , block4, None , Default :: default ( ) ) ;
3389+ assert_eq ! ( backend. blockchain( ) . info( ) . best_hash, block5) ;
3390+
3391+ // Insert 1 as best again. This should fail because canonicalization_delay == 3 and best == 5
3392+ let header = Header {
3393+ number : 1 ,
3394+ parent_hash : block0,
3395+ state_root : BlakeTwo256 :: trie_root ( Vec :: new ( ) ) ,
3396+ digest : Default :: default ( ) ,
3397+ extrinsics_root : Default :: default ( ) ,
3398+ } ;
3399+ let mut op = backend. begin_operation ( ) . unwrap ( ) ;
3400+ op. set_block_data ( header, None , None , None , NewBlockState :: Best ) . unwrap ( ) ;
3401+ assert ! ( matches!( backend. commit_operation( op) , Err ( sp_blockchain:: Error :: SetHeadTooOld ) ) ) ;
3402+
3403+ // Insert 2 as best again.
3404+ let header = Header {
3405+ number : 2 ,
3406+ parent_hash : block1,
3407+ state_root : BlakeTwo256 :: trie_root ( Vec :: new ( ) ) ,
3408+ digest : Default :: default ( ) ,
3409+ extrinsics_root : Default :: default ( ) ,
3410+ } ;
3411+ let mut op = backend. begin_operation ( ) . unwrap ( ) ;
3412+ op. set_block_data ( header, None , None , None , NewBlockState :: Best ) . unwrap ( ) ;
3413+ backend. commit_operation ( op) . unwrap ( ) ;
3414+ assert_eq ! ( backend. blockchain( ) . info( ) . best_hash, block2) ;
3415+ }
3416+
3417+ #[ test]
3418+ fn test_import_existing_block_as_final ( ) {
3419+ let backend: Backend < Block > = Backend :: new_test ( 10 , 10 ) ;
3420+ let block0 = insert_header ( & backend, 0 , Default :: default ( ) , None , Default :: default ( ) ) ;
3421+ let block1 = insert_header ( & backend, 1 , block0, None , Default :: default ( ) ) ;
3422+ let _block2 = insert_header ( & backend, 2 , block1, None , Default :: default ( ) ) ;
3423+ // Genesis is auto finalized, the rest are not.
3424+ assert_eq ! ( backend. blockchain( ) . info( ) . finalized_hash, block0) ;
3425+
3426+ // Insert 1 as final again.
3427+ let header = Header {
3428+ number : 1 ,
3429+ parent_hash : block0,
3430+ state_root : BlakeTwo256 :: trie_root ( Vec :: new ( ) ) ,
3431+ digest : Default :: default ( ) ,
3432+ extrinsics_root : Default :: default ( ) ,
3433+ } ;
3434+
3435+ let mut op = backend. begin_operation ( ) . unwrap ( ) ;
3436+ op. set_block_data ( header, None , None , None , NewBlockState :: Final ) . unwrap ( ) ;
3437+ backend. commit_operation ( op) . unwrap ( ) ;
3438+
3439+ assert_eq ! ( backend. blockchain( ) . info( ) . finalized_hash, block1) ;
3440+ }
33933441}
0 commit comments