Ejemplo n.º 1
0
    async def validate_unfinished_block(
            self,
            block: UnfinishedBlock,
            skip_overflow_ss_validation=True) -> PreValidationResult:
        if (not self.contains_block(block.prev_header_hash)
                and not block.prev_header_hash
                == self.constants.GENESIS_CHALLENGE):
            return PreValidationResult(
                uint16(Err.INVALID_PREV_BLOCK_HASH.value), None, None)

        unfinished_header_block = UnfinishedHeaderBlock(
            block.finished_sub_slots,
            block.reward_chain_block,
            block.challenge_chain_sp_proof,
            block.reward_chain_sp_proof,
            block.foliage,
            block.foliage_transaction_block,
            b"",
        )
        prev_b = self.try_block_record(
            unfinished_header_block.prev_header_hash)
        sub_slot_iters, difficulty = get_next_sub_slot_iters_and_difficulty(
            self.constants,
            len(unfinished_header_block.finished_sub_slots) > 0, prev_b, self)
        required_iters, error = validate_unfinished_header_block(
            self.constants,
            self,
            unfinished_header_block,
            False,
            difficulty,
            sub_slot_iters,
            skip_overflow_ss_validation,
        )

        if error is not None:
            return PreValidationResult(uint16(error.code.value), None, None)

        prev_height = (-1 if block.prev_header_hash
                       == self.constants.GENESIS_CHALLENGE else
                       self.block_record(block.prev_header_hash).height)

        error_code, cost_result = await validate_block_body(
            self.constants,
            self,
            self.block_store,
            self.coin_store,
            self.get_peak(),
            block,
            uint32(prev_height + 1),
            None,
        )

        if error_code is not None:
            return PreValidationResult(uint16(error_code.value), None, None)

        return PreValidationResult(None, required_iters, cost_result)
Ejemplo n.º 2
0
    async def validate_unfinished_block(
        self, block: UnfinishedBlock, skip_overflow_ss_validation=True
    ) -> Tuple[Optional[uint64], Optional[Err]]:
        if (
            not self.contains_sub_block(block.prev_header_hash)
            and not block.prev_header_hash == self.constants.GENESIS_CHALLENGE
        ):
            return None, Err.INVALID_PREV_BLOCK_HASH

        unfinished_header_block = UnfinishedHeaderBlock(
            block.finished_sub_slots,
            block.reward_chain_sub_block,
            block.challenge_chain_sp_proof,
            block.reward_chain_sp_proof,
            block.foliage_sub_block,
            block.foliage_block,
            b"",
        )
        prev_sb = self.try_sub_block(unfinished_header_block.prev_header_hash)
        sub_slot_iters, difficulty = get_sub_slot_iters_and_difficulty(
            self.constants, unfinished_header_block, prev_sb, self
        )
        required_iters, error = validate_unfinished_header_block(
            self.constants,
            self,
            unfinished_header_block,
            False,
            difficulty,
            sub_slot_iters,
            skip_overflow_ss_validation,
        )

        if error is not None:
            return None, error.code

        prev_height = (
            -1
            if block.prev_header_hash == self.constants.GENESIS_CHALLENGE
            else self.sub_block_record(block.prev_header_hash).height
        )

        error_code = await validate_block_body(
            self.constants,
            self,
            self.block_store,
            self.coin_store,
            self.get_peak(),
            block,
            uint32(prev_height + 1),
            None,
        )

        if error_code is not None:
            return None, error_code

        return required_iters, None
    async def receive_block(
        self,
        block_record: HeaderBlockRecord,
        pre_validation_result: Optional[PreValidationResult] = None,
        trusted: bool = False,
        fork_point_with_peak: Optional[uint32] = None,
    ) -> Tuple[ReceiveBlockResult, Optional[Err], Optional[uint32]]:
        """
        Adds a new block into the blockchain, if it's valid and connected to the current
        blockchain, regardless of whether it is the child of a head, or another block.
        Returns a header if block is added to head. Returns an error if the block is
        invalid. Also returns the fork height, in the case of a new peak.
        """
        block = block_record.header
        genesis: bool = block.height == 0

        if self.contains_sub_block(block.header_hash):
            return ReceiveBlockResult.ALREADY_HAVE_BLOCK, None, None

        if not self.contains_sub_block(block.prev_header_hash) and not genesis:
            return (
                ReceiveBlockResult.DISCONNECTED_BLOCK,
                Err.INVALID_PREV_BLOCK_HASH,
                None,
            )

        if block.height == 0:
            prev_sb: Optional[SubBlockRecord] = None
        else:
            prev_sb = self.sub_block_record(block.prev_header_hash)
        sub_slot_iters, difficulty = get_sub_slot_iters_and_difficulty(
            self.constants, block, prev_sb, self)

        if trusted is False and pre_validation_result is None:
            required_iters, error = validate_finished_header_block(
                self.constants, self, block, False, difficulty, sub_slot_iters)
        elif trusted:
            unfinished_header_block = UnfinishedHeaderBlock(
                block.finished_sub_slots,
                block.reward_chain_sub_block.get_unfinished(),
                block.challenge_chain_sp_proof,
                block.reward_chain_sp_proof,
                block.foliage_sub_block,
                block.foliage_block,
                block.transactions_filter,
            )

            required_iters, val_error = validate_unfinished_header_block(
                self.constants, self, unfinished_header_block, False,
                difficulty, sub_slot_iters, False, True)
            error = ValidationError(
                Err(val_error)) if val_error is not None else None
        else:
            assert pre_validation_result is not None
            required_iters = pre_validation_result.required_iters
            error = (ValidationError(Err(pre_validation_result.error))
                     if pre_validation_result.error is not None else None)

        if error is not None:
            return ReceiveBlockResult.INVALID_BLOCK, error.code, None
        assert required_iters is not None

        sub_block = block_to_sub_block_record(
            self.constants,
            self,
            required_iters,
            None,
            block,
        )

        # Always add the block to the database
        await self.block_store.add_block_record(block_record, sub_block)
        self.add_sub_block(sub_block)
        self.clean_sub_block_record(sub_block.height -
                                    self.constants.SUB_BLOCKS_CACHE_SIZE)

        fork_height: Optional[uint32] = await self._reconsider_peak(
            sub_block, genesis, fork_point_with_peak)
        if fork_height is not None:
            self.log.info(
                f"💰 Updated wallet peak to sub height {sub_block.height}, weight {sub_block.weight}, "
            )
            return ReceiveBlockResult.NEW_PEAK, None, fork_height
        else:
            return ReceiveBlockResult.ADDED_AS_ORPHAN, None, None
Ejemplo n.º 4
0
    async def validate_unfinished_block(
        self,
        block: UnfinishedBlock,
        skip_overflow_ss_validation=True
    ) -> Tuple[Optional[uint64], Optional[Err]]:
        if (block.prev_header_hash not in self.sub_blocks
                and not block.prev_header_hash
                == self.constants.GENESIS_PREV_HASH):
            return None, Err.INVALID_PREV_BLOCK_HASH

        unfinished_header_block = UnfinishedHeaderBlock(
            block.finished_sub_slots,
            block.reward_chain_sub_block,
            block.challenge_chain_sp_proof,
            block.reward_chain_sp_proof,
            block.foliage_sub_block,
            block.foliage_block,
            b"",
        )
        prev_sb = self.sub_blocks.get(unfinished_header_block.prev_header_hash,
                                      None)
        sub_slot_iters, difficulty = get_sub_slot_iters_and_difficulty(
            self.constants, unfinished_header_block, self.sub_height_to_hash,
            prev_sb, self.sub_blocks)
        required_iters, error = validate_unfinished_header_block(
            self.constants,
            self.sub_blocks,
            unfinished_header_block,
            False,
            difficulty,
            sub_slot_iters,
            skip_overflow_ss_validation,
        )

        if error is not None:
            return None, error.code

        prev_sub_height = (
            -1 if block.prev_header_hash == self.constants.GENESIS_PREV_HASH
            else self.sub_blocks[block.prev_header_hash].sub_block_height)

        if block.is_block():
            assert block.foliage_block is not None
            height: Optional[uint32] = block.foliage_block.height
        else:
            height = None
        error_code = await validate_block_body(
            self.constants,
            self.sub_blocks,
            self.sub_height_to_hash,
            self.block_store,
            self.coin_store,
            self.get_peak(),
            block,
            uint32(prev_sub_height + 1),
            height,
        )

        if error_code is not None:
            return None, error_code

        return required_iters, None