1
1
import functools
2
- from typing import Iterable , Tuple
2
+ from typing import cast , Iterable , Tuple
3
3
4
4
import rlp
5
5
@@ -83,11 +83,15 @@ def get_canonical_head(self) -> BlockHeaderAPI:
83
83
84
84
@classmethod
85
85
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 :
86
91
try :
87
- canonical_head_hash = db [SchemaV1 .make_canonical_head_hash_lookup_key ()]
92
+ return Hash32 ( db [SchemaV1 .make_canonical_head_hash_lookup_key ()])
88
93
except KeyError :
89
94
raise CanonicalHeadNotFound ("No canonical head set for this chain" )
90
- return cls ._get_block_header_by_hash (db , Hash32 (canonical_head_hash ))
91
95
92
96
#
93
97
# Header API
@@ -173,7 +177,7 @@ def _persist_checkpoint_header(
173
177
)
174
178
previous_score = score - header .difficulty
175
179
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 )
177
181
178
182
@classmethod
179
183
def _persist_header_chain (
@@ -226,21 +230,21 @@ def _persist_header_chain(
226
230
score = cls ._set_hash_scores_to_db (db , curr_chain_head , score )
227
231
228
232
try :
229
- previous_canonical_head = cls ._get_canonical_head (db ). hash
233
+ previous_canonical_head = cls ._get_canonical_head_hash (db )
230
234
head_score = cls ._get_score (db , previous_canonical_head )
231
235
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 )
233
237
234
238
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 )
236
240
237
241
return tuple (), tuple ()
238
242
239
243
@classmethod
240
244
def _set_as_canonical_chain_head (
241
245
cls ,
242
246
db : DatabaseAPI ,
243
- block_hash : Hash32 ,
247
+ header : BlockHeaderAPI ,
244
248
genesis_parent_hash : Hash32 ,
245
249
) -> Tuple [Tuple [BlockHeaderAPI , ...], Tuple [BlockHeaderAPI , ...]]:
246
250
"""
@@ -251,14 +255,41 @@ def _set_as_canonical_chain_head(
251
255
are no longer in the canonical chain
252
256
"""
253
257
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
258
278
)
259
279
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 , ...]:
262
293
old_canonical_headers = []
263
294
264
295
for h in new_canonical_headers :
@@ -271,12 +302,7 @@ def _set_as_canonical_chain_head(
271
302
old_canonical_header = cls ._get_block_header_by_hash (db , old_canonical_hash )
272
303
old_canonical_headers .append (old_canonical_header )
273
304
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 )
280
306
281
307
@classmethod
282
308
@to_tuple
0 commit comments