11from __future__ import annotations
22
3+ import pytest
34from chia_rs import PlotSize
45from chia_rs .sized_ints import uint8 , uint16 , uint32 , uint64 , uint128
56from pytest import raises
@@ -83,67 +84,96 @@ def test_calculate_ip_iters(self):
8384 assert ip_iters == (sp_iters + test_constants .NUM_SP_INTERVALS_EXTRA * sp_interval_iters + required_iters ) % ssi
8485 assert sp_iters > ip_iters
8586
86- # TODO: todo_v2_plots test this for v2 plots as well
87- def test_win_percentage (self ):
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 ):
8898 """
8999 Tests that the percentage of blocks won is proportional to the space of each farmer,
90100 with the assumption that all farmers have access to the same VDF speed.
91101 """
92102 farmer_ks = {
93- uint8 (32 ): 100 ,
94- uint8 (33 ): 100 ,
95- uint8 (34 ): 100 ,
96- uint8 (35 ): 100 ,
97- uint8 (36 ): 100 ,
103+ PlotSize .make_v1 (32 ): 100 ,
104+ PlotSize .make_v1 (33 ): 100 ,
105+ PlotSize .make_v1 (34 ): 100 ,
106+ PlotSize .make_v1 (35 ): 100 ,
107+ PlotSize .make_v1 (36 ): 100 ,
108+ PlotSize .make_v2 (28 ): 200 ,
109+ PlotSize .make_v2 (30 ): 200 ,
110+ PlotSize .make_v2 (32 ): 200 ,
98111 }
99- farmer_space = {k : _expected_plot_size (PlotSize .make_v1 (k )) * count for k , count in farmer_ks .items ()}
100- total_space = sum (farmer_space .values ())
101- percentage_space = {k : float (sp / total_space ) for k , sp in farmer_space .items ()}
112+ farmer_space = {k : _expected_plot_size (k ) * count for k , count in farmer_ks .items ()}
102113 wins = {k : 0 for k in farmer_ks .keys ()}
114+
115+ constants = test_constants .replace (DIFFICULTY_CONSTANT_FACTOR = uint128 (2 ** 25 ))
103116 total_slots = 50
104117 num_sps = 16
105- sp_interval_iters = uint64 (100000000 // 32 )
118+ sub_slot_iters = uint64 (100000000 )
119+ sp_interval_iters = calculate_sp_interval_iters (constants , sub_slot_iters )
106120 difficulty = uint64 (500000000000 )
107- constants = test_constants .replace (DIFFICULTY_CONSTANT_FACTOR = uint128 (2 ** 25 ))
108121 for slot_index in range (total_slots ):
109122 total_wins_in_slot = 0
110123 for sp_index in range (num_sps ):
111124 sp_hash = std_hash (slot_index .to_bytes (4 , "big" ) + sp_index .to_bytes (4 , "big" ))
112125 for k , count in farmer_ks .items ():
113126 for farmer_index in range (count ):
114- quality = std_hash (slot_index .to_bytes (4 , "big" ) + k .to_bytes (1 , "big" ) + bytes (farmer_index ))
127+ plot_k_val = k .size_v1 if k .size_v2 is None else k .size_v2
128+ assert plot_k_val is not None
129+ quality = std_hash (
130+ slot_index .to_bytes (4 , "big" ) + plot_k_val .to_bytes (1 , "big" ) + bytes (farmer_index )
131+ )
115132 required_iters = calculate_iterations_quality (
116- constants , quality , PlotSize . make_v1 ( k ) , difficulty , sp_hash , uint64 ( 100000000 ), uint32 ( 0 )
133+ constants , quality , k , difficulty , sp_hash , sub_slot_iters , height
117134 )
118135 if required_iters < sp_interval_iters :
119136 wins [k ] += 1
120137 total_wins_in_slot += 1
121138
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+ }
149+
122150 win_percentage = {k : wins [k ] / sum (wins .values ()) for k in farmer_ks .keys ()}
123151 for k in farmer_ks .keys ():
124152 # Win rate is proportional to percentage of space
125153 assert abs (win_percentage [k ] - percentage_space [k ]) < 0.01
126154
127- def test_calculate_phase_out (self ):
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 ):
128157 constants = test_constants
129- sub_slot_iters = uint64 (100000000000 )
130- sp_interval = calculate_sp_interval_iters (constants , sub_slot_iters )
158+ sub_slot_iters = uint64 (sp_interval * constants .NUM_SPS_SUB_SLOT )
131159 # Before or at HARD_FORK2_HEIGHT, should return 0
132- assert calculate_phase_out (constants , sub_slot_iters , constants .HARD_FORK2_HEIGHT - 1 ) == 0
160+ assert calculate_phase_out (constants , sub_slot_iters , uint32 ( constants .HARD_FORK2_HEIGHT - 1 ) ) == 0
133161 assert calculate_phase_out (constants , sub_slot_iters , constants .HARD_FORK2_HEIGHT ) == 0
134162 # after HARD_FORK2_HEIGHT, should return value = delta/phase_out_period * sp_interval
135163 assert (
136- calculate_phase_out (constants , sub_slot_iters , constants .HARD_FORK2_HEIGHT + 1 )
164+ calculate_phase_out (constants , sub_slot_iters , uint32 ( constants .HARD_FORK2_HEIGHT + 1 ) )
137165 == sp_interval // constants .PLOT_V1_PHASE_OUT
138166 )
139167 assert (
140168 calculate_phase_out (
141- constants , sub_slot_iters , constants .HARD_FORK2_HEIGHT + constants .PLOT_V1_PHASE_OUT // 2
169+ constants , sub_slot_iters , uint32 ( constants .HARD_FORK2_HEIGHT + constants .PLOT_V1_PHASE_OUT // 2 )
142170 )
143171 == sp_interval // 2
144172 )
145173 assert (
146- calculate_phase_out (constants , sub_slot_iters , constants .HARD_FORK2_HEIGHT + constants .PLOT_V1_PHASE_OUT )
174+ calculate_phase_out (
175+ constants , sub_slot_iters , uint32 (constants .HARD_FORK2_HEIGHT + constants .PLOT_V1_PHASE_OUT )
176+ )
147177 == sp_interval
148178 )
149179
@@ -154,21 +184,16 @@ def test_calculate_phase_out(self):
154184
155185
156186def test_expected_plot_size_v1 () -> None :
157- last_size = 4800000
187+ last_size = 2_400_000
158188 for k in range (18 , 50 ):
159189 plot_size = _expected_plot_size (PlotSize .make_v1 (k ))
160- assert plot_size > last_size
190+ assert plot_size > last_size * 2
161191 last_size = plot_size
162192
163193
164194def test_expected_plot_size_v2 () -> None :
165- last_size = 1700000000
166- for k in range (18 , 32 , 2 ):
195+ last_size = 100_000
196+ for k in range (16 , 32 , 2 ):
167197 plot_size = _expected_plot_size (PlotSize .make_v2 (k ))
168- # TODO: todo_v2_plots remove this special case once we support smaller k-sizes
169- if k < 28 :
170- assert plot_size == 0
171- continue
172-
173- assert plot_size > last_size
198+ assert plot_size > last_size * 2
174199 last_size = plot_size
0 commit comments