def _get_header_chain_gaps(cls, db: DatabaseAPI) -> ChainGaps: try: encoded_gaps = db[SchemaV1.make_header_chain_gaps_lookup_key()] except KeyError: return GENESIS_CHAIN_GAPS else: return rlp.decode(encoded_gaps, sedes=chain_gaps)
def _decanonicalize_descendant_orphans( cls, db: DatabaseAPI, header: BlockHeaderAPI, checkpoints: Tuple[Hash32, ...]) -> None: # Determine if any children need to be de-canonicalized because they are not children of # the new chain head new_gaps = starting_gaps = cls._get_header_chain_gaps(db) child_number = BlockNumber(header.block_number + 1) try: child = cls._get_canonical_block_header_by_number(db, child_number) except HeaderNotFound: # There is no canonical block here next_invalid_child = None else: if child.parent_hash != header.hash: if child.hash in checkpoints: raise CheckpointsMustBeCanonical( f"Trying to decanonicalize {child} while making {header} the chain tip" ) else: next_invalid_child = child else: next_invalid_child = None while next_invalid_child: # decanonicalize, and add gap for tracking db.delete(SchemaV1.make_block_number_to_hash_lookup_key(child_number)) new_gaps = reopen_gap(child_number, new_gaps) # find next child child_number = BlockNumber(child_number + 1) try: # All contiguous children must now be made invalid next_invalid_child = cls._get_canonical_block_header_by_number(db, child_number) except HeaderNotFound: # Found the end of this streak of canonical blocks break else: if next_invalid_child.hash in checkpoints: raise CheckpointsMustBeCanonical( f"Trying to decanonicalize {next_invalid_child} while making {header} the" " chain tip" ) if new_gaps != starting_gaps: db.set( SchemaV1.make_header_chain_gaps_lookup_key(), rlp.encode(new_gaps, sedes=chain_gaps) )
def _decanonicalize_single(cls, db: DatabaseAPI, block_num: BlockNumber, base_gaps: ChainGaps) -> ChainGaps: """ A single block number was found to no longer be canonical. At doc-time, this only happens because it does not link up with a checkpoint header. So de-canonicalize this block number and insert a gap in the tracked chain gaps. """ db.delete(SchemaV1.make_block_number_to_hash_lookup_key(block_num)) new_gaps = reopen_gap(block_num, base_gaps) if new_gaps != base_gaps: db.set(SchemaV1.make_header_chain_gaps_lookup_key(), rlp.encode(new_gaps, sedes=chain_gaps)) return new_gaps
def _update_header_chain_gaps(cls, db: DatabaseAPI, persisted_header: BlockHeaderAPI, base_gaps: ChainGaps = None) -> GapInfo: # If we make many updates in a row, we can avoid reloading the integrity info by # continuously caching it and providing it as a parameter to this API if base_gaps is None: base_gaps = cls._get_header_chain_gaps(db) gap_change, gaps = fill_gap(persisted_header.block_number, base_gaps) if gap_change is not GapChange.NoChange: db.set(SchemaV1.make_header_chain_gaps_lookup_key(), rlp.encode(gaps, sedes=chain_gaps)) return gap_change, gaps