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
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()
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()
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
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()
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()
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()
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
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()