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

Code before:
    test_setup.check_additions(expected_same_parent_additions)
    if rollback:
        # Now we rollback before the spend that belongs to the test conditions
        test_setup.fork_info.rollback(test_setup.test_block.prev_header_hash, test_setup.test_block.height - 1)
        # That should leave only the initial additions we started with
        assert test_setup.fork_info.additions_since_fork == test_setup.initial_additions_since_fork
    if reset:
        # Now we reset to a test height and header hash
        test_setup.fork_info.reset(1, bytes32([4] * 32))
        # That should leave this empty
        assert test_setup.fork_info.additions_since_fork == {}


@pytest.mark.parametrize("odd_amount", [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_include_block_same_as_parent_coins(
    odd_amount: 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
    spent, its puzzle hash and amount match, and the amount is odd. We're
    covering here `include_block`, `rollback` and `reset` in
    the context of potential fast forward singletons.
    """
    test_setup = ForkInfoTestSetup.create(same_ph_as_parent, same_amount_as_parent, odd_amount)
    # Now let's run the test
    test_setup.fork_info.include_block(
        [(test_setup.child_coin, None)], [test_setup.coin], test_setup.test_block, test_setup.test_block.header_hash
    )
    # Let's make sure the results are as expected
    expected_same_as_parent_additions = (
        {test_setup.child_coin.name()} if odd_amount and same_ph_as_parent and same_amount_as_parent else set()
    )
    test_setup.check_additions(expected_same_as_parent_additions)
    if rollback:
        # Now we rollback before the spend that belongs to the test conditions
        test_setup.fork_info.rollback(test_setup.test_block.prev_header_hash, test_setup.test_block.height - 1)
        # That should leave only the initial additions we started with
        assert test_setup.fork_info.additions_since_fork == test_setup.initial_additions_since_fork
    if reset:
        # Now we reset to a test height and header hash
        test_setup.fork_info.reset(1, bytes32([4] * 32))
        # That should leave this empty
        assert test_setup.fork_info.additions_since_fork == {}


Review comment (suggestion):
It sounds a bit odd to refer to a coin being created as "its parent is spent". unless I'm missing something. A coin can never have an unspent parent.
```suggestion
    A coin is tracked as a potential fast forward singleton when it's created,
    if its puzzle hash and amount match the parent, and the amount is odd. We're
```

Code after:
    test_setup.fork_info.include_spends(conds, test_setup.test_block, test_setup.test_block.header_hash)
    # Let's make sure the results are as expected
    expected_same_parent_additions = (
        {test_setup.child_coin.name()} if same_ph_as_parent and same_amount_as_parent else set()
    )
    test_setup.check_additions(expected_same_parent_additions)
    if rollback:
        # Now we rollback before the spend that belongs to the test conditions
        test_setup.fork_info.rollback(test_setup.test_block.prev_header_hash, test_setup.test_block.height - 1)
        # That should leave only the initial additions we started with, which
        # are unrelated to the test conditions. We added this initial state to
        # create a difference between `rollback` state and the completely empty
        # `reset` state.
        assert test_setup.fork_info.additions_since_fork == test_setup.initial_additions_since_fork
    if reset:
        # Now we reset to a test height and header hash
        test_setup.fork_info.reset(1, bytes32([0] * 32))
        # That should leave this empty
        assert test_setup.fork_info.additions_since_fork == {}


@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_include_block_same_as_parent_coins(
    same_ph_as_parent: bool, same_amount_as_parent: bool, rollback: bool, reset: bool
) -> None:
    """
    Tests that `ForkInfo` properly tracks same-as-parent created coins.
    A created coin is tracked as such if its puzzle hash and amount match the
    parent. We're covering here `include_block`, `rollback` and `reset` in the
    context of such coins.
    """
    test_setup = ForkInfoTestSetup.create(same_ph_as_parent, same_amount_as_parent)
    # Now let's run the test
    test_setup.fork_info.include_block(
        [(test_setup.child_coin, None)], [test_setup.coin], test_setup.test_block, test_setup.test_block.header_hash
    )
    # Let's make sure the results are as expected
    expected_same_as_parent_additions = (
        {test_setup.child_coin.name()} if same_ph_as_parent and same_amount_as_parent else set()
    )
    test_setup.check_additions(expected_same_as_parent_additions)
    if rollback:
        # Now we rollback before the spend that belongs to the test conditions
        test_setup.fork_info.rollback(test_setup.test_block.prev_header_hash, test_setup.test_block.height - 1)
        # That should leave only the initial additions we started with
        assert test_setup.fork_info.additions_since_fork == test_setup.initial_additions_since_fork
    if reset: