Skip to content

Commit 1626309

Browse files
committed
solver service, api, rpc
1 parent e9fecc0 commit 1626309

25 files changed

+529
-178
lines changed

chia/_tests/conftest.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
)
7171
from chia.simulator.start_simulator import SimulatorFullNodeService
7272
from chia.simulator.wallet_tools import WalletTool
73+
from chia.solver.solver_service import SolverService
7374
from chia.timelord.timelord_service import TimelordService
7475
from chia.types.peer_info import PeerInfo
7576
from chia.util.config import create_default_chia_config, lock_and_load_config

chia/_tests/core/custom_types/test_proof_of_space.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ def test_calculate_plot_difficulty(height: uint32, difficulty: uint8) -> None:
223223

224224
class TestProofOfSpace:
225225
@pytest.mark.parametrize("prefix_bits", [DEFAULT_CONSTANTS.NUMBER_ZERO_BITS_PLOT_FILTER_V1, 8, 7, 6, 5, 1, 0])
226-
def test_can_create_proof(self, prefix_bits: int, seeded_random: random.Random) -> None:
226+
def test_can_create_proof(self, prefix_bits: uint8, seeded_random: random.Random) -> None:
227227
"""
228228
Tests that the change of getting a correct proof is exactly 1/target_filter.
229229
"""

chia/_tests/harvester/test_harvester_api.py

Lines changed: 82 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -17,126 +17,100 @@
1717
from chia.simulator.block_tools import BlockTools
1818

1919

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+
)
2537

26-
# create a version with real constants values
2738
return harvester_protocol.NewSignagePointHarvester(
28-
challenge_hash=new_signage_point_harvester.challenge_hash,
39+
challenge_hash=challenge_hash,
2940
difficulty=uint64(bt.constants.DIFFICULTY_STARTING),
3041
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,
3647
)
3748

3849

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
5461

55-
result = harvester_api.new_signage_point_harvester(new_challenge, mock_peer)
56-
assert result is None
62+
return mock_plot_info
5763

5864

5965
@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
6569
harvester_api = harvester_service._server.api
6670
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
7174
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()
8377
plot_path = Path("/fake/plot.plot")
8478

8579
with patch.object(harvester_api.harvester.plot_manager, "public_keys_available", return_value=True):
8680
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)
10587

10688

10789
@pytest.mark.anyio
108-
async def test_new_signage_point_harvester_pool_difficulty_override(
90+
async def test_new_signage_point_harvester_pool_difficulty(
10991
harvester_farmer_environment: HarvesterFarmerEnvironment,
11092
) -> 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
11395
harvester_api = harvester_service._server.api
11496
assert isinstance(harvester_api, HarvesterAPI)
11597

98+
# harvester doesn't accept incoming connections, so use mock peer like other tests
11699
mock_peer = MagicMock(spec=WSChiaConnection)
117-
118100
pool_puzzle_hash = bytes32(b"pool" + b"0" * 28)
119101

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()
127104
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")
131106
pool_difficulty = PoolDifficulty(
132107
pool_contract_puzzle_hash=pool_puzzle_hash,
133108
difficulty=uint64(500), # lower than main difficulty
134109
sub_slot_iters=uint64(67108864), # different from main
135110
)
136111

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)
140114
new_challenge = harvester_protocol.NewSignagePointHarvester(
141115
challenge_hash=new_challenge.challenge_hash,
142116
difficulty=new_challenge.difficulty,
@@ -150,60 +124,44 @@ async def test_new_signage_point_harvester_pool_difficulty_override(
150124

151125
with patch.object(harvester_api.harvester.plot_manager, "public_keys_available", return_value=True):
152126
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
153128
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
175139

176140

177141
@pytest.mark.anyio
178142
async def test_new_signage_point_harvester_prover_error(
179143
harvester_farmer_environment: HarvesterFarmerEnvironment,
180144
) -> 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
183147
harvester_api = harvester_service._server.api
184148
assert isinstance(harvester_api, HarvesterAPI)
185149

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)
188152

189153
mock_peer = MagicMock(spec=WSChiaConnection)
190154

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()
199157
plot_path = Path("/fake/plot.plot")
200158

201159
with patch.object(harvester_api.harvester.plot_manager, "public_keys_available", return_value=True):
202160
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)

chia/_tests/plotting/test_prover.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def test_v2_prover_get_qualities_for_challenge_raises_error(self) -> None:
4242

4343
def test_v2_prover_get_full_proof_raises_error(self) -> None:
4444
prover = V2Prover("/nonexistent/path/test.plot2")
45-
with pytest.raises(NotImplementedError, match="V2 plot format is not yet implemented"):
45+
with pytest.raises(NotImplementedError, match="V2 plot format require solver to get full proof"):
4646
prover.get_full_proof(b"challenge", 0)
4747

4848
def test_v2_prover_bytes_raises_error(self) -> None:

chia/_tests/solver/test_solver.py

Lines changed: 0 additions & 30 deletions
This file was deleted.

0 commit comments

Comments
 (0)