Пример #1
0
 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)
Пример #2
0
    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)
            )
Пример #3
0
    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
Пример #4
0
    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