Repository: Chia-Network/chia-blockchain
File: chia/_tests/blockchain/test_blockchain.py (Python)

Code before:
    return fork_info


@pytest.mark.anyio
async def test_get_header_blocks_in_range_tx_filter_non_tx_block(empty_blockchain: Blockchain, bt: BlockTools) -> None:
    """
    Covers the case of calling `get_header_blocks_in_range`, requesting
    transactions filter, on a non transaction block.
    """
    b = empty_blockchain
    blocks = bt.get_consecutive_blocks(2)
    for block in blocks:
        await _validate_and_add_block(b, block)
    non_tx_block = next(block for block in blocks if not block.is_transaction_block())
    blocks_with_filter = await b.get_header_blocks_in_range(0, 42, tx_filter=True)
    empty_tx_filter = b"\x00"
    assert blocks_with_filter[non_tx_block.header_hash].transactions_filter == empty_tx_filter


@pytest.mark.parametrize("eligible_for_ff_flag", [True, False])
@pytest.mark.parametrize("same_ph_as_parent", [True, False])
@pytest.mark.parametrize("same_amount_as_parent", [True, False])
@pytest.mark.parametrize("rollback", [True, False])
@pytest.mark.parametrize("reset", [True, False])
@pytest.mark.anyio
async def test_fork_info_potential_ff_singletons(
    eligible_for_ff_flag: bool, same_ph_as_parent: bool, same_amount_as_parent: bool, rollback: bool, reset: bool
) -> None:
    """
    Tests that `ForkInfo` properly tracks potential fast forward singletons.
    A coin is tracked as a potential fast forward singleton when its parent is
    eligible for fast forward, the puzzle hash and amount match. We're covering
    here `include_spends`, `rollback` and `reset` in the context of potential
    fast forward singletons.
    """
    from chia._tests.util.network_protocol_data import full_block as test_block

    # Let's start with a reference base to construct the initial ForkInfo
    puzzle_hash = bytes32([0] * 32)
    amount = uint64(1337)
    init_coin_parent_id = bytes32([1] * 32)
    init_coin = Coin(init_coin_parent_id, puzzle_hash, amount)
    init_coin_id = init_coin.name()
    initial_additions_since_fork = {init_coin_id: ForkAdd(init_coin, uint32(1), uint64(0), None, False)}
    fork_info = ForkInfo(
        test_block.height - 1,
        test_block.height - 1,
        test_block.prev_header_hash,
        additions_since_fork=copy.copy(initial_additions_since_fork),
    )
    # Now let's prepare the test spend bundle conditions

Review comment (suggestion):
I think we should use a different name than "potential_ff_singleton". Partly because it's very long but also that it might be misunderstood to mean the same thing as "eligible for ff". Maybe something concise that describes more closely what it represents

Code after:
        b.clean_block_records()
    with pytest.raises(AssertionError):
        await b.lookup_block_generators(blocks_1[600].prev_header_hash, {uint32(3)})


async def get_fork_info(blockchain: Blockchain, block: FullBlock, peak: BlockRecord) -> ForkInfo:
    fork_chain, fork_hash = await lookup_fork_chain(
        blockchain,
        (peak.height, peak.header_hash),
        (block.height - 1, block.prev_header_hash),
        blockchain.constants,
    )
    # now we know how long the fork is, and can compute the fork
    # height.
    fork_height = block.height - len(fork_chain) - 1
    fork_info = ForkInfo(fork_height, fork_height, fork_hash)

    # now run all the blocks of the fork to compute the additions
    # and removals. They are recorded in the fork_info object
    counter = 0
    start = time.monotonic()
    for height in range(fork_info.fork_height + 1, block.height):
        fork_block: Optional[FullBlock] = await blockchain.block_store.get_full_block(fork_chain[uint32(height)])
        assert fork_block is not None
        assert fork_block.height - 1 == fork_info.peak_height
        assert fork_block.height == 0 or fork_block.prev_header_hash == fork_info.peak_hash
        await blockchain.run_single_block(fork_block, fork_info)
        counter += 1
    end = time.monotonic()
    log.info(
        f"executed {counter} block generators in {end - start:2f} s. "
        f"{len(fork_info.additions_since_fork)} additions, "
        f"{len(fork_info.removals_since_fork)} removals"
    )

    return fork_info


@pytest.mark.anyio
async def test_get_header_blocks_in_range_tx_filter_non_tx_block(empty_blockchain: Blockchain, bt: BlockTools) -> None:
    """
    Covers the case of calling `get_header_blocks_in_range`, requesting
    transactions filter, on a non transaction block.
    """
    b = empty_blockchain
    blocks = bt.get_consecutive_blocks(2)
    for block in blocks:
        await _validate_and_add_block(b, block)
    non_tx_block = next(block for block in blocks if not block.is_transaction_block())
    blocks_with_filter = await b.get_header_blocks_in_range(0, 42, tx_filter=True)
    empty_tx_filter = b"\x00"