17
17
from chia .simulator .block_tools import BlockTools
18
18
19
19
20
- def create_signage_point_harvester_from_constants (bt : BlockTools ) -> harvester_protocol .NewSignagePointHarvester :
21
- """create a NewSignagePointHarvester using real constants from block tools"""
22
- # use the pre-generated signage point data from network_protocol_data.py
23
- # but with real constants from block_tools
24
- from chia ._tests .util .network_protocol_data import new_signage_point_harvester
20
+ def signage_point_from_block (bt : BlockTools ) -> harvester_protocol .NewSignagePointHarvester :
21
+ """Create a real NewSignagePointHarvester from actual blockchain blocks."""
22
+ # generate real blocks using BlockTools
23
+ blocks = bt .get_consecutive_blocks (
24
+ num_blocks = 3 ,
25
+ guarantee_transaction_block = True ,
26
+ farmer_reward_puzzle_hash = bt .farmer_ph ,
27
+ )
28
+ block = blocks [- 1 ] # always use the last block
29
+ # extract real signage point data from the block
30
+ sp_index = block .reward_chain_block .signage_point_index
31
+ challenge_hash = block .reward_chain_block .pos_ss_cc_challenge_hash
32
+ sp_hash = (
33
+ block .reward_chain_block .reward_chain_sp_vdf .output .get_hash ()
34
+ if block .reward_chain_block .reward_chain_sp_vdf
35
+ else challenge_hash
36
+ )
25
37
26
- # create a version with real constants values
27
38
return harvester_protocol .NewSignagePointHarvester (
28
- challenge_hash = new_signage_point_harvester . challenge_hash ,
39
+ challenge_hash = challenge_hash ,
29
40
difficulty = uint64 (bt .constants .DIFFICULTY_STARTING ),
30
41
sub_slot_iters = uint64 (bt .constants .SUB_SLOT_ITERS_STARTING ),
31
- signage_point_index = new_signage_point_harvester . signage_point_index ,
32
- sp_hash = new_signage_point_harvester . sp_hash ,
33
- pool_difficulties = [], # empty for simplicity, unless testing pool functionality
34
- peak_height = new_signage_point_harvester . peak_height ,
35
- last_tx_height = new_signage_point_harvester . last_tx_height ,
42
+ signage_point_index = sp_index ,
43
+ sp_hash = sp_hash ,
44
+ pool_difficulties = [],
45
+ peak_height = block . height ,
46
+ last_tx_height = block . height ,
36
47
)
37
48
38
49
39
- @pytest .mark .anyio
40
- async def test_new_signage_point_harvester_no_keys (
41
- harvester_farmer_environment : HarvesterFarmerEnvironment ,
42
- ) -> None :
43
- """test that new_signage_point_harvester returns early when no keys available"""
44
- _farmer_service , _farmer_rpc_client , harvester_service , _harvester_rpc_client , bt = harvester_farmer_environment
45
- harvester_api = harvester_service ._server .api
46
- assert isinstance (harvester_api , HarvesterAPI )
47
-
48
- # create real signage point data from block tools
49
- new_challenge = create_signage_point_harvester_from_constants (bt )
50
-
51
- # mock plot manager to return false for public_keys_available
52
- with patch .object (harvester_api .harvester .plot_manager , "public_keys_available" , return_value = False ):
53
- mock_peer = MagicMock (spec = WSChiaConnection )
50
+ def create_plot_info () -> PlotInfo :
51
+ """Create a realistic PlotInfo mock for testing."""
52
+ mock_prover = MagicMock ()
53
+ mock_prover .get_id .return_value = bytes32 (b"plot_id_123456789012345678901234" ) # exactly 32 bytes
54
+ mock_prover .get_size .return_value = 32 # standard k32 plot
55
+ mock_prover .get_qualities_for_challenge .return_value = [
56
+ bytes32 (b"quality_123456789012345678901234" )
57
+ ] # exactly 32 bytes
58
+ mock_plot_info = MagicMock (spec = PlotInfo )
59
+ mock_plot_info .prover = mock_prover
60
+ mock_plot_info .pool_contract_puzzle_hash = None
54
61
55
- result = harvester_api .new_signage_point_harvester (new_challenge , mock_peer )
56
- assert result is None
62
+ return mock_plot_info
57
63
58
64
59
65
@pytest .mark .anyio
60
- async def test_new_signage_point_harvester_happy_path (
61
- harvester_farmer_environment : HarvesterFarmerEnvironment ,
62
- ) -> None :
63
- """test successful signage point processing with valid plots"""
64
- _farmer_service , _farmer_rpc_client , harvester_service , _harvester_rpc_client , bt = harvester_farmer_environment
66
+ async def test_new_signage_point_harvester (harvester_farmer_environment : HarvesterFarmerEnvironment ) -> None :
67
+ """Test successful signage point processing with real blockchain data."""
68
+ _ , _ , harvester_service , _ , bt = harvester_farmer_environment
65
69
harvester_api = harvester_service ._server .api
66
70
assert isinstance (harvester_api , HarvesterAPI )
67
-
68
- # create real signage point data from block tools
69
- new_challenge = create_signage_point_harvester_from_constants (bt )
70
-
71
+ # use real signage point data from actual block
72
+ new_challenge = signage_point_from_block (bt )
73
+ # harvester doesn't accept incoming connections, so use mock peer like other tests
71
74
mock_peer = MagicMock (spec = WSChiaConnection )
72
-
73
- # create mock plot info
74
- mock_prover = MagicMock ()
75
- mock_prover .get_id .return_value = bytes32 (b"2" * 32 )
76
- mock_prover .get_size .return_value = 32
77
- mock_prover .get_qualities_for_challenge .return_value = [bytes32 (b"quality" + b"0" * 25 )]
78
-
79
- mock_plot_info = MagicMock (spec = PlotInfo )
80
- mock_plot_info .prover = mock_prover
81
- mock_plot_info .pool_contract_puzzle_hash = None
82
-
75
+ # create realistic plot info for testing
76
+ mock_plot_info = create_plot_info ()
83
77
plot_path = Path ("/fake/plot.plot" )
84
78
85
79
with patch .object (harvester_api .harvester .plot_manager , "public_keys_available" , return_value = True ):
86
80
with patch .object (harvester_api .harvester .plot_manager , "plots" , {plot_path : mock_plot_info }):
87
- with patch ("chia.harvester.harvester_api.passes_plot_filter" , return_value = True ):
88
- with patch ("chia.harvester.harvester_api.calculate_pos_challenge" ) as mock_calc_pos :
89
- mock_calc_pos .return_value = bytes32 (b"sp_challenge" + b"0" * 20 )
90
-
91
- with patch ("chia.harvester.harvester_api.calculate_iterations_quality" ) as mock_calc_iter :
92
- # set required_iters low enough to pass the sp_interval_iters check
93
- mock_calc_iter .return_value = uint64 (1000 )
94
-
95
- with patch ("chia.harvester.harvester_api.calculate_sp_interval_iters" ) as mock_sp_interval :
96
- mock_sp_interval .return_value = uint64 (10000 )
97
-
98
- with patch .object (mock_prover , "get_full_proof" ) as mock_get_proof :
99
- mock_proof = MagicMock (spec = ProofOfSpace )
100
- mock_get_proof .return_value = mock_proof , None
101
-
102
- result = harvester_api .new_signage_point_harvester (new_challenge , mock_peer )
103
- # function returns None but should have processed the plot
104
- assert result is None
81
+ # let passes_plot_filter, calculate_pos_challenge, and calculate_sp_interval_iters use real implementations
82
+ with patch ("chia.harvester.harvester_api.calculate_iterations_quality" , return_value = uint64 (1000 )):
83
+ with patch .object (mock_plot_info .prover , "get_full_proof" ) as mock_get_proof :
84
+ mock_proof = MagicMock (spec = ProofOfSpace )
85
+ mock_get_proof .return_value = mock_proof , None
86
+ await harvester_api .new_signage_point_harvester (new_challenge , mock_peer )
105
87
106
88
107
89
@pytest .mark .anyio
108
- async def test_new_signage_point_harvester_pool_difficulty_override (
90
+ async def test_new_signage_point_harvester_pool_difficulty (
109
91
harvester_farmer_environment : HarvesterFarmerEnvironment ,
110
92
) -> None :
111
- """test that pool difficulty overrides are applied correctly """
112
- _farmer_service , _farmer_rpc_client , harvester_service , _harvester_rpc_client , bt = harvester_farmer_environment
93
+ """Test pool difficulty overrides with real blockchain signage points. """
94
+ _ , _ , harvester_service , _ , bt = harvester_farmer_environment
113
95
harvester_api = harvester_service ._server .api
114
96
assert isinstance (harvester_api , HarvesterAPI )
115
97
98
+ # harvester doesn't accept incoming connections, so use mock peer like other tests
116
99
mock_peer = MagicMock (spec = WSChiaConnection )
117
-
118
100
pool_puzzle_hash = bytes32 (b"pool" + b"0" * 28 )
119
101
120
- mock_prover = MagicMock ()
121
- mock_prover .get_id .return_value = bytes32 (b"2" * 32 )
122
- mock_prover .get_size .return_value = 32
123
- mock_prover .get_qualities_for_challenge .return_value = [bytes32 (b"quality" + b"0" * 25 )]
124
-
125
- mock_plot_info = MagicMock (spec = PlotInfo )
126
- mock_plot_info .prover = mock_prover
102
+ # create realistic plot info for testing
103
+ mock_plot_info = create_plot_info ()
127
104
mock_plot_info .pool_contract_puzzle_hash = pool_puzzle_hash
128
-
129
- plot_path = Path ("/fake/plot.plot" )
130
-
105
+ plot_path = Path ("/fake/pool_plot.plot" )
131
106
pool_difficulty = PoolDifficulty (
132
107
pool_contract_puzzle_hash = pool_puzzle_hash ,
133
108
difficulty = uint64 (500 ), # lower than main difficulty
134
109
sub_slot_iters = uint64 (67108864 ), # different from main
135
110
)
136
111
137
- # create real signage point data from constants with pool difficulty
138
- new_challenge = create_signage_point_harvester_from_constants (bt )
139
- # override with pool difficulty for this test
112
+ # create signage point from real block with pool difficulty
113
+ new_challenge = signage_point_from_block (bt )
140
114
new_challenge = harvester_protocol .NewSignagePointHarvester (
141
115
challenge_hash = new_challenge .challenge_hash ,
142
116
difficulty = new_challenge .difficulty ,
@@ -150,60 +124,44 @@ async def test_new_signage_point_harvester_pool_difficulty_override(
150
124
151
125
with patch .object (harvester_api .harvester .plot_manager , "public_keys_available" , return_value = True ):
152
126
with patch .object (harvester_api .harvester .plot_manager , "plots" , {plot_path : mock_plot_info }):
127
+ # mock passes_plot_filter to return True so we can test pool difficulty logic
153
128
with patch ("chia.harvester.harvester_api.passes_plot_filter" , return_value = True ):
154
- with patch ("chia.harvester.harvester_api.calculate_pos_challenge" ) as mock_calc_pos :
155
- mock_calc_pos .return_value = bytes32 (b"sp_challenge" + b"0" * 20 )
156
-
157
- with patch ("chia.harvester.harvester_api.calculate_iterations_quality" ) as mock_calc_iter :
158
- mock_calc_iter .return_value = uint64 (1000 )
159
-
160
- with patch ("chia.harvester.harvester_api.calculate_sp_interval_iters" ) as mock_sp_interval :
161
- mock_sp_interval .return_value = uint64 (10000 )
162
-
163
- with patch .object (mock_prover , "get_full_proof" ) as mock_get_proof :
164
- mock_proof = MagicMock (spec = ProofOfSpace )
165
- mock_get_proof .return_value = mock_proof , None
166
-
167
- result = harvester_api .new_signage_point_harvester (new_challenge , mock_peer )
168
-
169
- # verify that calculate_iterations_quality was called with pool difficulty
170
- mock_calc_iter .assert_called ()
171
- call_args = mock_calc_iter .call_args [0 ]
172
- assert call_args [3 ] == uint64 (500 ) # pool difficulty was used
173
-
174
- assert result is None
129
+ with patch ("chia.harvester.harvester_api.calculate_iterations_quality" ) as mock_calc_iter :
130
+ mock_calc_iter .return_value = uint64 (1000 )
131
+ with patch .object (mock_plot_info .prover , "get_full_proof" ) as mock_get_proof :
132
+ mock_proof = MagicMock (spec = ProofOfSpace )
133
+ mock_get_proof .return_value = mock_proof , None
134
+ await harvester_api .new_signage_point_harvester (new_challenge , mock_peer )
135
+ # verify that calculate_iterations_quality was called with pool difficulty
136
+ mock_calc_iter .assert_called ()
137
+ call_args = mock_calc_iter .call_args [0 ]
138
+ assert call_args [3 ] == uint64 (500 ) # pool difficulty was used
175
139
176
140
177
141
@pytest .mark .anyio
178
142
async def test_new_signage_point_harvester_prover_error (
179
143
harvester_farmer_environment : HarvesterFarmerEnvironment ,
180
144
) -> None :
181
- """test error handling when prover fails"""
182
- _farmer_service , _farmer_rpc_client , harvester_service , _harvester_rpc_client , bt = harvester_farmer_environment
145
+ """Test error handling when prover fails using real blockchain data. """
146
+ _ , _ , harvester_service , _ , bt = harvester_farmer_environment
183
147
harvester_api = harvester_service ._server .api
184
148
assert isinstance (harvester_api , HarvesterAPI )
185
149
186
- # create real signage point data from block tools
187
- new_challenge = create_signage_point_harvester_from_constants (bt )
150
+ # create signage point from real block
151
+ new_challenge = signage_point_from_block (bt )
188
152
189
153
mock_peer = MagicMock (spec = WSChiaConnection )
190
154
191
- mock_prover = MagicMock ()
192
- mock_prover .get_id .return_value = bytes32 (b"2" * 32 )
193
- mock_prover .get_qualities_for_challenge .side_effect = RuntimeError ("test error" )
194
-
195
- mock_plot_info = MagicMock (spec = PlotInfo )
196
- mock_plot_info .prover = mock_prover
197
- mock_plot_info .pool_contract_puzzle_hash = None
198
-
155
+ # create realistic plot info for testing
156
+ mock_plot_info = create_plot_info ()
199
157
plot_path = Path ("/fake/plot.plot" )
200
158
201
159
with patch .object (harvester_api .harvester .plot_manager , "public_keys_available" , return_value = True ):
202
160
with patch .object (harvester_api .harvester .plot_manager , "plots" , {plot_path : mock_plot_info }):
203
- with patch ( "chia.harvester.harvester_api. passes_plot_filter" , return_value = True ):
204
- with patch ( "chia.harvester.harvester_api.calculate_pos_challenge" ) as mock_calc_pos :
205
- mock_calc_pos . return_value = bytes32 ( b"sp_challenge" + b"0" * 20 )
206
-
207
- # should not raise exception, should handle error gracefully
208
- result = harvester_api . new_signage_point_harvester ( new_challenge , mock_peer )
209
- assert result is None
161
+ # let passes_plot_filter and calculate_pos_challenge use real implementations
162
+ # make the prover fail during quality check
163
+ with patch . object (
164
+ mock_plot_info . prover , "get_qualities_for_challenge" , side_effect = RuntimeError ( "test error" )
165
+ ):
166
+ # should not raise exception, should handle error gracefully
167
+ await harvester_api . new_signage_point_harvester ( new_challenge , mock_peer )
0 commit comments