Skip to content

Commit

Permalink
introduce SOFT_FORK4_HEIGHT and tie CHIP-13 to it (#15885)
Browse files Browse the repository at this point in the history
* introduce SOFT_FORK4_HEIGHT and tie CHIP-13 to it

* fix test_plot_refreshing
  • Loading branch information
arvidn authored Aug 4, 2023
1 parent a33f86b commit 8071dc6
Show file tree
Hide file tree
Showing 13 changed files with 61 additions and 39 deletions.
2 changes: 1 addition & 1 deletion chia/consensus/block_body_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ async def validate_block_body(
# from the database too (BlockStore). In `BlockHeaderValidation` we don't have access to the database,
# just the cache. This check makes sure we retrieve blocks from the database and perform the check with them,
# in case they were missing from the cache.
if height >= constants.SOFT_FORK3_HEIGHT:
if height >= constants.SOFT_FORK4_HEIGHT:
curr_optional_block_record: Optional[BlockRecord] = await blocks.get_block_record_from_db(
block.prev_header_hash
)
Expand Down
2 changes: 1 addition & 1 deletion chia/consensus/block_header_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -497,7 +497,7 @@ def validate_unfinished_header_block(
return None, ValidationError(Err.INVALID_POSPACE)

# 5c. Check plot id is not present within last `NUM_DISTINCT_CONSECUTIVE_PLOT_IDS` blocks.
if height >= constants.SOFT_FORK3_HEIGHT:
if height >= constants.SOFT_FORK4_HEIGHT:
curr_optional_block_record: Optional[BlockRecord] = prev_b
plot_id = get_plot_id(header_block.reward_chain_block.proof_of_space)
curr_sp = cc_sp_hash
Expand Down
3 changes: 3 additions & 0 deletions chia/consensus/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ class ConsensusConstants:
# soft fork initiated in 2.0 release
SOFT_FORK3_HEIGHT: uint32

# soft fork initiated in 2.1 release
SOFT_FORK4_HEIGHT: uint32

# the hard fork planned with the 2.0 release
# this is the block with the first plot filter adjustment
HARD_FORK_HEIGHT: uint32
Expand Down
2 changes: 2 additions & 0 deletions chia/consensus/default_constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@
"POOL_SUB_SLOT_ITERS": 37600000000, # iters limit * NUM_SPS
# October 23, 2023
"SOFT_FORK3_HEIGHT": 4410000,
# December 4, 2023
"SOFT_FORK4_HEIGHT": 4603536,
# June 2024
"HARD_FORK_HEIGHT": 5496000,
# June 2027
Expand Down
2 changes: 2 additions & 0 deletions chia/server/start_full_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ def update_testnet_overrides(network_id: str, overrides: Dict[str, Any]) -> None
# these numbers are supposed to match initial-config.yaml
if "SOFT_FORK3_HEIGHT" not in overrides:
overrides["SOFT_FORK3_HEIGHT"] = 2997292
if "SOFT_FORK4_HEIGHT" not in overrides:
overrides["SOFT_FORK4_HEIGHT"] = 2997292
if "HARD_FORK_HEIGHT" not in overrides:
overrides["HARD_FORK_HEIGHT"] = 2997292
if "PLOT_FILTER_128_HEIGHT" not in overrides:
Expand Down
4 changes: 2 additions & 2 deletions chia/simulator/block_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -729,7 +729,7 @@ def get_consecutive_blocks(
continue
assert latest_block.header_hash in blocks
plot_id = get_plot_id(proof_of_space)
if latest_block.height + 1 >= constants.SOFT_FORK3_HEIGHT:
if latest_block.height + 1 >= constants.SOFT_FORK4_HEIGHT:
if self.plot_id_passed_previous_filters(plot_id, cc_sp_output_hash, block_list):
continue
additions = None
Expand Down Expand Up @@ -1031,7 +1031,7 @@ def get_consecutive_blocks(
break
assert last_timestamp is not None
plot_id = get_plot_id(proof_of_space)
if latest_block.height + 1 >= constants.SOFT_FORK3_HEIGHT:
if latest_block.height + 1 >= constants.SOFT_FORK4_HEIGHT:
if self.plot_id_passed_previous_filters(plot_id, cc_sp_output_hash, block_list):
continue
if proof_of_space.pool_contract_puzzle_hash is not None:
Expand Down
1 change: 1 addition & 0 deletions chia/util/initial-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ network_overrides: &network_overrides
MEMPOOL_BLOCK_BUFFER: 10
MIN_PLOT_SIZE: 18
SOFT_FORK3_HEIGHT: 2997292
SOFT_FORK4_HEIGHT: 2997292
# planned 2.0 release is July 26, height 2965036 on testnet
# 1 week later
HARD_FORK_HEIGHT: 2997292
Expand Down
28 changes: 14 additions & 14 deletions tests/blockchain/test_blockchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -1369,8 +1369,8 @@ async def test_pool_target_signature(self, empty_blockchain, bt):
attempts += 1

@pytest.mark.asyncio
async def test_pool_target_contract(self, empty_blockchain, bt):
if bt.constants.SOFT_FORK3_HEIGHT == 0:
async def test_pool_target_contract(self, empty_blockchain, bt, consensus_mode: Mode):
if consensus_mode == Mode.SOFT_FORK4:
pytest.skip("Skipped temporarily until adding more pool plots.")
# 20c invalid pool target with contract
blocks_initial = bt.get_consecutive_blocks(2)
Expand Down Expand Up @@ -3612,26 +3612,26 @@ async def test_reorg_flip_flop(empty_blockchain, bt):


@pytest.mark.parametrize("unique_plots_window", [1, 2])
@pytest.mark.parametrize("bt_respects_soft_fork3", [True, False])
@pytest.mark.parametrize("soft_fork3_height", [0, 10, 10000])
@pytest.mark.parametrize("bt_respects_soft_fork4", [True, False])
@pytest.mark.parametrize("soft_fork4_height", [0, 10, 10000])
@pytest.mark.asyncio
async def test_soft_fork3_activation(
consensus_mode, blockchain_constants, bt_respects_soft_fork3, soft_fork3_height, db_version, unique_plots_window
async def test_soft_fork4_activation(
consensus_mode, blockchain_constants, bt_respects_soft_fork4, soft_fork4_height, db_version, unique_plots_window
):
# We don't run Mode.SOFT_FORK3, since this is already parametrized by this test.
# We don't run Mode.SOFT_FORK4, since this is already parametrized by this test.
# Additionally, Mode.HARD_FORK_2_0 mode is incopatible with this test, since plot filter size would be zero,
# blocks won't ever be produced (we'll pass every consecutive plot filter, hence no block would pass CHIP-13).
if consensus_mode != Mode.PLAIN:
pytest.skip("Skipped test")
with TempKeyring() as keychain:
bt = await create_block_tools_async(
constants=blockchain_constants.replace(
SOFT_FORK3_HEIGHT=(0 if bt_respects_soft_fork3 else 10000),
SOFT_FORK4_HEIGHT=(0 if bt_respects_soft_fork4 else 10000),
UNIQUE_PLOTS_WINDOW=unique_plots_window,
),
keychain=keychain,
)
blockchain_constants = bt.constants.replace(SOFT_FORK3_HEIGHT=soft_fork3_height)
blockchain_constants = bt.constants.replace(SOFT_FORK3_HEIGHT=0, SOFT_FORK4_HEIGHT=soft_fork4_height)
b, db_wrapper, db_path = await create_blockchain(blockchain_constants, db_version)
blocks = bt.get_consecutive_blocks(25)
for height, block in enumerate(blocks):
Expand All @@ -3647,17 +3647,17 @@ async def test_soft_fork3_activation(
# We expect to add all blocks here (25 blocks), either because `unique_plots_window`=1 means we're not
# checking any extra plot filter, or `unique_plots_window`=True means `BlockTools` produced blocks
# that respect CHIP-13.
if bt_respects_soft_fork3 or unique_plots_window == 1:
if bt_respects_soft_fork4 or unique_plots_window == 1:
assert peak.height == 24
else:
# Here we have `bt_respects_soft_fork3`=False, which means the produced blocks by `BlockTools` will not
# Here we have `bt_respects_soft_fork4`=False, which means the produced blocks by `BlockTools` will not
# respect the CHIP-13 condition. We expect not adding blocks at some point after the soft fork 3
# activation height (`soft_fork3_height`).
if soft_fork3_height == 0:
# activation height (`soft_fork4_height`).
if soft_fork4_height == 0:
# We're not adding all blocks, since at some point `BlockTools` will break the CHIP-13 condition with
# very high likelyhood.
assert peak.height < 24
elif soft_fork3_height == 10:
elif soft_fork4_height == 10:
# We're not adding all blocks, but we've added all of them until the soft fork 3 activated (height 10)
assert peak.height < 24 and peak.height >= 9
else:
Expand Down
35 changes: 19 additions & 16 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,10 @@ class Mode(Enum):
PLAIN = 0
HARD_FORK_2_0 = 1
SOFT_FORK3 = 2
SOFT_FORK4 = 3


@pytest.fixture(scope="session", params=[Mode.PLAIN, Mode.HARD_FORK_2_0, Mode.SOFT_FORK3])
@pytest.fixture(scope="session", params=[Mode.PLAIN, Mode.HARD_FORK_2_0, Mode.SOFT_FORK3, Mode.SOFT_FORK4])
def consensus_mode(request):
return request.param

Expand All @@ -114,6 +115,8 @@ def blockchain_constants(consensus_mode) -> ConsensusConstants:
return test_constants
if consensus_mode == Mode.SOFT_FORK3:
return test_constants.replace(SOFT_FORK3_HEIGHT=3)
if consensus_mode == Mode.SOFT_FORK4:
return test_constants.replace(SOFT_FORK3_HEIGHT=3, SOFT_FORK4_HEIGHT=3)
if consensus_mode == Mode.HARD_FORK_2_0:
return test_constants.replace(
HARD_FORK_HEIGHT=2, PLOT_FILTER_128_HEIGHT=10, PLOT_FILTER_64_HEIGHT=15, PLOT_FILTER_32_HEIGHT=20
Expand Down Expand Up @@ -183,7 +186,7 @@ def softfork_height(request) -> int:
@pytest.fixture(scope="session")
def default_400_blocks(bt, consensus_mode):
version = ""
if consensus_mode == Mode.SOFT_FORK3:
if consensus_mode == Mode.SOFT_FORK4:
version = "_softfork3"

from tests.util.blockchain import persistent_blocks
Expand All @@ -194,7 +197,7 @@ def default_400_blocks(bt, consensus_mode):
@pytest.fixture(scope="session")
def default_1000_blocks(bt, consensus_mode):
version = ""
if consensus_mode == Mode.SOFT_FORK3:
if consensus_mode == Mode.SOFT_FORK4:
version = "_softfork3"

from tests.util.blockchain import persistent_blocks
Expand All @@ -205,7 +208,7 @@ def default_1000_blocks(bt, consensus_mode):
@pytest.fixture(scope="session")
def pre_genesis_empty_slots_1000_blocks(bt, consensus_mode):
version = ""
if consensus_mode == Mode.SOFT_FORK3:
if consensus_mode == Mode.SOFT_FORK4:
version = "_softfork3"

from tests.util.blockchain import persistent_blocks
Expand All @@ -222,7 +225,7 @@ def pre_genesis_empty_slots_1000_blocks(bt, consensus_mode):
@pytest.fixture(scope="session")
def default_1500_blocks(bt, consensus_mode):
version = ""
if consensus_mode == Mode.SOFT_FORK3:
if consensus_mode == Mode.SOFT_FORK4:
version = "_softfork3"

from tests.util.blockchain import persistent_blocks
Expand All @@ -234,15 +237,15 @@ def default_1500_blocks(bt, consensus_mode):
def default_10000_blocks(bt, consensus_mode):
from tests.util.blockchain import persistent_blocks

if consensus_mode == Mode.SOFT_FORK3:
if consensus_mode == Mode.SOFT_FORK4:
pytest.skip("Test cache not available yet")

return persistent_blocks(10000, f"test_blocks_10000_{saved_blocks_version}.db", bt, seed=b"10000")


@pytest.fixture(scope="session")
def default_20000_blocks(bt, consensus_mode):
if consensus_mode == Mode.SOFT_FORK3:
if consensus_mode == Mode.SOFT_FORK4:
pytest.skip("Test cache not available")

from tests.util.blockchain import persistent_blocks
Expand All @@ -253,7 +256,7 @@ def default_20000_blocks(bt, consensus_mode):
@pytest.fixture(scope="session")
def test_long_reorg_blocks(bt, consensus_mode, default_1500_blocks):
version = ""
if consensus_mode == Mode.SOFT_FORK3:
if consensus_mode == Mode.SOFT_FORK4:
version = "_softfork3"

from tests.util.blockchain import persistent_blocks
Expand All @@ -271,7 +274,7 @@ def test_long_reorg_blocks(bt, consensus_mode, default_1500_blocks):
@pytest.fixture(scope="session")
def default_2000_blocks_compact(bt, consensus_mode):
version = ""
if consensus_mode == Mode.SOFT_FORK3:
if consensus_mode == Mode.SOFT_FORK4:
version = "_softfork3"

from tests.util.blockchain import persistent_blocks
Expand All @@ -292,7 +295,7 @@ def default_2000_blocks_compact(bt, consensus_mode):
def default_10000_blocks_compact(bt, consensus_mode):
from tests.util.blockchain import persistent_blocks

if consensus_mode == Mode.SOFT_FORK3:
if consensus_mode == Mode.SOFT_FORK4:
pytest.skip("Test cache not available yet")
return persistent_blocks(
10000,
Expand Down Expand Up @@ -366,14 +369,14 @@ async def five_nodes(db_version: int, self_hostname, blockchain_constants):
@pytest_asyncio.fixture(scope="function")
async def wallet_nodes(blockchain_constants, consensus_mode):
# Since the constants are identical for `Mode.PLAIN` and `Mode.HARD_FORK_2_0`, we will only run in
# mode `PLAIN` and `SOFT_FORK3`.
if consensus_mode not in (Mode.PLAIN, Mode.SOFT_FORK3):
# mode `PLAIN` and `SOFT_FORK4`.
if consensus_mode not in (Mode.PLAIN, Mode.SOFT_FORK4):
pytest.skip("Skipping duplicate test, the same setup is ran by Mode.PLAIN")
constants = blockchain_constants
async_gen = setup_simulators_and_wallets(
2,
1,
{"MEMPOOL_BLOCK_BUFFER": 1, "MAX_BLOCK_COST_CLVM": 400000000, "SOFT_FORK3_HEIGHT": constants.SOFT_FORK3_HEIGHT},
{"MEMPOOL_BLOCK_BUFFER": 1, "MAX_BLOCK_COST_CLVM": 400000000, "SOFT_FORK4_HEIGHT": constants.SOFT_FORK4_HEIGHT},
)
nodes, wallets, bt = await async_gen.__anext__()
full_node_1 = nodes[0]
Expand Down Expand Up @@ -403,11 +406,11 @@ async def two_nodes_sim_and_wallets():
@pytest_asyncio.fixture(scope="function")
async def two_nodes_sim_and_wallets_services(blockchain_constants, consensus_mode):
# Since the constants are identical for `Mode.PLAIN` and `Mode.HARD_FORK_2_0`, we will only run in
# mode `PLAIN` and `SOFT_FORK3`.
if consensus_mode not in (Mode.PLAIN, Mode.SOFT_FORK3):
# mode `PLAIN` and `SOFT_FORK4`.
if consensus_mode not in (Mode.PLAIN, Mode.SOFT_FORK4):
pytest.skip("Skipping duplicate test, the same setup is ran by Mode.PLAIN")
async for _ in setup_simulators_and_wallets_service(
2, 0, {"SOFT_FORK3_HEIGHT": blockchain_constants.SOFT_FORK3_HEIGHT}
2, 0, {"SOFT_FORK4_HEIGHT": blockchain_constants.SOFT_FORK4_HEIGHT}
):
yield _

Expand Down
2 changes: 1 addition & 1 deletion tests/core/full_node/test_conditions.py
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,7 @@ async def test_announce_conditions_limit(
pre-v2-softfork, and rejects more than the announcement limit afterward.
"""

if consensus_mode != Mode.SOFT_FORK3:
if consensus_mode.value < Mode.SOFT_FORK3.value:
# before softfork 3, there was no limit on the number of
# announcements
expect_err = None
Expand Down
6 changes: 5 additions & 1 deletion tests/core/test_full_node_rpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,17 @@
from chia.util.hash import std_hash
from chia.util.ints import uint8
from tests.blockchain.blockchain_test_utils import _validate_and_add_block
from tests.conftest import Mode
from tests.connection_utils import connect_and_get_peer
from tests.util.rpc import validate_get_routes


class TestRpc:
@pytest.mark.asyncio
async def test1(self, two_nodes_sim_and_wallets_services, self_hostname):
async def test1(self, two_nodes_sim_and_wallets_services, self_hostname, consensus_mode):
if consensus_mode != Mode.PLAIN:
pytest.skip("test does not depend on consesus rules")

num_blocks = 5
nodes, _, bt = two_nodes_sim_and_wallets_services
full_node_service_1, full_node_service_2 = nodes
Expand Down
10 changes: 7 additions & 3 deletions tests/plotting/test_plot_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from os import unlink
from pathlib import Path
from shutil import copy, move
from typing import Callable, Iterator, List, Optional
from typing import Callable, Iterator, List, Optional, cast

import pytest
from blspy import G1Element
Expand All @@ -28,6 +28,7 @@
from chia.util.config import create_default_chia_config, lock_and_load_config, save_config
from chia.util.ints import uint16, uint32
from chia.util.misc import VersionedBlob
from tests.conftest import Mode
from tests.plotting.util import get_test_plots

log = logging.getLogger(__name__)
Expand Down Expand Up @@ -170,7 +171,10 @@ def trigger_remove_plot(_: Path, plot_path: str):


@pytest.mark.asyncio
async def test_plot_refreshing(environment):
async def test_plot_refreshing(environment, consensus_mode: Mode):
if consensus_mode != Mode.PLAIN:
pytest.skip("plot refreshing is not dependent on consensus. This test does not support parallel execution")

env: Environment = environment
expected_result = PlotRefreshResult()
dir_duplicates: Directory = Directory(get_plot_dir().resolve() / "duplicates", env.dir_1.plots)
Expand All @@ -186,7 +190,7 @@ async def run_test_case(
expected_directories: int,
expect_total_plots: int,
):
expected_result.loaded = expect_loaded
expected_result.loaded = cast(List[PlotInfo], expect_loaded)
expected_result.removed = expect_removed
expected_result.processed = expect_processed
trigger(env.root_path, str(test_path))
Expand Down
3 changes: 3 additions & 0 deletions tests/util/test_testnet_overrides.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ def test_testnet10() -> None:
update_testnet_overrides("testnet10", overrides)
assert overrides == {
"SOFT_FORK3_HEIGHT": 2997292,
"SOFT_FORK4_HEIGHT": 2997292,
"HARD_FORK_HEIGHT": 2997292,
"PLOT_FILTER_128_HEIGHT": 3061804,
"PLOT_FILTER_64_HEIGHT": 8010796,
Expand All @@ -20,6 +21,7 @@ def test_testnet10() -> None:
def test_testnet10_existing() -> None:
overrides: Dict[str, Any] = {
"SOFT_FORK3_HEIGHT": 42,
"SOFT_FORK4_HEIGHT": 45,
"HARD_FORK_HEIGHT": 42,
"PLOT_FILTER_128_HEIGHT": 42,
"PLOT_FILTER_64_HEIGHT": 42,
Expand All @@ -28,6 +30,7 @@ def test_testnet10_existing() -> None:
update_testnet_overrides("testnet10", overrides)
assert overrides == {
"SOFT_FORK3_HEIGHT": 42,
"SOFT_FORK4_HEIGHT": 45,
"HARD_FORK_HEIGHT": 42,
"PLOT_FILTER_128_HEIGHT": 42,
"PLOT_FILTER_64_HEIGHT": 42,
Expand Down

0 comments on commit 8071dc6

Please sign in to comment.