Skip to content

Commit 794cce7

Browse files
authored
PoS2-prover (#20159)
* bump chia_rs to 0.31.0 * integrate new pos2 API from chia_rs into V2Prover * fixup test_harvester_api mocking of Prover * review-comments: rename get_quality() to get_string() on Quality protocol * reivew comments * fixup bump chia_rs * restore quality string to bytes32
1 parent e57358a commit 794cce7

File tree

22 files changed

+330
-302
lines changed

22 files changed

+330
-302
lines changed

chia/_tests/core/custom_types/test_proof_of_space.py

Lines changed: 19 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
from chia.consensus.default_constants import DEFAULT_CONSTANTS
1414
from chia.types.blockchain_format.proof_of_space import (
1515
calculate_prefix_bits,
16-
calculate_required_plot_strength,
1716
check_plot_size,
1817
make_pos,
1918
passes_plot_filter,
@@ -200,29 +199,6 @@ def test_verify_and_get_quality_string_v2(caplog: pytest.LogCaptureFixture, case
200199
assert len(caplog.text) == 0 if case.expected_error is None else case.expected_error in caplog.text
201200

202201

203-
@pytest.mark.parametrize(
204-
"height, strength",
205-
[
206-
(0, 2),
207-
(DEFAULT_CONSTANTS.HARD_FORK_HEIGHT, 2),
208-
(DEFAULT_CONSTANTS.HARD_FORK2_HEIGHT, 2),
209-
(DEFAULT_CONSTANTS.PLOT_STRENGTH_4_HEIGHT - 1, 2),
210-
(DEFAULT_CONSTANTS.PLOT_STRENGTH_4_HEIGHT, 4),
211-
(DEFAULT_CONSTANTS.PLOT_STRENGTH_5_HEIGHT - 1, 4),
212-
(DEFAULT_CONSTANTS.PLOT_STRENGTH_5_HEIGHT, 5),
213-
(DEFAULT_CONSTANTS.PLOT_STRENGTH_6_HEIGHT - 1, 5),
214-
(DEFAULT_CONSTANTS.PLOT_STRENGTH_6_HEIGHT, 6),
215-
(DEFAULT_CONSTANTS.PLOT_STRENGTH_7_HEIGHT - 1, 6),
216-
(DEFAULT_CONSTANTS.PLOT_STRENGTH_7_HEIGHT, 7),
217-
(DEFAULT_CONSTANTS.PLOT_STRENGTH_8_HEIGHT - 1, 7),
218-
(DEFAULT_CONSTANTS.PLOT_STRENGTH_8_HEIGHT, 8),
219-
(DEFAULT_CONSTANTS.PLOT_STRENGTH_8_HEIGHT + 1000000, 8),
220-
],
221-
)
222-
def test_calculate_plot_strength(height: uint32, strength: uint8) -> None:
223-
assert calculate_required_plot_strength(DEFAULT_CONSTANTS, height) == strength
224-
225-
226202
@pytest.mark.parametrize(
227203
"size, valid",
228204
[
@@ -272,12 +248,9 @@ def test_can_create_proof(self, prefix_bits: int, seeded_random: random.Random)
272248

273249

274250
@pytest.mark.parametrize("height,expected", [(0, 3), (5496000, 2), (10542000, 1), (15592000, 0), (20643000, 0)])
275-
@pytest.mark.parametrize("plot_size", [PlotSize.make_v1(32), PlotSize.make_v2(28)])
276-
def test_calculate_prefix_bits_clamp_zero(height: uint32, expected: int, plot_size: PlotSize) -> None:
251+
def test_calculate_prefix_bits_clamp_zero_v1(height: uint32, expected: int) -> None:
277252
constants = DEFAULT_CONSTANTS.replace(NUMBER_ZERO_BITS_PLOT_FILTER_V1=uint8(3))
278-
if plot_size.size_v2 is not None:
279-
expected = constants.NUMBER_ZERO_BITS_PLOT_FILTER_V2
280-
assert calculate_prefix_bits(constants, height, plot_size) == expected
253+
assert calculate_prefix_bits(constants, height, PlotSize.make_v1(32)) == expected
281254

282255

283256
@pytest.mark.parametrize(
@@ -294,9 +267,20 @@ def test_calculate_prefix_bits_clamp_zero(height: uint32, expected: int, plot_si
294267
(20643000, 5),
295268
],
296269
)
297-
@pytest.mark.parametrize("plot_size", [PlotSize.make_v1(32), PlotSize.make_v2(28)])
298-
def test_calculate_prefix_bits_default(height: uint32, expected: int, plot_size: PlotSize) -> None:
299-
constants = DEFAULT_CONSTANTS
300-
if plot_size.size_v2 is not None:
301-
expected = DEFAULT_CONSTANTS.NUMBER_ZERO_BITS_PLOT_FILTER_V2
302-
assert calculate_prefix_bits(constants, height, plot_size) == expected
270+
def test_calculate_prefix_bits_v1(height: uint32, expected: int) -> None:
271+
assert calculate_prefix_bits(DEFAULT_CONSTANTS, height, PlotSize.make_v1(32)) == expected
272+
273+
274+
@pytest.mark.parametrize(
275+
argnames=["height", "expected"],
276+
argvalues=[
277+
(0, 5),
278+
(0xFFFFFFFA, 5),
279+
(0xFFFFFFFB, 6),
280+
(0xFFFFFFFC, 7),
281+
(0xFFFFFFFD, 8),
282+
(0xFFFFFFFF, 8),
283+
],
284+
)
285+
def test_calculate_prefix_bits_v2(height: uint32, expected: int) -> None:
286+
assert calculate_prefix_bits(DEFAULT_CONSTANTS, height, PlotSize.make_v2(28)) == expected

chia/_tests/farmer_harvester/test_farmer_harvester.py

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -338,9 +338,11 @@ async def test_v2_partial_proofs_new_sp_hash(
338338
challenge_hash=bytes32(b"2" * 32),
339339
sp_hash=sp_hash,
340340
plot_identifier="test_plot_id",
341-
partial_proofs=[b"test_partial_proof_1"],
341+
partial_proofs=[[uint64(1), uint64(2), uint64(3), uint64(4)]],
342342
signage_point_index=uint8(0),
343343
plot_size=uint8(32),
344+
strength=uint8(5),
345+
plot_id=bytes32.fromhex("abababababababababababababababababababababababababababababababab"),
344346
pool_public_key=None,
345347
pool_contract_puzzle_hash=bytes32(b"4" * 32),
346348
plot_public_key=G1Element(),
@@ -367,9 +369,11 @@ async def test_v2_partial_proofs_missing_sp_hash(
367369
challenge_hash=bytes32(b"2" * 32),
368370
sp_hash=sp_hash,
369371
plot_identifier="test_plot_id",
370-
partial_proofs=[b"test_partial_proof_1"],
372+
partial_proofs=[[uint64(1), uint64(2), uint64(3), uint64(4)]],
371373
signage_point_index=uint8(0),
372374
plot_size=uint8(32),
375+
plot_id=bytes32.fromhex("abababababababababababababababababababababababababababababababab"),
376+
strength=uint8(5),
373377
pool_public_key=None,
374378
pool_contract_puzzle_hash=bytes32(b"4" * 32),
375379
plot_public_key=G1Element(),
@@ -409,9 +413,11 @@ async def test_v2_partial_proofs_with_existing_sp(
409413
challenge_hash=challenge_hash,
410414
sp_hash=sp_hash,
411415
plot_identifier="test_plot_id",
412-
partial_proofs=[b"test_partial_proof_1", b"test_partial_proof_2"],
416+
partial_proofs=[[uint64(1), uint64(2), uint64(3), uint64(4)], [uint64(2), uint64(3), uint64(4), uint64(5)]],
413417
signage_point_index=uint8(0),
414418
plot_size=uint8(32),
419+
plot_id=bytes32.fromhex("abababababababababababababababababababababababababababababababab"),
420+
strength=uint8(5),
415421
pool_public_key=G1Element(),
416422
pool_contract_puzzle_hash=bytes32(b"4" * 32),
417423
plot_public_key=G1Element(),
@@ -441,9 +447,11 @@ async def test_solution_response_handler(
441447
challenge_hash=challenge_hash,
442448
sp_hash=sp_hash,
443449
plot_identifier="test_plot_id",
444-
partial_proofs=[b"test_partial_proof_for_quality"],
450+
partial_proofs=[[uint64(1), uint64(2), uint64(3), uint64(4)]],
445451
signage_point_index=uint8(0),
446452
plot_size=uint8(32),
453+
plot_id=bytes32.fromhex("abababababababababababababababababababababababababababababababab"),
454+
strength=uint8(5),
447455
pool_public_key=G1Element(),
448456
pool_contract_puzzle_hash=bytes32(b"4" * 32),
449457
plot_public_key=G1Element(),
@@ -452,7 +460,8 @@ async def test_solution_response_handler(
452460
harvester_peer = await get_harvester_peer(farmer)
453461

454462
# manually add pending request
455-
farmer.pending_solver_requests[partial_proofs.partial_proofs[0]] = {
463+
key = bytes(partial_proofs.partial_proofs[0])
464+
farmer.pending_solver_requests[key] = {
456465
"proof_data": partial_proofs,
457466
"peer": harvester_peer,
458467
}
@@ -477,7 +486,8 @@ async def test_solution_response_handler(
477486
assert original_peer == harvester_peer
478487

479488
# verify pending request was removed
480-
assert partial_proofs.partial_proofs[0] not in farmer.pending_solver_requests
489+
key = bytes(partial_proofs.partial_proofs[0])
490+
assert key not in farmer.pending_solver_requests
481491

482492

483493
@pytest.mark.anyio
@@ -492,7 +502,9 @@ async def test_solution_response_unknown_quality(
492502
solver_peer = await get_solver_peer(farmer)
493503

494504
# create solution response with unknown quality
495-
solution_response = solver_protocol.SolverResponse(partial_proof=bytes(b"1" * 32), proof=b"test_proof")
505+
solution_response = solver_protocol.SolverResponse(
506+
partial_proof=[uint64(1), uint64(2), uint64(3), uint64(4)], proof=b"test_proof"
507+
)
496508

497509
with unittest.mock.patch.object(farmer_api, "new_proof_of_space", new_callable=AsyncMock) as mock_new_proof:
498510
await farmer_api.solution_response(solution_response, solver_peer)
@@ -518,9 +530,11 @@ async def test_solution_response_empty_proof(
518530
challenge_hash=challenge_hash,
519531
sp_hash=sp_hash,
520532
plot_identifier="test_plot_id",
521-
partial_proofs=[b"test_partial_proof_for_quality"],
533+
partial_proofs=[[uint64(1), uint64(2), uint64(3), uint64(4)], [uint64(2), uint64(3), uint64(4), uint64(5)]],
522534
signage_point_index=uint8(0),
523535
plot_size=uint8(32),
536+
plot_id=bytes32.fromhex("abababababababababababababababababababababababababababababababab"),
537+
strength=uint8(5),
524538
pool_public_key=G1Element(),
525539
pool_contract_puzzle_hash=bytes32(b"4" * 32),
526540
plot_public_key=G1Element(),
@@ -530,8 +544,9 @@ async def test_solution_response_empty_proof(
530544
harvester_peer.peer_node_id = "harvester_peer"
531545

532546
# manually add pending request
533-
farmer.pending_solver_requests[partial_proofs.partial_proofs[0]] = {
534-
"proof_data": partial_proofs.partial_proofs[0],
547+
key = bytes(partial_proofs.partial_proofs[0])
548+
farmer.pending_solver_requests[key] = {
549+
"proof_data": partial_proofs,
535550
"peer": harvester_peer,
536551
}
537552

@@ -548,7 +563,8 @@ async def test_solution_response_empty_proof(
548563
mock_new_proof.assert_not_called()
549564

550565
# verify pending request was removed (cleanup still happens)
551-
assert partial_proofs.partial_proofs[0] not in farmer.pending_solver_requests
566+
key = bytes(partial_proofs.partial_proofs[0])
567+
assert key not in farmer.pending_solver_requests
552568

553569

554570
@pytest.mark.anyio
@@ -579,9 +595,11 @@ async def test_v2_partial_proofs_solver_exception(
579595
challenge_hash=challenge_hash,
580596
sp_hash=sp_hash,
581597
plot_identifier="test_plot_id",
582-
partial_proofs=[b"test_partial_proof_1"],
598+
partial_proofs=[[uint64(1), uint64(2), uint64(3), uint64(4)], [uint64(2), uint64(3), uint64(4), uint64(5)]],
583599
signage_point_index=uint8(0),
584600
plot_size=uint8(32),
601+
plot_id=bytes32.fromhex("abababababababababababababababababababababababababababababababab"),
602+
strength=uint8(5),
585603
pool_public_key=G1Element(),
586604
pool_contract_puzzle_hash=bytes32(b"4" * 32),
587605
plot_public_key=G1Element(),
@@ -594,4 +612,5 @@ async def test_v2_partial_proofs_solver_exception(
594612
await farmer_api.partial_proofs(partial_proofs, harvester_peer)
595613

596614
# verify pending request was cleaned up after exception
597-
assert partial_proofs.partial_proofs[0] not in farmer.pending_solver_requests
615+
key = bytes(partial_proofs.partial_proofs[0])
616+
assert key not in farmer.pending_solver_requests

chia/_tests/harvester/test_harvester_api.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from chia._tests.plotting.util import get_test_plots
1616
from chia._tests.util.time_out_assert import time_out_assert
1717
from chia.harvester.harvester_api import HarvesterAPI
18+
from chia.plotting.prover import V1Prover, V2Prover
1819
from chia.plotting.util import PlotInfo
1920
from chia.protocols import harvester_protocol
2021
from chia.protocols.harvester_protocol import PoolDifficulty
@@ -85,10 +86,16 @@ def create_test_setup(
8586

8687
@contextmanager
8788
def mock_successful_proof(plot_info: PlotInfo) -> Iterator[None]:
88-
with patch.object(plot_info.prover, "get_full_proof") as mock_get_proof:
89-
mock_proof = MagicMock(spec=ProofOfSpace)
90-
mock_get_proof.return_value = mock_proof, None
91-
yield
89+
if isinstance(plot_info.prover, V1Prover):
90+
with patch.object(plot_info.prover, "get_full_proof") as mock_get_proof:
91+
mock_proof = MagicMock(spec=ProofOfSpace)
92+
mock_get_proof.return_value = mock_proof, None
93+
yield
94+
elif isinstance(plot_info.prover, V2Prover):
95+
with patch.object(plot_info.prover, "get_partial_proof") as mock_get_proof:
96+
mock_proof = MagicMock(spec=ProofOfSpace)
97+
mock_get_proof.return_value = [uint64(1)] * 64, None
98+
yield
9299

93100

94101
def assert_farming_info_sent(mock_peer: MagicMock) -> None:

chia/_tests/plotting/test_prover.py

Lines changed: 27 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -12,44 +12,57 @@
1212

1313

1414
class TestProver:
15+
def test_get_prover_from_file_with_plot1_still_works(self) -> None:
16+
with tempfile.NamedTemporaryFile(suffix=".plot", delete=False) as f:
17+
temp_path = f.name
18+
try:
19+
with pytest.raises(Exception) as exc_info:
20+
get_prover_from_file(temp_path)
21+
assert not isinstance(exc_info.value, NotImplementedError)
22+
finally:
23+
Path(temp_path).unlink()
24+
25+
def test_unsupported_file_extension_raises_value_error(self) -> None:
26+
with pytest.raises(ValueError, match="Unsupported plot file"):
27+
get_prover_from_file("/nonexistent/path/test.txt")
28+
29+
30+
# TODO: todo_v2_plots enable these tests once we have test plots we can load
31+
@pytest.mark.skip("we don't have v2 test plots yet")
32+
class TestV2Prover:
1533
def test_v2_prover_init_with_nonexistent_file(self) -> None:
16-
prover = V2Prover("/nonexistent/path/test.plot2")
34+
prover = V2Prover.from_filename("/nonexistent/path/test.plot2")
1735
assert prover.get_version() == PlotVersion.V2
1836
assert prover.get_filename() == "/nonexistent/path/test.plot2"
1937

2038
def test_v2_prover_get_size_raises_error(self) -> None:
21-
prover = V2Prover("/nonexistent/path/test.plot2")
39+
prover = V2Prover.from_filename("/nonexistent/path/test.plot2")
2240
with pytest.raises(NotImplementedError, match="V2 plot format is not yet implemented"):
2341
prover.get_size()
2442

2543
def test_v2_prover_get_memo_raises_error(self) -> None:
26-
prover = V2Prover("/nonexistent/path/test.plot2")
44+
prover = V2Prover.from_filename("/nonexistent/path/test.plot2")
2745
with pytest.raises(NotImplementedError, match="V2 plot format is not yet implemented"):
2846
prover.get_memo()
2947

3048
def test_v2_prover_get_compression_level(self) -> None:
31-
prover = V2Prover("/nonexistent/path/test.plot2")
49+
prover = V2Prover.from_filename("/nonexistent/path/test.plot2")
3250
assert prover.get_compression_level() == uint8(0)
3351

3452
def test_v2_prover_get_id_raises_error(self) -> None:
35-
prover = V2Prover("/nonexistent/path/test.plot2")
53+
prover = V2Prover.from_filename("/nonexistent/path/test.plot2")
3654
with pytest.raises(NotImplementedError, match="V2 plot format is not yet implemented"):
3755
prover.get_id()
3856

3957
def test_v2_prover_get_qualities_for_challenge_raises_error(self) -> None:
40-
prover = V2Prover("/nonexistent/path/test.plot2")
58+
prover = V2Prover.from_filename("/nonexistent/path/test.plot2")
4159
with pytest.raises(
4260
AssertionError, match="V2 plot format does not support qualities directly, use partial proofs"
4361
):
44-
prover.get_qualities_for_challenge(bytes32(b"1" * 32))
45-
46-
def test_v2_prover_get_full_proof_raises_error(self) -> None:
47-
prover = V2Prover("/nonexistent/path/test.plot2")
48-
with pytest.raises(AssertionError, match="V2 plot format require solver to get full proof"):
49-
prover.get_full_proof(bytes32(b"1" * 32), 0)
62+
prover.get_qualities_for_challenge(bytes32(b"1" * 32), uint8(5))
5063

5164
def test_v2_prover_bytes_raises_error(self) -> None:
52-
prover = V2Prover("/nonexistent/path/test.plot2")
65+
prover = V2Prover.from_filename("/nonexistent/path/test.plot2")
5366
with pytest.raises(NotImplementedError, match="V2 plot format is not yet implemented"):
5467
bytes(prover)
5568

@@ -63,20 +76,6 @@ def test_get_prover_from_file(self) -> None:
6376
with pytest.raises(NotImplementedError, match="V2 plot format is not yet implemented"):
6477
prover.get_size()
6578

66-
def test_get_prover_from_file_with_plot1_still_works(self) -> None:
67-
with tempfile.NamedTemporaryFile(suffix=".plot", delete=False) as f:
68-
temp_path = f.name
69-
try:
70-
with pytest.raises(Exception) as exc_info:
71-
get_prover_from_file(temp_path)
72-
assert not isinstance(exc_info.value, NotImplementedError)
73-
finally:
74-
Path(temp_path).unlink()
75-
76-
def test_unsupported_file_extension_raises_value_error(self) -> None:
77-
with pytest.raises(ValueError, match="Unsupported plot file"):
78-
get_prover_from_file("/nonexistent/path/test.txt")
79-
8079

8180
class TestV1Prover:
8281
def test_v1_prover_get_version(self) -> None:
@@ -87,13 +86,6 @@ def test_v1_prover_get_version(self) -> None:
8786

8887

8988
class TestGetProverFromBytes:
90-
def test_get_prover_from_bytes_v2_plot(self) -> None:
91-
with patch("chia.plotting.prover.V2Prover.from_bytes") as mock_v2_from_bytes:
92-
mock_prover = MagicMock()
93-
mock_v2_from_bytes.return_value = mock_prover
94-
result = get_prover_from_bytes("test.plot2", b"test_data")
95-
assert result == mock_prover
96-
9789
def test_get_prover_from_bytes_v1_plot(self) -> None:
9890
with patch("chia.plotting.prover.DiskProver") as mock_disk_prover_class:
9991
mock_disk_prover = MagicMock()
@@ -102,5 +94,5 @@ def test_get_prover_from_bytes_v1_plot(self) -> None:
10294
assert isinstance(result, V1Prover)
10395

10496
def test_get_prover_from_bytes_unsupported_extension(self) -> None:
105-
with pytest.raises(ValueError, match="Unsupported plot file"):
97+
with pytest.raises((RuntimeError, ValueError)):
10698
get_prover_from_bytes("test.txt", b"test_data")

chia/_tests/solver/test_solver_service.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
import pytest
77
from chia_rs import ConsensusConstants
8+
from chia_rs.sized_bytes import bytes32
9+
from chia_rs.sized_ints import uint8, uint64
810

911
from chia.protocols.outbound_message import Message
1012
from chia.protocols.solver_protocol import SolverInfo
@@ -21,7 +23,12 @@ async def test_solver_api_methods(blockchain_constants: ConsensusConstants, tmp_
2123
solver = solver_service._node
2224
solver_api = solver_service._api
2325
assert solver_api.ready() is True
24-
test_info = SolverInfo(partial_proof=b"test_partial_proof_42")
26+
test_info = SolverInfo(
27+
partial_proof=[uint64(1), uint64(2), uint64(3), uint64(4)],
28+
plot_id=bytes32.fromhex("abababababababababababababababababababababababababababababababab"),
29+
strength=uint8(5),
30+
size=uint8(28),
31+
)
2532
expected_proof = b"test_proof_data_12345"
2633
with patch.object(solver, "solve", return_value=expected_proof):
2734
api_result = await solver_api.solve(test_info)

0 commit comments

Comments
 (0)