Skip to content

Commit 75f8aa6

Browse files
committed
change v1 plot phase-out to not affect required iters, and to be quantized to epoch blocks
1 parent 6964661 commit 75f8aa6

File tree

16 files changed

+148
-103
lines changed

16 files changed

+148
-103
lines changed

chia/_tests/core/consensus/test_pot_iterations.py

Lines changed: 1 addition & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
from chia.consensus.pot_iterations import (
1111
calculate_ip_iters,
1212
calculate_iterations_quality,
13-
calculate_phase_out,
1413
calculate_sp_interval_iters,
1514
calculate_sp_iters,
1615
is_overflow_block,
@@ -129,9 +128,7 @@ def test_win_percentage(self, height: uint32):
129128
quality = std_hash(
130129
slot_index.to_bytes(4, "big") + plot_k_val.to_bytes(1, "big") + bytes(farmer_index)
131130
)
132-
required_iters = calculate_iterations_quality(
133-
constants, quality, k, difficulty, sp_hash, sub_slot_iters, height
134-
)
131+
required_iters = calculate_iterations_quality(constants, quality, k, difficulty, sp_hash)
135132
if required_iters < sp_interval_iters:
136133
wins[k] += 1
137134
total_wins_in_slot += 1
@@ -152,36 +149,6 @@ def test_win_percentage(self, height: uint32):
152149
# Win rate is proportional to percentage of space
153150
assert abs(win_percentage[k] - percentage_space[k]) < 0.01
154151

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-
185152

186153
def test_expected_plot_size_v1() -> None:
187154
last_size = 2_400_000

chia/_tests/core/custom_types/test_proof_of_space.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@
1111

1212
from chia._tests.util.misc import Marks, datacases
1313
from chia.consensus.default_constants import DEFAULT_CONSTANTS
14+
from chia.simulator.block_tools import test_constants
1415
from chia.types.blockchain_format.proof_of_space import (
1516
calculate_prefix_bits,
1617
check_plot_size,
18+
is_v1_phased_out,
1719
make_pos,
1820
passes_plot_filter,
1921
verify_and_get_quality_string,
@@ -150,6 +152,7 @@ def test_verify_and_get_quality_string(caplog: pytest.LogCaptureFixture, case: P
150152
original_challenge_hash=b32("0x73490e166d0b88347c37d921660b216c27316aae9a3450933d3ff3b854e5831a"),
151153
signage_point=b32("0x7b3e23dbd438f9aceefa9827e2c5538898189987f49b06eceb7a43067e77b531"),
152154
height=case.height,
155+
prev_transaction_block_height=case.height,
153156
)
154157
assert quality_string is None
155158
assert len(caplog.text) == 0 if case.expected_error is None else case.expected_error in caplog.text
@@ -187,6 +190,7 @@ def test_verify_and_get_quality_string_v2(caplog: pytest.LogCaptureFixture, case
187190
original_challenge_hash=b32("0x73490e166d0b88347c37d921660b216c27316aae9a3450933d3ff3b854e5831a"),
188191
signage_point=b32("0x7b3e23dbd438f9aceefa9827e2c5538898189987f49b06eceb7a43067e77b531"),
189192
height=case.height,
193+
prev_transaction_block_height=case.height,
190194
)
191195
except NotImplementedError as e:
192196
assert case.expected_error is not None
@@ -281,3 +285,30 @@ def test_calculate_prefix_bits_v1(height: uint32, expected: int) -> None:
281285
)
282286
def test_calculate_prefix_bits_v2(height: uint32, expected: int) -> None:
283287
assert calculate_prefix_bits(DEFAULT_CONSTANTS, height, PlotSize.make_v2(28)) == expected
288+
289+
290+
def test_v1_phase_out() -> None:
291+
constants = test_constants
292+
rng = random.Random()
293+
294+
phase_out_epochs = 1 << (constants.PLOT_V1_PHASE_OUT // constants.EPOCH_BLOCKS).bit_length()
295+
print(f"phase-out epochs: {phase_out_epochs}")
296+
297+
for epoch in range(-5, phase_out_epochs + 5):
298+
prev_tx_height = uint32(constants.HARD_FORK2_HEIGHT + epoch * constants.EPOCH_BLOCKS)
299+
num_phased_out = 0
300+
rng.seed(1337)
301+
for i in range(1000):
302+
proof = rng.randbytes(32)
303+
if is_v1_phased_out(proof, prev_tx_height, constants):
304+
num_phased_out += 1
305+
306+
expect = min(1.0, max(0.0, epoch / phase_out_epochs))
307+
308+
print(
309+
f"height: {prev_tx_height} "
310+
f"epoch: {epoch} "
311+
f"phased-out: {num_phased_out / 10:0.2f}% "
312+
f"expect: {expect * 100.0:0.2f}%"
313+
)
314+
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/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:

chia/consensus/pot_iterations.py

Lines changed: 10 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -28,25 +28,6 @@ def calculate_sp_iters(constants: ConsensusConstants, sub_slot_iters: uint64, si
2828
return uint64(calculate_sp_interval_iters(constants, sub_slot_iters) * signage_point_index)
2929

3030

31-
def calculate_phase_out(
32-
constants: ConsensusConstants,
33-
sub_slot_iters: uint64,
34-
prev_transaction_block_height: uint32,
35-
) -> uint64:
36-
if prev_transaction_block_height <= constants.HARD_FORK2_HEIGHT:
37-
return uint64(0)
38-
elif uint32(prev_transaction_block_height - constants.HARD_FORK2_HEIGHT) >= constants.PLOT_V1_PHASE_OUT:
39-
return uint64(calculate_sp_interval_iters(constants, sub_slot_iters))
40-
41-
return uint64(
42-
(
43-
uint32(prev_transaction_block_height - constants.HARD_FORK2_HEIGHT)
44-
* calculate_sp_interval_iters(constants, sub_slot_iters)
45-
)
46-
// constants.PLOT_V1_PHASE_OUT
47-
)
48-
49-
5031
def calculate_ip_iters(
5132
constants: ConsensusConstants,
5233
sub_slot_iters: uint64,
@@ -75,11 +56,15 @@ def validate_pospace_and_get_required_iters(
7556
cc_sp_hash: bytes32,
7657
height: uint32,
7758
difficulty: uint64,
78-
sub_slot_iters: uint64,
7959
prev_transaction_block_height: uint32, # this is the height of the last tx block before the current block SP
8060
) -> Optional[uint64]:
8161
q_str: Optional[bytes32] = verify_and_get_quality_string(
82-
proof_of_space, constants, challenge, cc_sp_hash, height=height
62+
proof_of_space,
63+
constants,
64+
challenge,
65+
cc_sp_hash,
66+
height=height,
67+
prev_transaction_block_height=prev_transaction_block_height,
8368
)
8469
if q_str is None:
8570
return None
@@ -90,8 +75,6 @@ def validate_pospace_and_get_required_iters(
9075
proof_of_space.size(),
9176
difficulty,
9277
cc_sp_hash,
93-
sub_slot_iters,
94-
prev_transaction_block_height,
9578
)
9679

9780

@@ -101,27 +84,17 @@ def calculate_iterations_quality(
10184
size: PlotSize,
10285
difficulty: uint64,
10386
cc_sp_output_hash: bytes32,
104-
ssi: uint64,
105-
prev_transaction_block_height: uint32, # this is the height of the last tx block before the current block SP
10687
) -> uint64:
10788
"""
10889
Calculates the number of iterations from the quality. This is derives as the difficulty times the constant factor
10990
times a random number between 0 and 1 (based on quality string), divided by plot size.
11091
"""
111-
if size.size_v1 is not None:
112-
assert size.size_v2 is None
113-
phase_out = calculate_phase_out(constants, ssi, prev_transaction_block_height)
114-
else:
115-
phase_out = uint64(0)
11692

11793
sp_quality_string: bytes32 = std_hash(quality_string + cc_sp_output_hash)
11894
iters = uint64(
119-
(
120-
int(difficulty)
121-
* int(constants.DIFFICULTY_CONSTANT_FACTOR)
122-
* int.from_bytes(sp_quality_string, "big", signed=False)
123-
// (int(pow(2, 256)) * int(_expected_plot_size(size)))
124-
)
125-
+ phase_out
95+
int(difficulty)
96+
* int(constants.DIFFICULTY_CONSTANT_FACTOR)
97+
* int.from_bytes(sp_quality_string, "big", signed=False)
98+
// (int(pow(2, 256)) * int(_expected_plot_size(size)))
12699
)
127100
return max(iters, uint64(1))

chia/farmer/farmer_api.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ async def new_proof_of_space(
111111
new_proof_of_space.challenge_hash,
112112
new_proof_of_space.sp_hash,
113113
height=sp.peak_height,
114+
prev_transaction_block_height=sp.last_tx_height,
114115
)
115116
if computed_quality_string is None:
116117
plotid: bytes32 = get_plot_id(new_proof_of_space.proof)
@@ -125,8 +126,6 @@ async def new_proof_of_space(
125126
new_proof_of_space.proof.size(),
126127
sp.difficulty,
127128
new_proof_of_space.sp_hash,
128-
sp.sub_slot_iters,
129-
sp.last_tx_height,
130129
)
131130

132131
# If the iters are good enough to make a block, proceed with the block making flow
@@ -234,8 +233,6 @@ async def new_proof_of_space(
234233
new_proof_of_space.proof.size(),
235234
pool_state_dict["current_difficulty"],
236235
new_proof_of_space.sp_hash,
237-
sp.sub_slot_iters,
238-
sp.last_tx_height,
239236
)
240237
if required_iters >= calculate_sp_interval_iters(
241238
self.farmer.constants, self.farmer.constants.POOL_SUB_SLOT_ITERS
@@ -813,6 +810,7 @@ def _process_respond_signatures(
813810
is_sp_signatures: bool = False
814811
sps = self.farmer.sps[response.sp_hash]
815812
peak_height = sps[0].peak_height
813+
last_tx_height = sps[0].last_tx_height
816814
signage_point_index = sps[0].signage_point_index
817815
found_sp_hash_debug = False
818816
for sp_candidate in sps:
@@ -831,7 +829,12 @@ def _process_respond_signatures(
831829
include_taproot: bool = pospace.pool_contract_puzzle_hash is not None
832830

833831
computed_quality_string = verify_and_get_quality_string(
834-
pospace, self.farmer.constants, response.challenge_hash, response.sp_hash, height=peak_height
832+
pospace,
833+
self.farmer.constants,
834+
response.challenge_hash,
835+
response.sp_hash,
836+
height=peak_height,
837+
prev_transaction_block_height=last_tx_height,
835838
)
836839
if computed_quality_string is None:
837840
self.farmer.log.warning(f"Have invalid PoSpace {pospace}")

0 commit comments

Comments
 (0)