예제 #1
0
 def _get_checkpoints(cls, db: DatabaseAPI) -> Tuple[Hash32, ...]:
     concatenated_checkpoints = db.get(
         SchemaV1.make_checkpoint_headers_key())
     if concatenated_checkpoints is None:
         return ()
     else:
         return tuple(
             Hash32(concatenated_checkpoints[index:index + 32])
             for index in range(0, len(concatenated_checkpoints), 32))
예제 #2
0
    def _persist_checkpoint_header(
            cls,
            db: DatabaseAPI,
            header: BlockHeaderAPI,
            score: int
    ) -> None:
        db.set(
            header.hash,
            rlp.encode(header),
        )

        # Add new checkpoint header
        previous_checkpoints = cls._get_checkpoints(db)
        new_checkpoints = previous_checkpoints + (header.hash,)
        db.set(
            SchemaV1.make_checkpoint_headers_key(),
            b''.join(new_checkpoints),
        )

        previous_score = score - header.difficulty
        cls._set_hash_scores_to_db(db, header, previous_score)
        cls._set_as_canonical_chain_head(db, header, GENESIS_PARENT_HASH)
        _, gaps = cls._update_header_chain_gaps(db, header)

        # check if the parent block number exists, and is not a match for checkpoint.parent_hash
        parent_block_num = BlockNumber(header.block_number - 1)
        try:
            parent_hash = cls._get_canonical_block_hash(db, parent_block_num)
        except HeaderNotFound:
            # no parent to check
            pass
        else:
            # User is asserting that the checkpoint must be canonical, so if the parent doesn't
            # match, then the parent must not be canonical, and should be de-canonicalized.
            if parent_hash != header.parent_hash:
                # does the correct header exist in the database?
                try:
                    true_parent = cls._get_block_header_by_hash(db, header.parent_hash)
                except HeaderNotFound:
                    # True parent unavailable, just delete the now non-canonical one
                    cls._decanonicalize_single(db, parent_block_num, gaps)
                else:
                    # True parent should have already been canonicalized during
                    #   _set_as_canonical_chain_head()
                    raise ValidationError(
                        f"Why was a non-matching parent header {parent_hash!r} left as canonical "
                        f"after _set_as_canonical_chain_head() and {true_parent} is available?"
                    )

        cls._decanonicalize_descendant_orphans(db, header, new_checkpoints)