def _persist_header_chain(
        cls, db: BaseDB, headers: Iterable[BlockHeader]
    ) -> Tuple[Tuple[BlockHeader, ...], Tuple[BlockHeader, ...]]:
        try:
            first_header = first(headers)
        except StopIteration:
            return tuple(), tuple()
        else:

            for parent, child in sliding_window(2, headers):
                if parent.hash != child.parent_hash:
                    raise ValidationError(
                        "Non-contiguous chain. Expected {} to have {} as parent but was {}"
                        .format(
                            encode_hex(child.hash),
                            encode_hex(parent.hash),
                            encode_hex(child.parent_hash),
                        ))

            is_genesis = first_header.parent_hash == GENESIS_PARENT_HASH
            if not is_genesis and not cls._header_exists(
                    db, first_header.parent_hash):
                raise ParentNotFound(
                    "Cannot persist block header ({}) with unknown parent ({})"
                    .format(encode_hex(first_header.hash),
                            encode_hex(first_header.parent_hash)))

            score = 0 if is_genesis else cls._get_score(
                db, first_header.parent_hash)

        for header in headers:
            db.set(
                header.hash,
                rlp.encode(header),
            )

            score += header.difficulty

            db.set(
                SchemaV1.make_block_hash_to_score_lookup_key(header.hash),
                rlp.encode(score, sedes=rlp.sedes.big_endian_int),
            )

        try:
            previous_canonical_head = cls._get_canonical_head(db).hash
            head_score = cls._get_score(db, previous_canonical_head)
        except CanonicalHeadNotFound:
            (new_canonical_headers,
             old_canonical_headers) = cls._set_as_canonical_chain_head(
                 db, header.hash)
        else:
            if score > head_score:
                (new_canonical_headers,
                 old_canonical_headers) = cls._set_as_canonical_chain_head(
                     db, header.hash)
            else:
                new_canonical_headers = tuple()
                old_canonical_headers = tuple()

        return new_canonical_headers, old_canonical_headers
Exemplo n.º 2
0
    def _persist_header_chain(
        cls, db: BaseDB, headers: Iterable[BlockHeader]
    ) -> Tuple[Tuple[BlockHeader, ...], Tuple[BlockHeader, ...]]:
        headers_iterator = iter(headers)

        try:
            first_header = first(headers_iterator)
        except StopIteration:
            return tuple(), tuple()

        is_genesis = first_header.parent_hash == GENESIS_PARENT_HASH
        if not is_genesis and not cls._header_exists(db,
                                                     first_header.parent_hash):
            raise ParentNotFound(
                "Cannot persist block header ({}) with unknown parent ({})".
                format(encode_hex(first_header.hash),
                       encode_hex(first_header.parent_hash)))

        if is_genesis:
            score = 0
        else:
            score = cls._get_score(db, first_header.parent_hash)

        curr_chain_head = first_header
        db.set(
            curr_chain_head.hash,
            rlp.encode(curr_chain_head),
        )
        score = cls._set_hash_scores_to_db(db, curr_chain_head, score)

        orig_headers_seq = concat([(first_header, ), headers_iterator])
        for parent, child in sliding_window(2, orig_headers_seq):
            if parent.hash != child.parent_hash:
                raise ValidationError(
                    "Non-contiguous chain. Expected {} to have {} as parent but was {}"
                    .format(
                        encode_hex(child.hash),
                        encode_hex(parent.hash),
                        encode_hex(child.parent_hash),
                    ))

            curr_chain_head = child
            db.set(
                curr_chain_head.hash,
                rlp.encode(curr_chain_head),
            )

            score = cls._set_hash_scores_to_db(db, curr_chain_head, score)

        try:
            previous_canonical_head = cls._get_canonical_head(db).hash
            head_score = cls._get_score(db, previous_canonical_head)
        except CanonicalHeadNotFound:
            return cls._set_as_canonical_chain_head(db, curr_chain_head.hash)

        if score > head_score:
            return cls._set_as_canonical_chain_head(db, curr_chain_head.hash)

        return tuple(), tuple()
Exemplo n.º 3
0
    def _persist_block_chain(
        cls, db: BaseDB, blocks: Iterable[BaseBeaconBlock],
        block_class: Type[BaseBeaconBlock]
    ) -> Tuple[Tuple[BaseBeaconBlock, ...], Tuple[BaseBeaconBlock, ...]]:
        try:
            first_block = first(blocks)
        except StopIteration:
            return tuple(), tuple()
        else:
            for parent, child in sliding_window(2, blocks):
                if parent.root != child.parent_root:
                    raise ValidationError(
                        "Non-contiguous chain. Expected {} to have {} as parent but was {}"
                        .format(
                            encode_hex(child.root),
                            encode_hex(parent.root),
                            encode_hex(child.parent_root),
                        ))

            is_genesis = first_block.parent_root == GENESIS_PARENT_HASH
            if not is_genesis and not cls._block_exists(
                    db, first_block.parent_root):
                raise ParentNotFound(
                    "Cannot persist block ({}) with unknown parent ({})".
                    format(encode_hex(first_block.root),
                           encode_hex(first_block.parent_root)))

            if is_genesis:
                score = 0
            else:
                score = cls._get_score(db, first_block.parent_root)

        for block in blocks:
            db.set(
                block.root,
                rlp.encode(block),
            )

            # TODO: It's a stub before we implement fork choice rule
            score = block.slot

            db.set(
                SchemaV1.make_block_root_to_score_lookup_key(block.root),
                rlp.encode(score, sedes=rlp.sedes.big_endian_int),
            )

        try:
            previous_canonical_head = cls._get_canonical_head(db,
                                                              block_class).root
            head_score = cls._get_score(db, previous_canonical_head)
        except CanonicalHeadNotFound:
            return cls._set_as_canonical_chain_head(db, block.root,
                                                    block_class)

        if score > head_score:
            return cls._set_as_canonical_chain_head(db, block.root,
                                                    block_class)
        else:
            return tuple(), tuple()
Exemplo n.º 4
0
    def persist_header(
        self, header: BlockHeader
    ) -> Tuple[Tuple[BlockHeader, ...], Tuple[BlockHeader, ...]]:
        """
        :returns: iterable of headers newly on the canonical chain
        """
        if header.parent_hash != GENESIS_PARENT_HASH:
            try:
                self.get_block_header_by_hash(header.parent_hash)
            except HeaderNotFound:
                raise ParentNotFound(
                    "Cannot persist block header ({}) with unknown parent ({})"
                    .format(encode_hex(header.hash),
                            encode_hex(header.parent_hash)))

        self.db.set(
            header.hash,
            rlp.encode(header),
        )

        if header.parent_hash == GENESIS_PARENT_HASH:
            score = header.difficulty
        else:
            score = self.get_score(header.parent_hash) + header.difficulty

        self.db.set(
            SchemaV1.make_block_hash_to_score_lookup_key(header.hash),
            rlp.encode(score, sedes=rlp.sedes.big_endian_int),
        )

        try:
            head_score = self.get_score(self.get_canonical_head().hash)
        except CanonicalHeadNotFound:
            new_canonical_headers, old_canonical_headers = self._set_as_canonical_chain_head(
                header.hash, )
        else:
            if score > head_score:
                new_canonical_headers, old_canonical_headers = self._set_as_canonical_chain_head(
                    header.hash)
            else:
                new_canonical_headers = tuple()
                old_canonical_headers = tuple()

        return new_canonical_headers, old_canonical_headers
Exemplo n.º 5
0
    def _persist_block_chain(
        cls,
        db: DatabaseAPI,
        blocks: Iterable[BaseBeaconBlock],
        block_class: Type[BaseBeaconBlock],
        fork_choice_scorings: Iterable[ForkChoiceScoringFn],
    ) -> Tuple[Tuple[BaseBeaconBlock, ...], Tuple[BaseBeaconBlock, ...]]:
        blocks_iterator = iter(blocks)
        scorings_iterator = iter(fork_choice_scorings)

        try:
            first_block = first(blocks_iterator)
            first_scoring = first(scorings_iterator)
        except StopIteration:
            return tuple(), tuple()

        try:
            previous_canonical_head = cls._get_canonical_head(
                db, block_class).signing_root
            head_score = cls._get_score(db, previous_canonical_head)
        except CanonicalHeadNotFound:
            no_canonical_head = True
        else:
            no_canonical_head = False

        is_genesis = first_block.is_genesis
        if not is_genesis and not cls._block_exists(db,
                                                    first_block.parent_root):
            raise ParentNotFound(
                "Cannot persist block ({}) with unknown parent ({})".format(
                    encode_hex(first_block.signing_root),
                    encode_hex(first_block.parent_root),
                ))

        score = first_scoring(first_block)

        curr_block_head = first_block
        db.set(curr_block_head.signing_root, ssz.encode(curr_block_head))
        cls._add_block_root_to_slot_lookup(db, curr_block_head)
        cls._set_block_score_to_db(db, curr_block_head, score)
        cls._add_attestations_root_to_block_lookup(db, curr_block_head)

        orig_blocks_seq = concat([(first_block, ), blocks_iterator])

        for parent, child in sliding_window(2, orig_blocks_seq):
            if parent.signing_root != child.parent_root:
                raise ValidationError(
                    "Non-contiguous chain. Expected {} to have {} as parent but was {}"
                    .format(
                        encode_hex(child.signing_root),
                        encode_hex(parent.signing_root),
                        encode_hex(child.parent_root),
                    ))

            curr_block_head = child
            db.set(curr_block_head.signing_root, ssz.encode(curr_block_head))
            cls._add_block_root_to_slot_lookup(db, curr_block_head)
            cls._add_attestations_root_to_block_lookup(db, curr_block_head)

            # NOTE: len(scorings_iterator) should equal len(blocks_iterator)
            try:
                next_scoring = next(scorings_iterator)
            except StopIteration:
                raise MissingForkChoiceScoringFns

            score = next_scoring(curr_block_head)
            cls._set_block_score_to_db(db, curr_block_head, score)

        if no_canonical_head:
            return cls._set_as_canonical_chain_head(
                db, curr_block_head.signing_root, block_class)

        if score > head_score:
            return cls._set_as_canonical_chain_head(
                db, curr_block_head.signing_root, block_class)
        else:
            return tuple(), tuple()
Exemplo n.º 6
0
    def _persist_header_chain(
        cls,
        db: DatabaseAPI,
        headers: Iterable[BlockHeaderAPI],
        genesis_parent_hash: Hash32,
    ) -> Tuple[Tuple[BlockHeaderAPI, ...], Tuple[BlockHeaderAPI, ...]]:
        headers_iterator = iter(headers)

        try:
            first_header = first(headers_iterator)
        except StopIteration:
            return tuple(), tuple()

        is_genesis = first_header.parent_hash == genesis_parent_hash
        if not is_genesis and not cls._header_exists(db,
                                                     first_header.parent_hash):
            raise ParentNotFound(
                f"Cannot persist block header ({encode_hex(first_header.hash)}) "
                f"with unknown parent ({encode_hex(first_header.parent_hash)})"
            )

        if is_genesis:
            score = 0
        else:
            score = cls._get_score(db, first_header.parent_hash)

        curr_chain_head = first_header
        db.set(
            curr_chain_head.hash,
            rlp.encode(curr_chain_head),
        )
        score = cls._set_hash_scores_to_db(db, curr_chain_head, score)

        base_gaps = cls._get_header_chain_gaps(db)
        gap_info = cls._update_header_chain_gaps(db, curr_chain_head,
                                                 base_gaps)
        gaps = cls._handle_gap_change(db, gap_info, curr_chain_head,
                                      genesis_parent_hash)

        orig_headers_seq = concat([(first_header, ), headers_iterator])
        for parent, child in sliding_window(2, orig_headers_seq):
            if parent.hash != child.parent_hash:
                raise ValidationError(
                    f"Non-contiguous chain. Expected {encode_hex(child.hash)} "
                    f"to have {encode_hex(parent.hash)} as parent "
                    f"but was {encode_hex(child.parent_hash)}")

            curr_chain_head = child
            db.set(
                curr_chain_head.hash,
                rlp.encode(curr_chain_head),
            )

            score = cls._set_hash_scores_to_db(db, curr_chain_head, score)
            gap_info = cls._update_header_chain_gaps(db, curr_chain_head, gaps)
            gaps = cls._handle_gap_change(db, gap_info, curr_chain_head,
                                          genesis_parent_hash)
        try:
            previous_canonical_head = cls._get_canonical_head_hash(db)
            head_score = cls._get_score(db, previous_canonical_head)
        except CanonicalHeadNotFound:
            return cls._set_as_canonical_chain_head(db, curr_chain_head,
                                                    genesis_parent_hash)

        if score > head_score:
            return cls._set_as_canonical_chain_head(db, curr_chain_head,
                                                    genesis_parent_hash)

        return tuple(), tuple()
Exemplo n.º 7
0
    def _persist_block_chain(
        cls, db: BaseDB, blocks: Iterable[BaseBeaconBlock],
        block_class: Type[BaseBeaconBlock]
    ) -> Tuple[Tuple[BaseBeaconBlock, ...], Tuple[BaseBeaconBlock, ...]]:
        blocks_iterator = iter(blocks)

        try:
            first_block = first(blocks_iterator)
        except StopIteration:
            return tuple(), tuple()

        try:
            previous_canonical_head = cls._get_canonical_head(
                db, block_class).signed_root
            head_score = cls._get_score(db, previous_canonical_head)
        except CanonicalHeadNotFound:
            no_canonical_head = True
        else:
            no_canonical_head = False

        is_genesis = first_block.previous_block_root == GENESIS_PARENT_HASH
        if not is_genesis and not cls._block_exists(
                db, first_block.previous_block_root):
            raise ParentNotFound(
                "Cannot persist block ({}) with unknown parent ({})".format(
                    encode_hex(first_block.signed_root),
                    encode_hex(first_block.previous_block_root),
                ))

        if is_genesis:
            score = 0
            # TODO: this should probably be done as part of the fork choice rule processing
            db.set(
                SchemaV1.make_finalized_head_root_lookup_key(),
                first_block.signed_root,
            )
        else:
            score = first_block.slot

        curr_block_head = first_block
        db.set(
            curr_block_head.signed_root,
            ssz.encode(curr_block_head),
        )
        cls._add_block_root_to_slot_lookup(db, curr_block_head)
        cls._set_block_scores_to_db(db, curr_block_head)

        orig_blocks_seq = concat([(first_block, ), blocks_iterator])

        for parent, child in sliding_window(2, orig_blocks_seq):
            if parent.signed_root != child.previous_block_root:
                raise ValidationError(
                    "Non-contiguous chain. Expected {} to have {} as parent but was {}"
                    .format(
                        encode_hex(child.signed_root),
                        encode_hex(parent.signed_root),
                        encode_hex(child.previous_block_root),
                    ))

            curr_block_head = child
            db.set(
                curr_block_head.signed_root,
                ssz.encode(curr_block_head),
            )
            cls._add_block_root_to_slot_lookup(db, curr_block_head)
            score = cls._set_block_scores_to_db(db, curr_block_head)

        if no_canonical_head:
            return cls._set_as_canonical_chain_head(
                db, curr_block_head.signed_root, block_class)

        if score > head_score:
            return cls._set_as_canonical_chain_head(
                db, curr_block_head.signed_root, block_class)
        else:
            return tuple(), tuple()
Exemplo n.º 8
0
    def persist_header_chain(
        self, headers: Iterable[BlockHeader]
    ) -> Tuple[Tuple[BlockHeader, ...], Tuple[BlockHeader, ...]]:
        """
        Return two iterable of headers, the first containing the new canonical headers,
        the second containing the old canonical headers
        """

        try:
            first_header = first(headers)
        except StopIteration:
            return tuple(), tuple()
        else:

            for parent, child in sliding_window(2, headers):
                if parent.hash != child.parent_hash:
                    raise ValidationError(
                        "Non-contiguous chain. Expected {} to have {} as parent but was {}"
                        .format(
                            encode_hex(child.hash),
                            encode_hex(parent.hash),
                            encode_hex(child.parent_hash),
                        ))

            is_genesis = first_header.parent_hash == GENESIS_PARENT_HASH
            if not is_genesis and not self.header_exists(
                    first_header.parent_hash):
                raise ParentNotFound(
                    "Cannot persist block header ({}) with unknown parent ({})"
                    .format(encode_hex(first_header.hash),
                            encode_hex(first_header.parent_hash)))

            score = 0 if is_genesis else self.get_score(
                first_header.parent_hash)

        for header in headers:
            self.db.set(
                header.hash,
                rlp.encode(header),
            )

            score += header.difficulty

            self.db.set(
                SchemaV1.make_block_hash_to_score_lookup_key(header.hash),
                rlp.encode(score, sedes=rlp.sedes.big_endian_int),
            )

        try:
            head_score = self.get_score(self.get_canonical_head().hash)
        except CanonicalHeadNotFound:
            (new_canonical_headers,
             old_canonical_headers) = self._set_as_canonical_chain_head(
                 header.hash)
        else:
            if score > head_score:
                (new_canonical_headers,
                 old_canonical_headers) = self._set_as_canonical_chain_head(
                     header.hash)
            else:
                new_canonical_headers = tuple()
                old_canonical_headers = tuple()

        return new_canonical_headers, old_canonical_headers
Exemplo n.º 9
0
    def _persist_block_chain(
        cls, db: BaseDB, blocks: Iterable[BaseBeaconBlock],
        block_class: Type[BaseBeaconBlock]
    ) -> Tuple[Tuple[BaseBeaconBlock, ...], Tuple[BaseBeaconBlock, ...]]:
        blocks_iterator = iter(blocks)

        try:
            first_block = first(blocks_iterator)
        except StopIteration:
            return tuple(), tuple()

        is_genesis = first_block.parent_root == GENESIS_PARENT_HASH
        if not is_genesis and not cls._block_exists(db,
                                                    first_block.parent_root):
            raise ParentNotFound(
                "Cannot persist block ({}) with unknown parent ({})".format(
                    encode_hex(first_block.root),
                    encode_hex(first_block.parent_root)))

        if is_genesis:
            score = 0
        else:
            score = cls._get_score(db, first_block.parent_root)

        curr_block_head = first_block
        db.set(
            curr_block_head.root,
            rlp.encode(curr_block_head),
        )
        cls._set_block_scores_to_db(db, curr_block_head)

        orig_blocks_seq = concat([(first_block, ), blocks_iterator])

        for parent, child in sliding_window(2, orig_blocks_seq):
            if parent.root != child.parent_root:
                raise ValidationError(
                    "Non-contiguous chain. Expected {} to have {} as parent but was {}"
                    .format(
                        encode_hex(child.root),
                        encode_hex(parent.root),
                        encode_hex(child.parent_root),
                    ))

            curr_block_head = child
            db.set(
                curr_block_head.root,
                rlp.encode(curr_block_head),
            )
            cls._set_block_scores_to_db(db, curr_block_head)

        try:
            previous_canonical_head = cls._get_canonical_head(db,
                                                              block_class).root
            head_score = cls._get_score(db, previous_canonical_head)
        except CanonicalHeadNotFound:
            return cls._set_as_canonical_chain_head(db, curr_block_head.root,
                                                    block_class)

        if score > head_score:
            return cls._set_as_canonical_chain_head(db, curr_block_head.root,
                                                    block_class)
        else:
            return tuple(), tuple()