11import functools
2- from typing import Iterable , Tuple
2+ from typing import cast , Iterable , Tuple
33
44import rlp
55
@@ -83,11 +83,15 @@ def get_canonical_head(self) -> BlockHeaderAPI:
8383
8484 @classmethod
8585 def _get_canonical_head (cls , db : DatabaseAPI ) -> BlockHeaderAPI :
86+ canonical_head_hash = cls ._get_canonical_head_hash (db )
87+ return cls ._get_block_header_by_hash (db , canonical_head_hash )
88+
89+ @classmethod
90+ def _get_canonical_head_hash (cls , db : DatabaseAPI ) -> Hash32 :
8691 try :
87- canonical_head_hash = db [SchemaV1 .make_canonical_head_hash_lookup_key ()]
92+ return Hash32 ( db [SchemaV1 .make_canonical_head_hash_lookup_key ()])
8893 except KeyError :
8994 raise CanonicalHeadNotFound ("No canonical head set for this chain" )
90- return cls ._get_block_header_by_hash (db , Hash32 (canonical_head_hash ))
9195
9296 #
9397 # Header API
@@ -173,7 +177,7 @@ def _persist_checkpoint_header(
173177 )
174178 previous_score = score - header .difficulty
175179 cls ._set_hash_scores_to_db (db , header , previous_score )
176- cls ._set_as_canonical_chain_head (db , header . hash , header .parent_hash )
180+ cls ._set_as_canonical_chain_head (db , header , header .parent_hash )
177181
178182 @classmethod
179183 def _persist_header_chain (
@@ -226,21 +230,21 @@ def _persist_header_chain(
226230 score = cls ._set_hash_scores_to_db (db , curr_chain_head , score )
227231
228232 try :
229- previous_canonical_head = cls ._get_canonical_head (db ). hash
233+ previous_canonical_head = cls ._get_canonical_head_hash (db )
230234 head_score = cls ._get_score (db , previous_canonical_head )
231235 except CanonicalHeadNotFound :
232- return cls ._set_as_canonical_chain_head (db , curr_chain_head . hash , genesis_parent_hash )
236+ return cls ._set_as_canonical_chain_head (db , curr_chain_head , genesis_parent_hash )
233237
234238 if score > head_score :
235- return cls ._set_as_canonical_chain_head (db , curr_chain_head . hash , genesis_parent_hash )
239+ return cls ._set_as_canonical_chain_head (db , curr_chain_head , genesis_parent_hash )
236240
237241 return tuple (), tuple ()
238242
239243 @classmethod
240244 def _set_as_canonical_chain_head (
241245 cls ,
242246 db : DatabaseAPI ,
243- block_hash : Hash32 ,
247+ header : BlockHeaderAPI ,
244248 genesis_parent_hash : Hash32 ,
245249 ) -> Tuple [Tuple [BlockHeaderAPI , ...], Tuple [BlockHeaderAPI , ...]]:
246250 """
@@ -251,14 +255,41 @@ def _set_as_canonical_chain_head(
251255 are no longer in the canonical chain
252256 """
253257 try :
254- header = cls ._get_block_header_by_hash (db , block_hash )
255- except HeaderNotFound :
256- raise ValueError (
257- f"Cannot use unknown block hash as canonical head: { block_hash } "
258+ current_canonical_head = cls ._get_canonical_head_hash (db )
259+ except CanonicalHeadNotFound :
260+ current_canonical_head = None
261+
262+ new_canonical_headers : Tuple [BlockHeaderAPI , ...]
263+ old_canonical_headers : Tuple [BlockHeaderAPI , ...]
264+
265+ if current_canonical_head and header .parent_hash == current_canonical_head :
266+ # the calls to _find_new_ancestors and _decanonicalize_old_headers are
267+ # relatively expensive, it's better to skip them in this case, where we're
268+ # extending the canonical chain by a header
269+ new_canonical_headers = (header ,)
270+ old_canonical_headers = ()
271+ else :
272+ new_canonical_headers = cast (
273+ Tuple [BlockHeaderAPI , ...],
274+ tuple (reversed (cls ._find_new_ancestors (db , header , genesis_parent_hash )))
275+ )
276+ old_canonical_headers = cls ._decanonicalize_old_headers (
277+ db , new_canonical_headers
258278 )
259279
260- new_canonical_headers = tuple (reversed (
261- cls ._find_new_ancestors (db , header , genesis_parent_hash )))
280+ for h in new_canonical_headers :
281+ cls ._add_block_number_to_hash_lookup (db , h )
282+
283+ db .set (SchemaV1 .make_canonical_head_hash_lookup_key (), header .hash )
284+
285+ return new_canonical_headers , old_canonical_headers
286+
287+ @classmethod
288+ def _decanonicalize_old_headers (
289+ cls ,
290+ db : DatabaseAPI ,
291+ new_canonical_headers : Tuple [BlockHeaderAPI , ...]
292+ ) -> Tuple [BlockHeaderAPI , ...]:
262293 old_canonical_headers = []
263294
264295 for h in new_canonical_headers :
@@ -271,12 +302,7 @@ def _set_as_canonical_chain_head(
271302 old_canonical_header = cls ._get_block_header_by_hash (db , old_canonical_hash )
272303 old_canonical_headers .append (old_canonical_header )
273304
274- for h in new_canonical_headers :
275- cls ._add_block_number_to_hash_lookup (db , h )
276-
277- db .set (SchemaV1 .make_canonical_head_hash_lookup_key (), header .hash )
278-
279- return new_canonical_headers , tuple (old_canonical_headers )
305+ return tuple (old_canonical_headers )
280306
281307 @classmethod
282308 @to_tuple
0 commit comments