Exemplo n.º 1
0
async def get_total_miniters(rpc_client, old_block, new_block):
    """
    Calculates the sum of min_iters from all blocks starting from old and up to and including
    new_block, but not including old_block.
    """
    old_block_parent = await rpc_client.get_header(old_block.prev_header_hash)
    old_diff = old_block.weight - old_block_parent.weight
    curr_mi = calculate_min_iters_from_iterations(
        old_block.proof_of_space, old_diff, old_block.proof_of_time.number_of_iterations
    )
    # We do not count the min iters in the old block, since it's not included in the range
    total_mi: uint64 = uint64(0)
    for curr_h in range(old_block.height + 1, new_block.height + 1):
        if (curr_h % constants["DIFFICULTY_EPOCH"]) == constants["DIFFICULTY_DELAY"]:
            curr_b_header = await rpc_client.get_header_by_height(curr_h)
            curr_b_block = await rpc_client.get_block(curr_b_header.header_hash)
            curr_parent = await rpc_client.get_header(curr_b_block.prev_header_hash)
            curr_diff = curr_b_block.weight - curr_parent.weight
            curr_mi = calculate_min_iters_from_iterations(
                curr_b_block.proof_of_space,
                curr_diff,
                curr_b_block.proof_of_time.number_of_iterations,
            )
        total_mi = uint64(total_mi + curr_mi)

    print("Minimum iterations:", total_mi)
    return total_mi
Exemplo n.º 2
0
    async def get_total_miniters(self, newer_block, older_block) -> Optional[uint64]:
        """
        Calculates the sum of min_iters from all blocks starting from
        old and up to and including new_block, but not including old_block.
        """
        older_block_parent = await self.service.block_store.get_block(
            older_block.prev_header_hash
        )
        if older_block_parent is None:
            return None
        older_diff = older_block.weight - older_block_parent.weight
        curr_mi = calculate_min_iters_from_iterations(
            older_block.proof_of_space,
            older_diff,
            older_block.proof_of_time.number_of_iterations,
            self.service.constants["NUMBER_ZERO_BITS_CHALLENGE_SIG"],
        )
        # We do not count the min iters in the old block, since it's not included in the range
        total_mi: uint64 = uint64(0)
        for curr_h in range(older_block.height + 1, newer_block.height + 1):
            if (
                curr_h % self.service.constants["DIFFICULTY_EPOCH"]
            ) == self.service.constants["DIFFICULTY_DELAY"]:
                curr_b_header_hash = self.service.blockchain.height_to_hash.get(
                    uint32(int(curr_h))
                )
                if curr_b_header_hash is None:
                    return None
                curr_b_block = await self.service.block_store.get_block(
                    curr_b_header_hash
                )
                if curr_b_block is None or curr_b_block.proof_of_time is None:
                    return None
                curr_parent = await self.service.block_store.get_block(
                    curr_b_block.prev_header_hash
                )
                if curr_parent is None:
                    return None
                curr_diff = curr_b_block.weight - curr_parent.weight
                curr_mi = calculate_min_iters_from_iterations(
                    curr_b_block.proof_of_space,
                    uint64(curr_diff),
                    curr_b_block.proof_of_time.number_of_iterations,
                    self.service.constants["NUMBER_ZERO_BITS_CHALLENGE_SIG"],
                )
                if curr_mi is None:
                    raise web.HTTPBadRequest()
            total_mi = uint64(total_mi + curr_mi)

        return total_mi
Exemplo n.º 3
0
    def get_consecutive_blocks(
            self,
            test_constants: ConsensusConstants,
            num_blocks: int,
            block_list: List[FullBlock] = [],
            seconds_per_block=None,
            seed: bytes = b"",
            reward_puzzlehash: bytes32 = None,
            transaction_data_at_height: Dict[int, Tuple[Program,
                                                        G2Element]] = None,
            fees: uint64 = uint64(0),
    ) -> List[FullBlock]:
        if transaction_data_at_height is None:
            transaction_data_at_height = {}
        if seconds_per_block is None:
            seconds_per_block = test_constants.BLOCK_TIME_TARGET

        if len(block_list) == 0:
            block_list.append(
                FullBlock.from_bytes(test_constants.GENESIS_BLOCK))
            prev_difficulty = test_constants.DIFFICULTY_STARTING
            curr_difficulty = prev_difficulty
            curr_min_iters = test_constants.MIN_ITERS_STARTING
        elif len(block_list) < (test_constants.DIFFICULTY_EPOCH +
                                test_constants.DIFFICULTY_DELAY):
            # First epoch (+delay), so just get first difficulty
            prev_difficulty = block_list[0].weight
            curr_difficulty = block_list[0].weight
            assert test_constants.DIFFICULTY_STARTING == prev_difficulty
            curr_min_iters = test_constants.MIN_ITERS_STARTING
        else:
            curr_difficulty = block_list[-1].weight - block_list[-2].weight
            prev_difficulty = (
                block_list[-1 - test_constants.DIFFICULTY_EPOCH].weight -
                block_list[-2 - test_constants.DIFFICULTY_EPOCH].weight)
            assert block_list[-1].proof_of_time is not None
            curr_min_iters = calculate_min_iters_from_iterations(
                block_list[-1].proof_of_space,
                curr_difficulty,
                block_list[-1].proof_of_time.number_of_iterations,
                test_constants.NUMBER_ZERO_BITS_CHALLENGE_SIG,
            )

        starting_height = block_list[-1].height + 1
        timestamp = block_list[-1].header.data.timestamp
        for next_height in range(starting_height,
                                 starting_height + num_blocks):
            if (next_height > test_constants.DIFFICULTY_EPOCH
                    and next_height % test_constants.DIFFICULTY_EPOCH
                    == test_constants.DIFFICULTY_DELAY):
                # Calculates new difficulty
                height1 = uint64(next_height -
                                 (test_constants.DIFFICULTY_EPOCH +
                                  test_constants.DIFFICULTY_DELAY) - 1)
                height2 = uint64(next_height -
                                 (test_constants.DIFFICULTY_EPOCH) - 1)
                height3 = uint64(next_height -
                                 (test_constants.DIFFICULTY_DELAY) - 1)
                if height1 >= 0:
                    block1 = block_list[height1]
                    iters1 = block1.header.data.total_iters
                    timestamp1 = block1.header.data.timestamp
                else:
                    block1 = block_list[0]
                    timestamp1 = uint64(block1.header.data.timestamp -
                                        test_constants.BLOCK_TIME_TARGET)
                    iters1 = uint64(0)
                timestamp2 = block_list[height2].header.data.timestamp
                timestamp3 = block_list[height3].header.data.timestamp

                block3 = block_list[height3]
                iters3 = block3.header.data.total_iters
                term1 = (test_constants.DIFFICULTY_DELAY * prev_difficulty *
                         (timestamp3 - timestamp2) *
                         test_constants.BLOCK_TIME_TARGET)

                term2 = ((test_constants.DIFFICULTY_WARP_FACTOR - 1) *
                         (test_constants.DIFFICULTY_EPOCH -
                          test_constants.DIFFICULTY_DELAY) * curr_difficulty *
                         (timestamp2 - timestamp1) *
                         test_constants.BLOCK_TIME_TARGET)

                # Round down after the division
                new_difficulty_precise: uint64 = uint64(
                    (term1 + term2) // (test_constants.DIFFICULTY_WARP_FACTOR *
                                        (timestamp3 - timestamp2) *
                                        (timestamp2 - timestamp1)))
                new_difficulty = uint64(
                    truncate_to_significant_bits(
                        new_difficulty_precise,
                        test_constants.SIGNIFICANT_BITS))
                max_diff = uint64(
                    truncate_to_significant_bits(
                        test_constants.DIFFICULTY_FACTOR * curr_difficulty,
                        test_constants.SIGNIFICANT_BITS,
                    ))
                min_diff = uint64(
                    truncate_to_significant_bits(
                        curr_difficulty // test_constants.DIFFICULTY_FACTOR,
                        test_constants.SIGNIFICANT_BITS,
                    ))
                if new_difficulty >= curr_difficulty:
                    new_difficulty = min(
                        new_difficulty,
                        max_diff,
                    )
                else:
                    new_difficulty = max([uint64(1), new_difficulty, min_diff])

                min_iters_precise = uint64(
                    (iters3 - iters1) // (test_constants.DIFFICULTY_EPOCH *
                                          test_constants.MIN_ITERS_PROPORTION))
                curr_min_iters = uint64(
                    truncate_to_significant_bits(
                        min_iters_precise, test_constants.SIGNIFICANT_BITS))
                prev_difficulty = curr_difficulty
                curr_difficulty = new_difficulty
            time_taken = seconds_per_block
            timestamp += time_taken

            transactions: Optional[Program] = None
            aggsig: Optional[G2Element] = None
            if next_height in transaction_data_at_height:
                transactions, aggsig = transaction_data_at_height[next_height]

            update_difficulty = (next_height % test_constants.DIFFICULTY_EPOCH
                                 == test_constants.DIFFICULTY_DELAY)
            block_list.append(
                self.create_next_block(
                    test_constants,
                    block_list[-1],
                    timestamp,
                    update_difficulty,
                    curr_difficulty,
                    curr_min_iters,
                    seed,
                    reward_puzzlehash,
                    transactions,
                    aggsig,
                    fees,
                ))
        return block_list
Exemplo n.º 4
0
def get_next_min_iters(
    constants: Dict,
    headers: Dict[bytes32, Header],
    height_to_hash: Dict[uint32, bytes32],
    block: Union[FullBlock, HeaderBlock],
) -> uint64:
    """
    Returns the VDF speed in iterations per seconds, to be used for the next block. This depends on
    the number of iterations of the last epoch, and changes at the same block as the difficulty.
    """
    next_height: uint32 = uint32(block.height + 1)
    if next_height < constants["DIFFICULTY_EPOCH"]:
        # First epoch has a hardcoded vdf speed
        return constants["MIN_ITERS_STARTING"]

    prev_block_header: Header = headers[block.prev_header_hash]

    proof_of_space = block.proof_of_space
    difficulty = get_next_difficulty(
        constants, headers, height_to_hash, prev_block_header
    )
    iterations = uint64(
        block.header.data.total_iters - prev_block_header.data.total_iters
    )
    prev_min_iters = calculate_min_iters_from_iterations(
        proof_of_space, difficulty, iterations
    )

    if next_height % constants["DIFFICULTY_EPOCH"] != constants["DIFFICULTY_DELAY"]:
        # Not at a point where ips would change, so return the previous ips
        # TODO: cache this for efficiency
        return prev_min_iters

    # min iters (along with difficulty) will change in this block, so we need to calculate the new one.
    # The calculation is (iters_2 - iters_1) // epoch size
    # 1 and 2 correspond to height_1 and height_2, being the last block of the second to last, and last
    # block of the last epochs. Basically, it's total iterations per block on average.

    # Height1 is the last block 2 epochs ago, so we can include the iterations taken for mining first block in epoch
    height1 = uint32(
        next_height - constants["DIFFICULTY_EPOCH"] - constants["DIFFICULTY_DELAY"] - 1
    )
    # Height2 is the last block in the previous epoch
    height2 = uint32(next_height - constants["DIFFICULTY_DELAY"] - 1)

    block1: Optional[Header] = None
    block2: Optional[Header] = None

    # We need to backtrack until we merge with the LCA chain, so we can use the height_to_hash dict.
    # This is important if we are on a fork, or beyond the LCA.
    curr: Optional[Header] = block.header
    assert curr is not None
    while (
        curr.height not in height_to_hash
        or height_to_hash[curr.height] != curr.header_hash
    ):
        if curr.height == height1:
            block1 = curr
        elif curr.height == height2:
            block2 = curr
        curr = headers.get(curr.prev_header_hash, None)
        assert curr is not None

    # Once we are before the fork point (and before the LCA), we can use the height_to_hash map
    if block1 is None and height1 >= 0:
        # height1 could be -1, for the first difficulty calculation
        block1 = headers.get(height_to_hash[height1], None)
    if block2 is None:
        block2 = headers.get(height_to_hash[height2], None)
    assert block2 is not None

    if block1 is not None:
        iters1 = block1.data.total_iters
    else:
        # In the case of height == -1, iters = 0
        iters1 = uint64(0)

    iters2 = block2.data.total_iters

    min_iters_precise = uint64(
        (iters2 - iters1)
        // (constants["DIFFICULTY_EPOCH"] * constants["MIN_ITERS_PROPORTION"])
    )
    min_iters = uint64(
        truncate_to_significant_bits(min_iters_precise, constants["SIGNIFICANT_BITS"])
    )
    assert count_significant_bits(min_iters) <= constants["SIGNIFICANT_BITS"]
    return min_iters
Exemplo n.º 5
0
    def get_consecutive_blocks(
        self,
        input_constants: Dict,
        num_blocks: int,
        block_list: List[FullBlock] = [],
        seconds_per_block=None,
        seed: bytes = b"",
        reward_puzzlehash: bytes32 = None,
        transaction_data_at_height: Dict[int, Tuple[Program, BLSSignature]] = None,
        fees: uint64 = uint64(0),
    ) -> List[FullBlock]:
        if transaction_data_at_height is None:
            transaction_data_at_height = {}
        test_constants: Dict[str, Any] = constants.copy()
        for key, value in input_constants.items():
            test_constants[key] = value
        if seconds_per_block is None:
            seconds_per_block = test_constants["BLOCK_TIME_TARGET"]

        if len(block_list) == 0:
            if "GENESIS_BLOCK" in test_constants:
                block_list.append(FullBlock.from_bytes(test_constants["GENESIS_BLOCK"]))
            else:
                block_list.append(
                    self.create_genesis_block(test_constants, std_hash(seed), seed)
                )
            prev_difficulty = test_constants["DIFFICULTY_STARTING"]
            curr_difficulty = prev_difficulty
            curr_min_iters = test_constants["MIN_ITERS_STARTING"]
        elif len(block_list) < (
            test_constants["DIFFICULTY_EPOCH"] + test_constants["DIFFICULTY_DELAY"]
        ):
            # First epoch (+delay), so just get first difficulty
            prev_difficulty = block_list[0].weight
            curr_difficulty = block_list[0].weight
            assert test_constants["DIFFICULTY_STARTING"] == prev_difficulty
            curr_min_iters = test_constants["MIN_ITERS_STARTING"]
        else:
            curr_difficulty = block_list[-1].weight - block_list[-2].weight
            prev_difficulty = (
                block_list[-1 - test_constants["DIFFICULTY_EPOCH"]].weight
                - block_list[-2 - test_constants["DIFFICULTY_EPOCH"]].weight
            )
            assert block_list[-1].proof_of_time is not None
            curr_min_iters = calculate_min_iters_from_iterations(
                block_list[-1].proof_of_space,
                curr_difficulty,
                block_list[-1].proof_of_time.number_of_iterations,
            )

        starting_height = block_list[-1].height + 1
        timestamp = block_list[-1].header.data.timestamp
        for next_height in range(starting_height, starting_height + num_blocks):
            if (
                next_height > test_constants["DIFFICULTY_EPOCH"]
                and next_height % test_constants["DIFFICULTY_EPOCH"]
                == test_constants["DIFFICULTY_DELAY"]
            ):
                # Calculates new difficulty
                height1 = uint64(
                    next_height
                    - (
                        test_constants["DIFFICULTY_EPOCH"]
                        + test_constants["DIFFICULTY_DELAY"]
                    )
                    - 1
                )
                height2 = uint64(next_height - (test_constants["DIFFICULTY_EPOCH"]) - 1)
                height3 = uint64(next_height - (test_constants["DIFFICULTY_DELAY"]) - 1)
                if height1 >= 0:
                    block1 = block_list[height1]
                    iters1 = block1.header.data.total_iters
                    timestamp1 = block1.header.data.timestamp
                else:
                    block1 = block_list[0]
                    timestamp1 = (
                        block1.header.data.timestamp
                        - test_constants["BLOCK_TIME_TARGET"]
                    )
                    iters1 = uint64(0)
                timestamp2 = block_list[height2].header.data.timestamp
                timestamp3 = block_list[height3].header.data.timestamp

                block3 = block_list[height3]
                iters3 = block3.header.data.total_iters
                term1 = (
                    test_constants["DIFFICULTY_DELAY"]
                    * prev_difficulty
                    * (timestamp3 - timestamp2)
                    * test_constants["BLOCK_TIME_TARGET"]
                )

                term2 = (
                    (test_constants["DIFFICULTY_WARP_FACTOR"] - 1)
                    * (
                        test_constants["DIFFICULTY_EPOCH"]
                        - test_constants["DIFFICULTY_DELAY"]
                    )
                    * curr_difficulty
                    * (timestamp2 - timestamp1)
                    * test_constants["BLOCK_TIME_TARGET"]
                )

                # Round down after the division
                new_difficulty_precise: uint64 = uint64(
                    (term1 + term2)
                    // (
                        test_constants["DIFFICULTY_WARP_FACTOR"]
                        * (timestamp3 - timestamp2)
                        * (timestamp2 - timestamp1)
                    )
                )
                new_difficulty = uint64(
                    truncate_to_significant_bits(
                        new_difficulty_precise, test_constants["SIGNIFICANT_BITS"]
                    )
                )
                max_diff = uint64(
                    truncate_to_significant_bits(
                        test_constants["DIFFICULTY_FACTOR"] * curr_difficulty,
                        test_constants["SIGNIFICANT_BITS"],
                    )
                )
                min_diff = uint64(
                    truncate_to_significant_bits(
                        curr_difficulty // test_constants["DIFFICULTY_FACTOR"],
                        test_constants["SIGNIFICANT_BITS"],
                    )
                )
                if new_difficulty >= curr_difficulty:
                    new_difficulty = min(new_difficulty, max_diff,)
                else:
                    new_difficulty = max([uint64(1), new_difficulty, min_diff])

                min_iters_precise = uint64(
                    (iters3 - iters1)
                    // (
                        test_constants["DIFFICULTY_EPOCH"]
                        * test_constants["MIN_ITERS_PROPORTION"]
                    )
                )
                curr_min_iters = uint64(
                    truncate_to_significant_bits(
                        min_iters_precise, test_constants["SIGNIFICANT_BITS"]
                    )
                )
                prev_difficulty = curr_difficulty
                curr_difficulty = new_difficulty
            time_taken = seconds_per_block
            timestamp += time_taken

            transactions: Optional[Program] = None
            aggsig: Optional[BLSSignature] = None
            if next_height in transaction_data_at_height:
                transactions, aggsig = transaction_data_at_height[next_height]

            update_difficulty = (
                next_height % test_constants["DIFFICULTY_EPOCH"]
                == test_constants["DIFFICULTY_DELAY"]
            )
            block_list.append(
                self.create_next_block(
                    test_constants,
                    block_list[-1],
                    timestamp,
                    update_difficulty,
                    curr_difficulty,
                    curr_min_iters,
                    seed,
                    reward_puzzlehash,
                    transactions,
                    aggsig,
                    fees,
                )
            )
        return block_list