コード例 #1
0
def validate_finished_header_block(
    constants: ConsensusConstants,
    blocks: BlockchainInterface,
    header_block: HeaderBlock,
    check_filter: bool,
    expected_difficulty: uint64,
    expected_sub_slot_iters: uint64,
) -> Tuple[Optional[uint64], Optional[ValidationError]]:
    """
    Fully validates the header of a block. A header block is the same  as a full block, but
    without transactions and transaction info. Returns (required_iters, error).
    """
    unfinished_header_block = UnfinishedHeaderBlock(
        header_block.finished_sub_slots,
        header_block.reward_chain_block.get_unfinished(),
        header_block.challenge_chain_sp_proof,
        header_block.reward_chain_sp_proof,
        header_block.foliage,
        header_block.foliage_transaction_block,
        header_block.transactions_filter,
    )

    required_iters, validate_unfinished_err = validate_unfinished_header_block(
        constants,
        blocks,
        unfinished_header_block,
        check_filter,
        expected_difficulty,
        expected_sub_slot_iters,
        False,
    )

    genesis_block = False
    if validate_unfinished_err is not None:
        return None, validate_unfinished_err

    assert required_iters is not None

    if header_block.height == 0:
        prev_b: Optional[BlockRecord] = None
        genesis_block = True
    else:
        prev_b = blocks.block_record(header_block.prev_header_hash)
    new_sub_slot: bool = len(header_block.finished_sub_slots) > 0

    ip_iters: uint64 = calculate_ip_iters(
        constants,
        expected_sub_slot_iters,
        header_block.reward_chain_block.signage_point_index,
        required_iters,
    )
    if not genesis_block:
        assert prev_b is not None
        # 27. Check block height
        if header_block.height != prev_b.height + 1:
            return None, ValidationError(Err.INVALID_HEIGHT)

        # 28. Check weight
        if header_block.weight != prev_b.weight + expected_difficulty:
            log.error(
                f"INVALID WEIGHT: {header_block} {prev_b} {expected_difficulty}"
            )
            return None, ValidationError(Err.INVALID_WEIGHT)
    else:
        if header_block.height != uint32(0):
            return None, ValidationError(Err.INVALID_HEIGHT)
        if header_block.weight != constants.DIFFICULTY_STARTING:
            return None, ValidationError(Err.INVALID_WEIGHT)

    # RC vdf challenge is taken from more recent of (slot start, prev_block)
    if genesis_block:
        cc_vdf_output = ClassgroupElement.get_default_element()
        ip_vdf_iters = ip_iters
        if new_sub_slot:
            rc_vdf_challenge = header_block.finished_sub_slots[
                -1].reward_chain.get_hash()
        else:
            rc_vdf_challenge = constants.GENESIS_CHALLENGE
    else:
        assert prev_b is not None
        if new_sub_slot:
            # slot start is more recent
            rc_vdf_challenge = header_block.finished_sub_slots[
                -1].reward_chain.get_hash()
            ip_vdf_iters = ip_iters
            cc_vdf_output = ClassgroupElement.get_default_element()

        else:
            # Prev sb is more recent
            rc_vdf_challenge = prev_b.reward_infusion_new_challenge
            ip_vdf_iters = uint64(header_block.reward_chain_block.total_iters -
                                  prev_b.total_iters)
            cc_vdf_output = prev_b.challenge_vdf_output

    # 29. Check challenge chain infusion point VDF
    if new_sub_slot:
        cc_vdf_challenge = header_block.finished_sub_slots[
            -1].challenge_chain.get_hash()
    else:
        # Not first block in slot
        if genesis_block:
            # genesis block
            cc_vdf_challenge = constants.GENESIS_CHALLENGE
        else:
            assert prev_b is not None
            # Not genesis block, go back to first block in slot
            curr = prev_b
            while curr.finished_challenge_slot_hashes is None:
                curr = blocks.block_record(curr.prev_hash)
            cc_vdf_challenge = curr.finished_challenge_slot_hashes[-1]

    cc_target_vdf_info = VDFInfo(
        cc_vdf_challenge,
        ip_vdf_iters,
        header_block.reward_chain_block.challenge_chain_ip_vdf.output,
    )
    if header_block.reward_chain_block.challenge_chain_ip_vdf != dataclasses.replace(
            cc_target_vdf_info,
            number_of_iterations=ip_iters,
    ):
        expected = dataclasses.replace(
            cc_target_vdf_info,
            number_of_iterations=ip_iters,
        )
        log.error(
            f"{header_block.reward_chain_block.challenge_chain_ip_vdf }. expected {expected}"
        )
        log.error(f"Block: {header_block}")
        return None, ValidationError(Err.INVALID_CC_IP_VDF)
    if not header_block.challenge_chain_ip_proof.is_valid(
            constants,
            cc_vdf_output,
            cc_target_vdf_info,
            None,
    ):
        log.error(f"Did not validate, output {cc_vdf_output}")
        log.error(f"Block: {header_block}")
        return None, ValidationError(Err.INVALID_CC_IP_VDF)

    # 30. Check reward chain infusion point VDF
    rc_target_vdf_info = VDFInfo(
        rc_vdf_challenge,
        ip_vdf_iters,
        header_block.reward_chain_block.reward_chain_ip_vdf.output,
    )
    if not header_block.reward_chain_ip_proof.is_valid(
            constants,
            ClassgroupElement.get_default_element(),
            header_block.reward_chain_block.reward_chain_ip_vdf,
            rc_target_vdf_info,
    ):
        return None, ValidationError(Err.INVALID_RC_IP_VDF)

    # 31. Check infused challenge chain infusion point VDF
    if not genesis_block:
        overflow = is_overflow_block(
            constants, header_block.reward_chain_block.signage_point_index)
        deficit = calculate_deficit(
            constants,
            header_block.height,
            prev_b,
            overflow,
            len(header_block.finished_sub_slots),
        )

        if header_block.reward_chain_block.infused_challenge_chain_ip_vdf is None:
            # If we don't have an ICC chain, deficit must be 4 or 5
            if deficit < constants.MIN_BLOCKS_PER_CHALLENGE_BLOCK - 1:
                return None, ValidationError(Err.INVALID_ICC_VDF)
        else:
            assert header_block.infused_challenge_chain_ip_proof is not None
            # If we have an ICC chain, deficit must be 0, 1, 2 or 3
            if deficit >= constants.MIN_BLOCKS_PER_CHALLENGE_BLOCK - 1:
                return (
                    None,
                    ValidationError(
                        Err.INVALID_ICC_VDF,
                        f"icc vdf and deficit is bigger or equal to {constants.MIN_BLOCKS_PER_CHALLENGE_BLOCK - 1}",
                    ),
                )
            if new_sub_slot:
                last_ss = header_block.finished_sub_slots[-1]
                assert last_ss.infused_challenge_chain is not None
                icc_vdf_challenge: bytes32 = last_ss.infused_challenge_chain.get_hash(
                )
                icc_vdf_input = ClassgroupElement.get_default_element()
            else:
                assert prev_b is not None
                if prev_b.is_challenge_block(constants):
                    icc_vdf_input = ClassgroupElement.get_default_element()
                else:
                    icc_vdf_input = prev_b.infused_challenge_vdf_output
                curr = prev_b
                while curr.finished_infused_challenge_slot_hashes is None and not curr.is_challenge_block(
                        constants):
                    curr = blocks.block_record(curr.prev_hash)

                if curr.is_challenge_block(constants):
                    icc_vdf_challenge = curr.challenge_block_info_hash
                else:
                    assert curr.finished_infused_challenge_slot_hashes is not None
                    icc_vdf_challenge = curr.finished_infused_challenge_slot_hashes[
                        -1]

            icc_target_vdf_info = VDFInfo(
                icc_vdf_challenge,
                ip_vdf_iters,
                header_block.reward_chain_block.infused_challenge_chain_ip_vdf.
                output,
            )
            if not header_block.infused_challenge_chain_ip_proof.is_valid(
                    constants,
                    icc_vdf_input,
                    header_block.reward_chain_block.
                    infused_challenge_chain_ip_vdf,
                    icc_target_vdf_info,
            ):
                return None, ValidationError(Err.INVALID_ICC_VDF,
                                             "invalid icc proof")
    else:
        if header_block.infused_challenge_chain_ip_proof is not None:
            return None, ValidationError(Err.INVALID_ICC_VDF)

    # 32. Check reward block hash
    if header_block.foliage.reward_block_hash != header_block.reward_chain_block.get_hash(
    ):
        return None, ValidationError(Err.INVALID_REWARD_BLOCK_HASH)

    # 33. Check reward block is_transaction_block
    if (header_block.foliage.foliage_transaction_block_hash is not None
        ) != header_block.reward_chain_block.is_transaction_block:
        return None, ValidationError(Err.INVALID_FOLIAGE_BLOCK_PRESENCE)

    return required_iters, None
コード例 #2
0
def block_to_block_record(
    constants: ConsensusConstants,
    blocks: BlockchainInterface,
    required_iters: uint64,
    full_block: Optional[Union[FullBlock, HeaderBlock]],
    header_block: Optional[HeaderBlock],
):

    if full_block is None:
        assert header_block is not None
        block: Union[HeaderBlock, FullBlock] = header_block
    else:
        block = full_block
    prev_b = blocks.try_block_record(block.prev_header_hash)
    if block.height > 0:
        assert prev_b is not None
    sub_slot_iters, _ = get_next_sub_slot_iters_and_difficulty(
        constants,
        len(block.finished_sub_slots) > 0, prev_b, blocks)
    overflow = is_overflow_block(constants,
                                 block.reward_chain_block.signage_point_index)
    deficit = calculate_deficit(
        constants,
        block.height,
        prev_b,
        overflow,
        len(block.finished_sub_slots),
    )

    found_ses_hash: Optional[bytes32] = None
    ses: Optional[SubEpochSummary] = None
    if len(block.finished_sub_slots) > 0:
        for sub_slot in block.finished_sub_slots:
            if sub_slot.challenge_chain.subepoch_summary_hash is not None:
                found_ses_hash = sub_slot.challenge_chain.subepoch_summary_hash
    if found_ses_hash:
        assert prev_b is not None
        assert len(block.finished_sub_slots) > 0
        ses = make_sub_epoch_summary(
            constants,
            blocks,
            block.height,
            blocks.block_record(prev_b.prev_hash),
            block.finished_sub_slots[0].challenge_chain.new_difficulty,
            block.finished_sub_slots[0].challenge_chain.new_sub_slot_iters,
        )
        assert ses.get_hash() == found_ses_hash

    prev_transaction_block_height = uint32(0)
    curr: Optional[BlockRecord] = blocks.try_block_record(
        block.prev_header_hash)
    while curr is not None and not curr.is_transaction_block:
        curr = blocks.try_block_record(curr.prev_hash)

    if curr is not None and curr.is_transaction_block:
        prev_transaction_block_height = curr.height

    return header_block_to_sub_block_record(
        constants,
        required_iters,
        block,
        sub_slot_iters,
        overflow,
        deficit,
        prev_transaction_block_height,
        ses,
    )
コード例 #3
0
def next_sub_epoch_summary(
    constants: ConsensusConstants,
    blocks: BlockchainInterface,
    required_iters: uint64,
    block: Union[UnfinishedBlock, FullBlock],
    can_finish_soon: bool = False,
) -> Optional[SubEpochSummary]:
    """
    Returns the sub-epoch summary that can be included in the block after block. If it should include one. Block
    must be eligible to be the last block in the epoch. If not, returns None. Assumes that there is a new slot
    ending after block.

    Args:
        constants: consensus constants being used for this chain
        blocks: interface to cached SBR
        required_iters: required iters of the proof of space in block
        block: the (potentially) last block in the new epoch
        can_finish_soon: this is useful when sending SES to timelords. We might not be able to finish it, but we will
            soon (within MAX_SUB_SLOT_BLOCKS)

    Returns:
        object: the new sub-epoch summary
    """
    signage_point_index = block.reward_chain_block.signage_point_index
    prev_b: Optional[BlockRecord] = blocks.try_block_record(
        block.prev_header_hash)
    if prev_b is None or prev_b.height == 0:
        return None

    if len(block.finished_sub_slots) > 0 and block.finished_sub_slots[
            0].challenge_chain.new_difficulty is not None:
        # We just included a sub-epoch summary
        return None

    assert prev_b is not None
    # This is the ssi of the current block
    sub_slot_iters = get_next_sub_slot_iters(
        constants,
        blocks,
        prev_b.prev_hash,
        prev_b.height,
        prev_b.sub_slot_iters,
        prev_b.deficit,
        len(block.finished_sub_slots) > 0,
        prev_b.sp_total_iters(constants),
    )
    overflow = is_overflow_block(constants, signage_point_index)
    deficit = calculate_deficit(
        constants,
        uint32(prev_b.height + 1),
        prev_b,
        overflow,
        len(block.finished_sub_slots),
    )
    can_finish_se, can_finish_epoch = can_finish_sub_and_full_epoch(
        constants,
        uint32(prev_b.height + 1),
        deficit,
        blocks,
        prev_b.header_hash if prev_b is not None else None,
        can_finish_soon,
    )

    # can't finish se, no summary
    if not can_finish_se:
        return None

    next_difficulty = None
    next_sub_slot_iters = None

    # if can finish epoch, new difficulty and ssi
    if can_finish_epoch:
        sp_iters = calculate_sp_iters(constants, sub_slot_iters,
                                      signage_point_index)
        ip_iters = calculate_ip_iters(constants, sub_slot_iters,
                                      signage_point_index, required_iters)
        next_difficulty = get_next_difficulty(
            constants,
            blocks,
            block.prev_header_hash,
            uint32(prev_b.height + 1),
            uint64(prev_b.weight -
                   blocks.block_record(prev_b.prev_hash).weight),
            deficit,
            True,
            uint128(block.total_iters - ip_iters + sp_iters -
                    (sub_slot_iters if overflow else 0)),
            True,
        )
        next_sub_slot_iters = get_next_sub_slot_iters(
            constants,
            blocks,
            block.prev_header_hash,
            uint32(prev_b.height + 1),
            sub_slot_iters,
            deficit,
            True,
            uint128(block.total_iters - ip_iters + sp_iters -
                    (sub_slot_iters if overflow else 0)),
            True,
        )

    return make_sub_epoch_summary(
        constants,
        blocks,
        uint32(prev_b.height + 2),
        prev_b,
        next_difficulty,
        next_sub_slot_iters,
    )
def block_to_sub_block_record(
    constants: ConsensusConstants,
    sub_blocks: Dict[bytes32, SubBlockRecord],
    height_to_hash: Dict[uint32, bytes32],
    required_iters: uint64,
    full_block: Optional[Union[FullBlock, HeaderBlock]],
    header_block: Optional[HeaderBlock],
):

    if full_block is None:
        assert header_block is not None
        block: Union[HeaderBlock, FullBlock] = header_block
    else:
        block = full_block
    if block.sub_block_height == 0:
        prev_sb: Optional[SubBlockRecord] = None
        sub_slot_iters: uint64 = uint64(constants.SUB_SLOT_ITERS_STARTING)
        height = 0
    else:
        prev_sb = sub_blocks[block.prev_header_hash]
        assert prev_sb is not None
        if prev_sb.is_block:
            height = prev_sb.height + 1
        else:
            height = prev_sb.height
        sub_slot_iters = get_next_sub_slot_iters(
            constants,
            sub_blocks,
            height_to_hash,
            prev_sb.prev_hash,
            prev_sb.sub_block_height,
            prev_sb.sub_slot_iters,
            prev_sb.deficit,
            len(block.finished_sub_slots) > 0,
            prev_sb.sp_total_iters(constants),
        )
    overflow = is_overflow_sub_block(
        constants, block.reward_chain_sub_block.signage_point_index)
    deficit = calculate_deficit(
        constants,
        block.sub_block_height,
        prev_sb,
        overflow,
        len(block.finished_sub_slots),
    )
    prev_block_hash = block.foliage_block.prev_block_hash if block.foliage_block is not None else None
    timestamp = block.foliage_block.timestamp if block.foliage_block is not None else None
    fees = block.transactions_info.fees if block.transactions_info is not None else None
    # reward_claims_incorporated = (
    #     block.transactions_info.reward_claims_incorporated if block.transactions_info is not None else None
    # )

    if len(block.finished_sub_slots) > 0:
        finished_challenge_slot_hashes: Optional[List[bytes32]] = [
            sub_slot.challenge_chain.get_hash()
            for sub_slot in block.finished_sub_slots
        ]
        finished_reward_slot_hashes: Optional[List[bytes32]] = [
            sub_slot.reward_chain.get_hash()
            for sub_slot in block.finished_sub_slots
        ]
        finished_infused_challenge_slot_hashes: Optional[List[bytes32]] = [
            sub_slot.infused_challenge_chain.get_hash()
            for sub_slot in block.finished_sub_slots
            if sub_slot.infused_challenge_chain is not None
        ]
    elif block.sub_block_height == 0:
        finished_challenge_slot_hashes = [constants.FIRST_CC_CHALLENGE]
        finished_reward_slot_hashes = [constants.FIRST_RC_CHALLENGE]
        finished_infused_challenge_slot_hashes = None
    else:
        finished_challenge_slot_hashes = None
        finished_reward_slot_hashes = None
        finished_infused_challenge_slot_hashes = None

    found_ses_hash: Optional[bytes32] = None
    ses: Optional[SubEpochSummary] = None
    if len(block.finished_sub_slots) > 0:
        for sub_slot in block.finished_sub_slots:
            if sub_slot.challenge_chain.subepoch_summary_hash is not None:
                found_ses_hash = sub_slot.challenge_chain.subepoch_summary_hash
    if found_ses_hash:
        assert prev_sb is not None
        assert len(block.finished_sub_slots) > 0
        ses = make_sub_epoch_summary(
            constants,
            sub_blocks,
            block.sub_block_height,
            sub_blocks[prev_sb.prev_hash],
            block.finished_sub_slots[0].challenge_chain.new_difficulty,
            block.finished_sub_slots[0].challenge_chain.new_sub_slot_iters,
        )
        assert ses.get_hash() == found_ses_hash

    cbi = ChallengeBlockInfo(
        block.reward_chain_sub_block.proof_of_space,
        block.reward_chain_sub_block.challenge_chain_sp_vdf,
        block.reward_chain_sub_block.challenge_chain_sp_signature,
        block.reward_chain_sub_block.challenge_chain_ip_vdf,
    )

    if block.reward_chain_sub_block.infused_challenge_chain_ip_vdf is not None:
        icc_output: Optional[
            ClassgroupElement] = block.reward_chain_sub_block.infused_challenge_chain_ip_vdf.output
    else:
        icc_output = None
    return SubBlockRecord(
        block.header_hash,
        block.prev_header_hash,
        block.sub_block_height,
        uint32(height),
        block.weight,
        block.total_iters,
        block.reward_chain_sub_block.signage_point_index,
        block.reward_chain_sub_block.challenge_chain_ip_vdf.output,
        icc_output,
        block.reward_chain_sub_block.get_hash(),
        cbi.get_hash(),
        sub_slot_iters,
        block.foliage_sub_block.foliage_sub_block_data.pool_target.puzzle_hash,
        block.foliage_sub_block.foliage_sub_block_data.
        farmer_reward_puzzle_hash,
        required_iters,
        deficit,
        overflow,
        timestamp,
        prev_block_hash,
        fees,
        # reward_claims_incorporated,
        finished_challenge_slot_hashes,
        finished_infused_challenge_slot_hashes,
        finished_reward_slot_hashes,
        ses,
    )
コード例 #5
0
def block_to_block_record(
    constants: ConsensusConstants,
    blocks: BlockchainInterface,
    required_iters: uint64,
    full_block: Optional[Union[FullBlock, HeaderBlock]],
    header_block: Optional[HeaderBlock],
):

    if full_block is None:
        assert header_block is not None
        block: Union[HeaderBlock, FullBlock] = header_block
    else:
        block = full_block
    if block.height == 0:
        prev_b: Optional[BlockRecord] = None
        sub_slot_iters: uint64 = uint64(constants.SUB_SLOT_ITERS_STARTING)
    else:
        prev_b = blocks.block_record(block.prev_header_hash)
        assert prev_b is not None
        sub_slot_iters = get_next_sub_slot_iters(
            constants,
            blocks,
            prev_b.prev_hash,
            prev_b.height,
            prev_b.sub_slot_iters,
            prev_b.deficit,
            len(block.finished_sub_slots) > 0,
            prev_b.sp_total_iters(constants),
        )
    overflow = is_overflow_block(constants,
                                 block.reward_chain_block.signage_point_index)
    deficit = calculate_deficit(
        constants,
        block.height,
        prev_b,
        overflow,
        len(block.finished_sub_slots),
    )
    prev_transaction_block_hash = (
        block.foliage_transaction_block.prev_transaction_block_hash
        if block.foliage_transaction_block is not None else None)
    timestamp = block.foliage_transaction_block.timestamp if block.foliage_transaction_block is not None else None
    fees = block.transactions_info.fees if block.transactions_info is not None else None
    reward_claims_incorporated = (
        block.transactions_info.reward_claims_incorporated
        if block.transactions_info is not None else None)

    if len(block.finished_sub_slots) > 0:
        finished_challenge_slot_hashes: Optional[List[bytes32]] = [
            sub_slot.challenge_chain.get_hash()
            for sub_slot in block.finished_sub_slots
        ]
        finished_reward_slot_hashes: Optional[List[bytes32]] = [
            sub_slot.reward_chain.get_hash()
            for sub_slot in block.finished_sub_slots
        ]
        finished_infused_challenge_slot_hashes: Optional[List[bytes32]] = [
            sub_slot.infused_challenge_chain.get_hash()
            for sub_slot in block.finished_sub_slots
            if sub_slot.infused_challenge_chain is not None
        ]
    elif block.height == 0:
        finished_challenge_slot_hashes = [constants.GENESIS_CHALLENGE]
        finished_reward_slot_hashes = [constants.GENESIS_CHALLENGE]
        finished_infused_challenge_slot_hashes = None
    else:
        finished_challenge_slot_hashes = None
        finished_reward_slot_hashes = None
        finished_infused_challenge_slot_hashes = None

    found_ses_hash: Optional[bytes32] = None
    ses: Optional[SubEpochSummary] = None
    if len(block.finished_sub_slots) > 0:
        for sub_slot in block.finished_sub_slots:
            if sub_slot.challenge_chain.subepoch_summary_hash is not None:
                found_ses_hash = sub_slot.challenge_chain.subepoch_summary_hash
    if found_ses_hash:
        assert prev_b is not None
        assert len(block.finished_sub_slots) > 0
        ses = make_sub_epoch_summary(
            constants,
            blocks,
            block.height,
            blocks.block_record(prev_b.prev_hash),
            block.finished_sub_slots[0].challenge_chain.new_difficulty,
            block.finished_sub_slots[0].challenge_chain.new_sub_slot_iters,
        )
        assert ses.get_hash() == found_ses_hash

    cbi = ChallengeBlockInfo(
        block.reward_chain_block.proof_of_space,
        block.reward_chain_block.challenge_chain_sp_vdf,
        block.reward_chain_block.challenge_chain_sp_signature,
        block.reward_chain_block.challenge_chain_ip_vdf,
    )

    if block.reward_chain_block.infused_challenge_chain_ip_vdf is not None:
        icc_output: Optional[
            ClassgroupElement] = block.reward_chain_block.infused_challenge_chain_ip_vdf.output
    else:
        icc_output = None

    prev_transaction_block_height = uint32(0)
    curr: Optional[BlockRecord] = blocks.try_block_record(
        block.prev_header_hash)
    while curr is not None and not curr.is_transaction_block:
        curr = blocks.try_block_record(curr.prev_hash)

    if curr is not None and curr.is_transaction_block:
        prev_transaction_block_height = curr.height

    return BlockRecord(
        block.header_hash,
        block.prev_header_hash,
        block.height,
        block.weight,
        block.total_iters,
        block.reward_chain_block.signage_point_index,
        block.reward_chain_block.challenge_chain_ip_vdf.output,
        icc_output,
        block.reward_chain_block.get_hash(),
        cbi.get_hash(),
        sub_slot_iters,
        block.foliage.foliage_block_data.pool_target.puzzle_hash,
        block.foliage.foliage_block_data.farmer_reward_puzzle_hash,
        required_iters,
        deficit,
        overflow,
        prev_transaction_block_height,
        timestamp,
        prev_transaction_block_hash,
        fees,
        reward_claims_incorporated,
        finished_challenge_slot_hashes,
        finished_infused_challenge_slot_hashes,
        finished_reward_slot_hashes,
        ses,
    )
コード例 #6
0
def finish_sub_block(
    constants: ConsensusConstants,
    sub_blocks: Dict[bytes32, SubBlockRecord],
    height_to_hash: Dict[uint32, bytes32],
    finished_sub_slots: List[EndOfSubSlotBundle],
    sub_slot_start_total_iters: uint128,
    signage_point_index: uint8,
    unfinished_block: UnfinishedBlock,
    required_iters: uint64,
    ip_iters: uint64,
    slot_cc_challenge: bytes32,
    slot_rc_challenge: bytes32,
    latest_sub_block: SubBlockRecord,
    sub_slot_iters: uint64,
    difficulty: uint64,
):
    is_overflow = is_overflow_sub_block(constants, signage_point_index)
    cc_vdf_challenge = slot_cc_challenge
    if len(finished_sub_slots) == 0:
        new_ip_iters = unfinished_block.total_iters - latest_sub_block.total_iters
        cc_vdf_input = latest_sub_block.challenge_vdf_output
        rc_vdf_challenge = latest_sub_block.reward_infusion_new_challenge
    else:
        new_ip_iters = ip_iters
        cc_vdf_input = ClassgroupElement.get_default_element()
        rc_vdf_challenge = slot_rc_challenge
    cc_ip_vdf, cc_ip_proof = get_vdf_info_and_proof(
        constants,
        cc_vdf_input,
        cc_vdf_challenge,
        new_ip_iters,
    )
    cc_ip_vdf = replace(cc_ip_vdf, number_of_iterations=ip_iters)
    deficit = calculate_deficit(
        constants,
        uint32(latest_sub_block.sub_block_height + 1),
        latest_sub_block,
        is_overflow,
        len(finished_sub_slots),
    )

    icc_ip_vdf, icc_ip_proof = get_icc(
        constants,
        unfinished_block.total_iters,
        finished_sub_slots,
        latest_sub_block,
        sub_blocks,
        uint128(sub_slot_start_total_iters + sub_slot_iters) if is_overflow else sub_slot_start_total_iters,
        deficit,
    )

    rc_ip_vdf, rc_ip_proof = get_vdf_info_and_proof(
        constants,
        ClassgroupElement.get_default_element(),
        rc_vdf_challenge,
        new_ip_iters,
    )
    assert unfinished_block is not None
    sp_total_iters = uint128(
        sub_slot_start_total_iters + calculate_sp_iters(constants, sub_slot_iters, signage_point_index)
    )
    full_block: FullBlock = unfinished_block_to_full_block(
        unfinished_block,
        cc_ip_vdf,
        cc_ip_proof,
        rc_ip_vdf,
        rc_ip_proof,
        icc_ip_vdf,
        icc_ip_proof,
        finished_sub_slots,
        latest_sub_block,
        sub_blocks,
        sp_total_iters,
        difficulty,
    )

    sub_block_record = block_to_sub_block_record(
        constants, sub_blocks, height_to_hash, required_iters, full_block, None
    )
    return full_block, sub_block_record