Skip to content

Commit ece6de2

Browse files
authored
[CHIA-3795] change v1 plot phase-out (#20216)
* change v1 plot phase-out to not affect required iters, and to be quantized to epoch blocks * disable hard-fork 2 tests until we have a new test cache * fix rate limits test * address review comments
1 parent cb7e51d commit ece6de2

File tree

18 files changed

+162
-132
lines changed

18 files changed

+162
-132
lines changed

chia/_tests/conftest.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,8 @@ class ConsensusMode(ComparableEnum):
200200

201201
@pytest.fixture(
202202
scope="session",
203-
params=[ConsensusMode.PLAIN, ConsensusMode.HARD_FORK_2_0, ConsensusMode.HARD_FORK_3_0],
203+
# TODO: todo_v2_plots add HARD_FORK_3_0 mode as well as after phase-out
204+
params=[ConsensusMode.PLAIN, ConsensusMode.HARD_FORK_2_0],
204205
)
205206
def consensus_mode(request):
206207
return request.param

chia/_tests/core/consensus/test_pot_iterations.py

Lines changed: 4 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
from __future__ import annotations
22

3-
import pytest
43
from chia_rs import PlotSize
54
from chia_rs.sized_ints import uint8, uint16, uint32, uint64, uint128
65
from pytest import raises
@@ -10,7 +9,6 @@
109
from chia.consensus.pot_iterations import (
1110
calculate_ip_iters,
1211
calculate_iterations_quality,
13-
calculate_phase_out,
1412
calculate_sp_interval_iters,
1513
calculate_sp_iters,
1614
is_overflow_block,
@@ -84,17 +82,7 @@ def test_calculate_ip_iters(self):
8482
assert ip_iters == (sp_iters + test_constants.NUM_SP_INTERVALS_EXTRA * sp_interval_iters + required_iters) % ssi
8583
assert sp_iters > ip_iters
8684

87-
@pytest.mark.parametrize(
88-
"height",
89-
[
90-
uint32(0),
91-
test_constants.HARD_FORK2_HEIGHT - 1,
92-
test_constants.HARD_FORK2_HEIGHT,
93-
test_constants.HARD_FORK2_HEIGHT + test_constants.PLOT_V1_PHASE_OUT,
94-
test_constants.HARD_FORK2_HEIGHT + test_constants.PLOT_V1_PHASE_OUT + 1,
95-
],
96-
)
97-
def test_win_percentage(self, height: uint32):
85+
def test_win_percentage(self):
9886
"""
9987
Tests that the percentage of blocks won is proportional to the space of each farmer,
10088
with the assumption that all farmers have access to the same VDF speed.
@@ -129,59 +117,19 @@ def test_win_percentage(self, height: uint32):
129117
quality = std_hash(
130118
slot_index.to_bytes(4, "big") + plot_k_val.to_bytes(1, "big") + bytes(farmer_index)
131119
)
132-
required_iters = calculate_iterations_quality(
133-
constants, quality, k, difficulty, sp_hash, sub_slot_iters, height
134-
)
120+
required_iters = calculate_iterations_quality(constants, quality, k, difficulty, sp_hash)
135121
if required_iters < sp_interval_iters:
136122
wins[k] += 1
137123
total_wins_in_slot += 1
138124

139-
if height < test_constants.HARD_FORK2_HEIGHT + test_constants.PLOT_V1_PHASE_OUT:
140-
total_space = sum(farmer_space.values())
141-
percentage_space = {k: float(sp / total_space) for k, sp in farmer_space.items()}
142-
else:
143-
# after the phase-out, v1 plots don't count
144-
# all wins are by v2 plots
145-
total_space = sum(0 if k.size_v2 is None else sp for k, sp in farmer_space.items())
146-
percentage_space = {
147-
k: 0.0 if k.size_v2 is None else float(sp / total_space) for k, sp in farmer_space.items()
148-
}
125+
total_space = sum(farmer_space.values())
126+
percentage_space = {k: float(sp / total_space) for k, sp in farmer_space.items()}
149127

150128
win_percentage = {k: wins[k] / sum(wins.values()) for k in farmer_ks.keys()}
151129
for k in farmer_ks.keys():
152130
# Win rate is proportional to percentage of space
153131
assert abs(win_percentage[k] - percentage_space[k]) < 0.01
154132

155-
@pytest.mark.parametrize("sp_interval", [uint64(6250000000), uint64(1), uint64(2), uint64(10), uint64(10000000000)])
156-
def test_calculate_phase_out(self, sp_interval: uint64):
157-
constants = test_constants
158-
sub_slot_iters = uint64(sp_interval * constants.NUM_SPS_SUB_SLOT)
159-
# Before or at HARD_FORK2_HEIGHT, should return 0
160-
assert calculate_phase_out(constants, sub_slot_iters, uint32(constants.HARD_FORK2_HEIGHT - 1)) == 0
161-
assert calculate_phase_out(constants, sub_slot_iters, constants.HARD_FORK2_HEIGHT) == 0
162-
# after HARD_FORK2_HEIGHT, should return value = delta/phase_out_period * sp_interval
163-
assert (
164-
calculate_phase_out(constants, sub_slot_iters, uint32(constants.HARD_FORK2_HEIGHT + 1))
165-
== sp_interval // constants.PLOT_V1_PHASE_OUT
166-
)
167-
assert (
168-
calculate_phase_out(
169-
constants, sub_slot_iters, uint32(constants.HARD_FORK2_HEIGHT + constants.PLOT_V1_PHASE_OUT // 2)
170-
)
171-
== sp_interval // 2
172-
)
173-
assert (
174-
calculate_phase_out(
175-
constants, sub_slot_iters, uint32(constants.HARD_FORK2_HEIGHT + constants.PLOT_V1_PHASE_OUT)
176-
)
177-
== sp_interval
178-
)
179-
180-
# Test with maximum uint32 height to ensure no overflow
181-
max_uint32_height = uint32(0xFFFFFFFF)
182-
result_max_height = calculate_phase_out(constants, sub_slot_iters, max_uint32_height)
183-
assert result_max_height == sp_interval # Should cap at sp_interval
184-
185133

186134
def test_expected_plot_size_v1() -> None:
187135
last_size = 2_400_000

chia/_tests/core/custom_types/test_proof_of_space.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from chia.types.blockchain_format.proof_of_space import (
1515
calculate_prefix_bits,
1616
check_plot_size,
17+
is_v1_phased_out,
1718
make_pos,
1819
passes_plot_filter,
1920
verify_and_get_quality_string,
@@ -150,6 +151,7 @@ def test_verify_and_get_quality_string(caplog: pytest.LogCaptureFixture, case: P
150151
original_challenge_hash=b32("0x73490e166d0b88347c37d921660b216c27316aae9a3450933d3ff3b854e5831a"),
151152
signage_point=b32("0x7b3e23dbd438f9aceefa9827e2c5538898189987f49b06eceb7a43067e77b531"),
152153
height=case.height,
154+
prev_transaction_block_height=case.height,
153155
)
154156
assert quality_string is None
155157
assert len(caplog.text) == 0 if case.expected_error is None else case.expected_error in caplog.text
@@ -187,6 +189,7 @@ def test_verify_and_get_quality_string_v2(caplog: pytest.LogCaptureFixture, case
187189
original_challenge_hash=b32("0x73490e166d0b88347c37d921660b216c27316aae9a3450933d3ff3b854e5831a"),
188190
signage_point=b32("0x7b3e23dbd438f9aceefa9827e2c5538898189987f49b06eceb7a43067e77b531"),
189191
height=case.height,
192+
prev_transaction_block_height=case.height,
190193
)
191194
except NotImplementedError as e:
192195
assert case.expected_error is not None
@@ -281,3 +284,30 @@ def test_calculate_prefix_bits_v1(height: uint32, expected: int) -> None:
281284
)
282285
def test_calculate_prefix_bits_v2(height: uint32, expected: int) -> None:
283286
assert calculate_prefix_bits(DEFAULT_CONSTANTS, height, PlotSize.make_v2(28)) == expected
287+
288+
289+
def test_v1_phase_out() -> None:
290+
constants = DEFAULT_CONSTANTS.replace(HARD_FORK2_HEIGHT=uint32(500000))
291+
rng = random.Random()
292+
293+
phase_out_epochs = 1 << (constants.PLOT_V1_PHASE_OUT // constants.EPOCH_BLOCKS).bit_length()
294+
print(f"phase-out epochs: {phase_out_epochs}")
295+
296+
for epoch in range(-5, phase_out_epochs + 5):
297+
prev_tx_height = uint32(constants.HARD_FORK2_HEIGHT + epoch * constants.EPOCH_BLOCKS)
298+
num_phased_out = 0
299+
rng.seed(1337)
300+
for i in range(1000):
301+
proof = rng.randbytes(32)
302+
if is_v1_phased_out(proof, prev_tx_height, constants):
303+
num_phased_out += 1
304+
305+
expect = min(1.0, max(0.0, epoch / phase_out_epochs))
306+
307+
print(
308+
f"height: {prev_tx_height} "
309+
f"epoch: {epoch} "
310+
f"phased-out: {num_phased_out / 10:0.2f}% "
311+
f"expect: {expect * 100.0:0.2f}%"
312+
)
313+
assert abs((num_phased_out / 1000) - expect) < 0.05

chia/_tests/core/full_node/test_full_node.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3224,12 +3224,15 @@ async def declare_pos_unfinished_block(
32243224
include_signature_source_data=True,
32253225
)
32263226
await full_node_api.declare_proof_of_space(pospace, dummy_peer)
3227+
tx_peak = blockchain.get_tx_peak()
3228+
assert tx_peak is not None
32273229
q_str: Optional[bytes32] = verify_and_get_quality_string(
32283230
block.reward_chain_block.proof_of_space,
32293231
blockchain.constants,
32303232
challenge,
32313233
challenge_chain_sp,
32323234
height=block.reward_chain_block.height,
3235+
prev_transaction_block_height=tx_peak.height,
32333236
)
32343237
assert q_str is not None
32353238
unfinised_block = None

chia/_tests/core/server/test_rate_limits.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
rl_v2 = [Capability.BASE, Capability.BLOCK_HEADERS, Capability.RATE_LIMITS_V2]
2525
rl_v1 = [Capability.BASE]
2626
node_with_params_b = node_with_params
27-
test_different_versions_results: list[int] = []
2827

2928

3029
@dataclass
@@ -418,11 +417,14 @@ async def test_different_versions(
418417
# The following code checks whether all of the runs resulted in the same number of items in "rate_limits_tx",
419418
# which would mean the same rate limits are always used. This should not happen, since two nodes with V2
420419
# will use V2.
421-
total_tx_msg_count = len(get_rate_limits_to_use(a_con.local_capabilities, a_con.peer_capabilities))
420+
rate_limits = get_rate_limits_to_use(a_con.local_capabilities, a_con.peer_capabilities)[0]
421+
limit = rate_limits[ProtocolMessageTypes.request_header_blocks]
422+
assert isinstance(limit, RLSettings)
422423

423-
test_different_versions_results.append(total_tx_msg_count)
424-
if len(test_different_versions_results) >= 4:
425-
assert len(set(test_different_versions_results)) >= 2
424+
if Capability.RATE_LIMITS_V2 in a_con.local_capabilities and Capability.RATE_LIMITS_V2 in a_con.peer_capabilities:
425+
assert limit.frequency == 5000
426+
else:
427+
assert limit.frequency == 500
426428

427429

428430
@pytest.mark.anyio

chia/_tests/farmer_harvester/test_farmer.py

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -626,7 +626,14 @@ async def test_farmer_new_proof_of_space_for_pool_stats(
626626
}
627627

628628
assert (
629-
verify_and_get_quality_string(pos, DEFAULT_CONSTANTS, case.challenge_hash, case.sp_hash, height=uint32(1))
629+
verify_and_get_quality_string(
630+
pos,
631+
DEFAULT_CONSTANTS,
632+
case.challenge_hash,
633+
case.sp_hash,
634+
height=uint32(1),
635+
prev_transaction_block_height=uint32(1),
636+
)
630637
is not None
631638
)
632639

@@ -883,7 +890,12 @@ async def test_farmer_pool_response(
883890

884891
assert (
885892
verify_and_get_quality_string(
886-
pos, DEFAULT_CONSTANTS, sp.challenge_hash, sp.challenge_chain_sp, height=uint32(1)
893+
pos,
894+
DEFAULT_CONSTANTS,
895+
sp.challenge_hash,
896+
sp.challenge_chain_sp,
897+
height=uint32(1),
898+
prev_transaction_block_height=uint32(1),
887899
)
888900
is not None
889901
)
@@ -1251,7 +1263,12 @@ async def test_farmer_additional_headers_on_partial_submit(
12511263

12521264
assert (
12531265
verify_and_get_quality_string(
1254-
pos, DEFAULT_CONSTANTS, sp.challenge_hash, sp.challenge_chain_sp, height=uint32(1)
1266+
pos,
1267+
DEFAULT_CONSTANTS,
1268+
sp.challenge_hash,
1269+
sp.challenge_chain_sp,
1270+
height=uint32(1),
1271+
prev_transaction_block_height=uint32(1),
12551272
)
12561273
is not None
12571274
)

chia/_tests/weight_proof/test_weight_proof.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ async def load_blocks_dont_validate(
4747
cc_sp,
4848
block.height,
4949
difficulty,
50-
sub_slot_iters,
5150
uint32(0), # prev_tx_block(blocks, prev_b), todo need to get height of prev tx block somehow here
5251
)
5352
assert required_iters is not None

chia/consensus/block_header_validation.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -502,7 +502,6 @@ def validate_unfinished_header_block(
502502
cc_sp_hash,
503503
height,
504504
expected_vs.difficulty,
505-
expected_vs.ssi,
506505
prev_tx_block(blocks, prev_b),
507506
)
508507
if required_iters is None:

chia/consensus/default_constants.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@
8484
HARD_FORK2_HEIGHT=uint32(0xFFFFFFFA),
8585
# starting at the hard fork 2 height, v1 plots will gradually be phased out,
8686
# and stop working entirely after this many blocks
87-
PLOT_V1_PHASE_OUT=uint32(1179648),
87+
PLOT_V1_PHASE_OUT=uint32(255 * 4608),
8888
# June 2027
8989
PLOT_FILTER_128_HEIGHT=uint32(10542000),
9090
# June 2030

chia/consensus/multiprocess_validation.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,6 @@ async def return_error(error_code: Err) -> PreValidationResult:
220220
cc_sp_hash,
221221
block.height,
222222
vs.difficulty,
223-
vs.ssi,
224223
prev_tx_block(blockchain, prev_b),
225224
)
226225
if required_iters is None:

0 commit comments

Comments
 (0)