mirror of
https://github.com/Chia-Network/chia-blockchain.git
synced 2026-08-24 10:05:29 -05:00
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
This commit is contained in:
@@ -13,7 +13,6 @@ from chia._tests.util.misc import Marks, datacases
|
||||
from chia.consensus.default_constants import DEFAULT_CONSTANTS
|
||||
from chia.types.blockchain_format.proof_of_space import (
|
||||
calculate_prefix_bits,
|
||||
calculate_required_plot_strength,
|
||||
check_plot_size,
|
||||
make_pos,
|
||||
passes_plot_filter,
|
||||
@@ -200,29 +199,6 @@ def test_verify_and_get_quality_string_v2(caplog: pytest.LogCaptureFixture, case
|
||||
assert len(caplog.text) == 0 if case.expected_error is None else case.expected_error in caplog.text
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"height, strength",
|
||||
[
|
||||
(0, 2),
|
||||
(DEFAULT_CONSTANTS.HARD_FORK_HEIGHT, 2),
|
||||
(DEFAULT_CONSTANTS.HARD_FORK2_HEIGHT, 2),
|
||||
(DEFAULT_CONSTANTS.PLOT_STRENGTH_4_HEIGHT - 1, 2),
|
||||
(DEFAULT_CONSTANTS.PLOT_STRENGTH_4_HEIGHT, 4),
|
||||
(DEFAULT_CONSTANTS.PLOT_STRENGTH_5_HEIGHT - 1, 4),
|
||||
(DEFAULT_CONSTANTS.PLOT_STRENGTH_5_HEIGHT, 5),
|
||||
(DEFAULT_CONSTANTS.PLOT_STRENGTH_6_HEIGHT - 1, 5),
|
||||
(DEFAULT_CONSTANTS.PLOT_STRENGTH_6_HEIGHT, 6),
|
||||
(DEFAULT_CONSTANTS.PLOT_STRENGTH_7_HEIGHT - 1, 6),
|
||||
(DEFAULT_CONSTANTS.PLOT_STRENGTH_7_HEIGHT, 7),
|
||||
(DEFAULT_CONSTANTS.PLOT_STRENGTH_8_HEIGHT - 1, 7),
|
||||
(DEFAULT_CONSTANTS.PLOT_STRENGTH_8_HEIGHT, 8),
|
||||
(DEFAULT_CONSTANTS.PLOT_STRENGTH_8_HEIGHT + 1000000, 8),
|
||||
],
|
||||
)
|
||||
def test_calculate_plot_strength(height: uint32, strength: uint8) -> None:
|
||||
assert calculate_required_plot_strength(DEFAULT_CONSTANTS, height) == strength
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"size, valid",
|
||||
[
|
||||
@@ -272,12 +248,9 @@ class TestProofOfSpace:
|
||||
|
||||
|
||||
@pytest.mark.parametrize("height,expected", [(0, 3), (5496000, 2), (10542000, 1), (15592000, 0), (20643000, 0)])
|
||||
@pytest.mark.parametrize("plot_size", [PlotSize.make_v1(32), PlotSize.make_v2(28)])
|
||||
def test_calculate_prefix_bits_clamp_zero(height: uint32, expected: int, plot_size: PlotSize) -> None:
|
||||
def test_calculate_prefix_bits_clamp_zero_v1(height: uint32, expected: int) -> None:
|
||||
constants = DEFAULT_CONSTANTS.replace(NUMBER_ZERO_BITS_PLOT_FILTER_V1=uint8(3))
|
||||
if plot_size.size_v2 is not None:
|
||||
expected = constants.NUMBER_ZERO_BITS_PLOT_FILTER_V2
|
||||
assert calculate_prefix_bits(constants, height, plot_size) == expected
|
||||
assert calculate_prefix_bits(constants, height, PlotSize.make_v1(32)) == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
@@ -294,9 +267,20 @@ def test_calculate_prefix_bits_clamp_zero(height: uint32, expected: int, plot_si
|
||||
(20643000, 5),
|
||||
],
|
||||
)
|
||||
@pytest.mark.parametrize("plot_size", [PlotSize.make_v1(32), PlotSize.make_v2(28)])
|
||||
def test_calculate_prefix_bits_default(height: uint32, expected: int, plot_size: PlotSize) -> None:
|
||||
constants = DEFAULT_CONSTANTS
|
||||
if plot_size.size_v2 is not None:
|
||||
expected = DEFAULT_CONSTANTS.NUMBER_ZERO_BITS_PLOT_FILTER_V2
|
||||
assert calculate_prefix_bits(constants, height, plot_size) == expected
|
||||
def test_calculate_prefix_bits_v1(height: uint32, expected: int) -> None:
|
||||
assert calculate_prefix_bits(DEFAULT_CONSTANTS, height, PlotSize.make_v1(32)) == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
argnames=["height", "expected"],
|
||||
argvalues=[
|
||||
(0, 5),
|
||||
(0xFFFFFFFA, 5),
|
||||
(0xFFFFFFFB, 6),
|
||||
(0xFFFFFFFC, 7),
|
||||
(0xFFFFFFFD, 8),
|
||||
(0xFFFFFFFF, 8),
|
||||
],
|
||||
)
|
||||
def test_calculate_prefix_bits_v2(height: uint32, expected: int) -> None:
|
||||
assert calculate_prefix_bits(DEFAULT_CONSTANTS, height, PlotSize.make_v2(28)) == expected
|
||||
|
||||
@@ -338,9 +338,11 @@ async def test_v2_partial_proofs_new_sp_hash(
|
||||
challenge_hash=bytes32(b"2" * 32),
|
||||
sp_hash=sp_hash,
|
||||
plot_identifier="test_plot_id",
|
||||
partial_proofs=[b"test_partial_proof_1"],
|
||||
partial_proofs=[[uint64(1), uint64(2), uint64(3), uint64(4)]],
|
||||
signage_point_index=uint8(0),
|
||||
plot_size=uint8(32),
|
||||
strength=uint8(5),
|
||||
plot_id=bytes32.fromhex("abababababababababababababababababababababababababababababababab"),
|
||||
pool_public_key=None,
|
||||
pool_contract_puzzle_hash=bytes32(b"4" * 32),
|
||||
plot_public_key=G1Element(),
|
||||
@@ -367,9 +369,11 @@ async def test_v2_partial_proofs_missing_sp_hash(
|
||||
challenge_hash=bytes32(b"2" * 32),
|
||||
sp_hash=sp_hash,
|
||||
plot_identifier="test_plot_id",
|
||||
partial_proofs=[b"test_partial_proof_1"],
|
||||
partial_proofs=[[uint64(1), uint64(2), uint64(3), uint64(4)]],
|
||||
signage_point_index=uint8(0),
|
||||
plot_size=uint8(32),
|
||||
plot_id=bytes32.fromhex("abababababababababababababababababababababababababababababababab"),
|
||||
strength=uint8(5),
|
||||
pool_public_key=None,
|
||||
pool_contract_puzzle_hash=bytes32(b"4" * 32),
|
||||
plot_public_key=G1Element(),
|
||||
@@ -409,9 +413,11 @@ async def test_v2_partial_proofs_with_existing_sp(
|
||||
challenge_hash=challenge_hash,
|
||||
sp_hash=sp_hash,
|
||||
plot_identifier="test_plot_id",
|
||||
partial_proofs=[b"test_partial_proof_1", b"test_partial_proof_2"],
|
||||
partial_proofs=[[uint64(1), uint64(2), uint64(3), uint64(4)], [uint64(2), uint64(3), uint64(4), uint64(5)]],
|
||||
signage_point_index=uint8(0),
|
||||
plot_size=uint8(32),
|
||||
plot_id=bytes32.fromhex("abababababababababababababababababababababababababababababababab"),
|
||||
strength=uint8(5),
|
||||
pool_public_key=G1Element(),
|
||||
pool_contract_puzzle_hash=bytes32(b"4" * 32),
|
||||
plot_public_key=G1Element(),
|
||||
@@ -441,9 +447,11 @@ async def test_solution_response_handler(
|
||||
challenge_hash=challenge_hash,
|
||||
sp_hash=sp_hash,
|
||||
plot_identifier="test_plot_id",
|
||||
partial_proofs=[b"test_partial_proof_for_quality"],
|
||||
partial_proofs=[[uint64(1), uint64(2), uint64(3), uint64(4)]],
|
||||
signage_point_index=uint8(0),
|
||||
plot_size=uint8(32),
|
||||
plot_id=bytes32.fromhex("abababababababababababababababababababababababababababababababab"),
|
||||
strength=uint8(5),
|
||||
pool_public_key=G1Element(),
|
||||
pool_contract_puzzle_hash=bytes32(b"4" * 32),
|
||||
plot_public_key=G1Element(),
|
||||
@@ -452,7 +460,8 @@ async def test_solution_response_handler(
|
||||
harvester_peer = await get_harvester_peer(farmer)
|
||||
|
||||
# manually add pending request
|
||||
farmer.pending_solver_requests[partial_proofs.partial_proofs[0]] = {
|
||||
key = bytes(partial_proofs.partial_proofs[0])
|
||||
farmer.pending_solver_requests[key] = {
|
||||
"proof_data": partial_proofs,
|
||||
"peer": harvester_peer,
|
||||
}
|
||||
@@ -477,7 +486,8 @@ async def test_solution_response_handler(
|
||||
assert original_peer == harvester_peer
|
||||
|
||||
# verify pending request was removed
|
||||
assert partial_proofs.partial_proofs[0] not in farmer.pending_solver_requests
|
||||
key = bytes(partial_proofs.partial_proofs[0])
|
||||
assert key not in farmer.pending_solver_requests
|
||||
|
||||
|
||||
@pytest.mark.anyio
|
||||
@@ -492,7 +502,9 @@ async def test_solution_response_unknown_quality(
|
||||
solver_peer = await get_solver_peer(farmer)
|
||||
|
||||
# create solution response with unknown quality
|
||||
solution_response = solver_protocol.SolverResponse(partial_proof=bytes(b"1" * 32), proof=b"test_proof")
|
||||
solution_response = solver_protocol.SolverResponse(
|
||||
partial_proof=[uint64(1), uint64(2), uint64(3), uint64(4)], proof=b"test_proof"
|
||||
)
|
||||
|
||||
with unittest.mock.patch.object(farmer_api, "new_proof_of_space", new_callable=AsyncMock) as mock_new_proof:
|
||||
await farmer_api.solution_response(solution_response, solver_peer)
|
||||
@@ -518,9 +530,11 @@ async def test_solution_response_empty_proof(
|
||||
challenge_hash=challenge_hash,
|
||||
sp_hash=sp_hash,
|
||||
plot_identifier="test_plot_id",
|
||||
partial_proofs=[b"test_partial_proof_for_quality"],
|
||||
partial_proofs=[[uint64(1), uint64(2), uint64(3), uint64(4)], [uint64(2), uint64(3), uint64(4), uint64(5)]],
|
||||
signage_point_index=uint8(0),
|
||||
plot_size=uint8(32),
|
||||
plot_id=bytes32.fromhex("abababababababababababababababababababababababababababababababab"),
|
||||
strength=uint8(5),
|
||||
pool_public_key=G1Element(),
|
||||
pool_contract_puzzle_hash=bytes32(b"4" * 32),
|
||||
plot_public_key=G1Element(),
|
||||
@@ -530,8 +544,9 @@ async def test_solution_response_empty_proof(
|
||||
harvester_peer.peer_node_id = "harvester_peer"
|
||||
|
||||
# manually add pending request
|
||||
farmer.pending_solver_requests[partial_proofs.partial_proofs[0]] = {
|
||||
"proof_data": partial_proofs.partial_proofs[0],
|
||||
key = bytes(partial_proofs.partial_proofs[0])
|
||||
farmer.pending_solver_requests[key] = {
|
||||
"proof_data": partial_proofs,
|
||||
"peer": harvester_peer,
|
||||
}
|
||||
|
||||
@@ -548,7 +563,8 @@ async def test_solution_response_empty_proof(
|
||||
mock_new_proof.assert_not_called()
|
||||
|
||||
# verify pending request was removed (cleanup still happens)
|
||||
assert partial_proofs.partial_proofs[0] not in farmer.pending_solver_requests
|
||||
key = bytes(partial_proofs.partial_proofs[0])
|
||||
assert key not in farmer.pending_solver_requests
|
||||
|
||||
|
||||
@pytest.mark.anyio
|
||||
@@ -579,9 +595,11 @@ async def test_v2_partial_proofs_solver_exception(
|
||||
challenge_hash=challenge_hash,
|
||||
sp_hash=sp_hash,
|
||||
plot_identifier="test_plot_id",
|
||||
partial_proofs=[b"test_partial_proof_1"],
|
||||
partial_proofs=[[uint64(1), uint64(2), uint64(3), uint64(4)], [uint64(2), uint64(3), uint64(4), uint64(5)]],
|
||||
signage_point_index=uint8(0),
|
||||
plot_size=uint8(32),
|
||||
plot_id=bytes32.fromhex("abababababababababababababababababababababababababababababababab"),
|
||||
strength=uint8(5),
|
||||
pool_public_key=G1Element(),
|
||||
pool_contract_puzzle_hash=bytes32(b"4" * 32),
|
||||
plot_public_key=G1Element(),
|
||||
@@ -594,4 +612,5 @@ async def test_v2_partial_proofs_solver_exception(
|
||||
await farmer_api.partial_proofs(partial_proofs, harvester_peer)
|
||||
|
||||
# verify pending request was cleaned up after exception
|
||||
assert partial_proofs.partial_proofs[0] not in farmer.pending_solver_requests
|
||||
key = bytes(partial_proofs.partial_proofs[0])
|
||||
assert key not in farmer.pending_solver_requests
|
||||
|
||||
@@ -15,6 +15,7 @@ from chia._tests.conftest import HarvesterFarmerEnvironment
|
||||
from chia._tests.plotting.util import get_test_plots
|
||||
from chia._tests.util.time_out_assert import time_out_assert
|
||||
from chia.harvester.harvester_api import HarvesterAPI
|
||||
from chia.plotting.prover import V1Prover, V2Prover
|
||||
from chia.plotting.util import PlotInfo
|
||||
from chia.protocols import harvester_protocol
|
||||
from chia.protocols.harvester_protocol import PoolDifficulty
|
||||
@@ -85,10 +86,16 @@ def create_test_setup(
|
||||
|
||||
@contextmanager
|
||||
def mock_successful_proof(plot_info: PlotInfo) -> Iterator[None]:
|
||||
with patch.object(plot_info.prover, "get_full_proof") as mock_get_proof:
|
||||
mock_proof = MagicMock(spec=ProofOfSpace)
|
||||
mock_get_proof.return_value = mock_proof, None
|
||||
yield
|
||||
if isinstance(plot_info.prover, V1Prover):
|
||||
with patch.object(plot_info.prover, "get_full_proof") as mock_get_proof:
|
||||
mock_proof = MagicMock(spec=ProofOfSpace)
|
||||
mock_get_proof.return_value = mock_proof, None
|
||||
yield
|
||||
elif isinstance(plot_info.prover, V2Prover):
|
||||
with patch.object(plot_info.prover, "get_partial_proof") as mock_get_proof:
|
||||
mock_proof = MagicMock(spec=ProofOfSpace)
|
||||
mock_get_proof.return_value = [uint64(1)] * 64, None
|
||||
yield
|
||||
|
||||
|
||||
def assert_farming_info_sent(mock_peer: MagicMock) -> None:
|
||||
|
||||
@@ -12,57 +12,6 @@ from chia.plotting.prover import PlotVersion, V1Prover, V2Prover, get_prover_fro
|
||||
|
||||
|
||||
class TestProver:
|
||||
def test_v2_prover_init_with_nonexistent_file(self) -> None:
|
||||
prover = V2Prover("/nonexistent/path/test.plot2")
|
||||
assert prover.get_version() == PlotVersion.V2
|
||||
assert prover.get_filename() == "/nonexistent/path/test.plot2"
|
||||
|
||||
def test_v2_prover_get_size_raises_error(self) -> None:
|
||||
prover = V2Prover("/nonexistent/path/test.plot2")
|
||||
with pytest.raises(NotImplementedError, match="V2 plot format is not yet implemented"):
|
||||
prover.get_size()
|
||||
|
||||
def test_v2_prover_get_memo_raises_error(self) -> None:
|
||||
prover = V2Prover("/nonexistent/path/test.plot2")
|
||||
with pytest.raises(NotImplementedError, match="V2 plot format is not yet implemented"):
|
||||
prover.get_memo()
|
||||
|
||||
def test_v2_prover_get_compression_level(self) -> None:
|
||||
prover = V2Prover("/nonexistent/path/test.plot2")
|
||||
assert prover.get_compression_level() == uint8(0)
|
||||
|
||||
def test_v2_prover_get_id_raises_error(self) -> None:
|
||||
prover = V2Prover("/nonexistent/path/test.plot2")
|
||||
with pytest.raises(NotImplementedError, match="V2 plot format is not yet implemented"):
|
||||
prover.get_id()
|
||||
|
||||
def test_v2_prover_get_qualities_for_challenge_raises_error(self) -> None:
|
||||
prover = V2Prover("/nonexistent/path/test.plot2")
|
||||
with pytest.raises(
|
||||
AssertionError, match="V2 plot format does not support qualities directly, use partial proofs"
|
||||
):
|
||||
prover.get_qualities_for_challenge(bytes32(b"1" * 32))
|
||||
|
||||
def test_v2_prover_get_full_proof_raises_error(self) -> None:
|
||||
prover = V2Prover("/nonexistent/path/test.plot2")
|
||||
with pytest.raises(AssertionError, match="V2 plot format require solver to get full proof"):
|
||||
prover.get_full_proof(bytes32(b"1" * 32), 0)
|
||||
|
||||
def test_v2_prover_bytes_raises_error(self) -> None:
|
||||
prover = V2Prover("/nonexistent/path/test.plot2")
|
||||
with pytest.raises(NotImplementedError, match="V2 plot format is not yet implemented"):
|
||||
bytes(prover)
|
||||
|
||||
def test_v2_prover_from_bytes_raises_error(self) -> None:
|
||||
with pytest.raises(NotImplementedError, match="V2 plot format is not yet implemented"):
|
||||
V2Prover.from_bytes(b"test_data")
|
||||
|
||||
def test_get_prover_from_file(self) -> None:
|
||||
prover = get_prover_from_file("/nonexistent/path/test.plot2")
|
||||
assert prover.get_version() == PlotVersion.V2
|
||||
with pytest.raises(NotImplementedError, match="V2 plot format is not yet implemented"):
|
||||
prover.get_size()
|
||||
|
||||
def test_get_prover_from_file_with_plot1_still_works(self) -> None:
|
||||
with tempfile.NamedTemporaryFile(suffix=".plot", delete=False) as f:
|
||||
temp_path = f.name
|
||||
@@ -78,6 +27,56 @@ class TestProver:
|
||||
get_prover_from_file("/nonexistent/path/test.txt")
|
||||
|
||||
|
||||
# TODO: todo_v2_plots enable these tests once we have test plots we can load
|
||||
@pytest.mark.skip("we don't have v2 test plots yet")
|
||||
class TestV2Prover:
|
||||
def test_v2_prover_init_with_nonexistent_file(self) -> None:
|
||||
prover = V2Prover.from_filename("/nonexistent/path/test.plot2")
|
||||
assert prover.get_version() == PlotVersion.V2
|
||||
assert prover.get_filename() == "/nonexistent/path/test.plot2"
|
||||
|
||||
def test_v2_prover_get_size_raises_error(self) -> None:
|
||||
prover = V2Prover.from_filename("/nonexistent/path/test.plot2")
|
||||
with pytest.raises(NotImplementedError, match="V2 plot format is not yet implemented"):
|
||||
prover.get_size()
|
||||
|
||||
def test_v2_prover_get_memo_raises_error(self) -> None:
|
||||
prover = V2Prover.from_filename("/nonexistent/path/test.plot2")
|
||||
with pytest.raises(NotImplementedError, match="V2 plot format is not yet implemented"):
|
||||
prover.get_memo()
|
||||
|
||||
def test_v2_prover_get_compression_level(self) -> None:
|
||||
prover = V2Prover.from_filename("/nonexistent/path/test.plot2")
|
||||
assert prover.get_compression_level() == uint8(0)
|
||||
|
||||
def test_v2_prover_get_id_raises_error(self) -> None:
|
||||
prover = V2Prover.from_filename("/nonexistent/path/test.plot2")
|
||||
with pytest.raises(NotImplementedError, match="V2 plot format is not yet implemented"):
|
||||
prover.get_id()
|
||||
|
||||
def test_v2_prover_get_qualities_for_challenge_raises_error(self) -> None:
|
||||
prover = V2Prover.from_filename("/nonexistent/path/test.plot2")
|
||||
with pytest.raises(
|
||||
AssertionError, match="V2 plot format does not support qualities directly, use partial proofs"
|
||||
):
|
||||
prover.get_qualities_for_challenge(bytes32(b"1" * 32), uint8(5))
|
||||
|
||||
def test_v2_prover_bytes_raises_error(self) -> None:
|
||||
prover = V2Prover.from_filename("/nonexistent/path/test.plot2")
|
||||
with pytest.raises(NotImplementedError, match="V2 plot format is not yet implemented"):
|
||||
bytes(prover)
|
||||
|
||||
def test_v2_prover_from_bytes_raises_error(self) -> None:
|
||||
with pytest.raises(NotImplementedError, match="V2 plot format is not yet implemented"):
|
||||
V2Prover.from_bytes(b"test_data")
|
||||
|
||||
def test_get_prover_from_file(self) -> None:
|
||||
prover = get_prover_from_file("/nonexistent/path/test.plot2")
|
||||
assert prover.get_version() == PlotVersion.V2
|
||||
with pytest.raises(NotImplementedError, match="V2 plot format is not yet implemented"):
|
||||
prover.get_size()
|
||||
|
||||
|
||||
class TestV1Prover:
|
||||
def test_v1_prover_get_version(self) -> None:
|
||||
"""Test that V1Prover.get_version() returns PlotVersion.V1"""
|
||||
@@ -87,13 +86,6 @@ class TestV1Prover:
|
||||
|
||||
|
||||
class TestGetProverFromBytes:
|
||||
def test_get_prover_from_bytes_v2_plot(self) -> None:
|
||||
with patch("chia.plotting.prover.V2Prover.from_bytes") as mock_v2_from_bytes:
|
||||
mock_prover = MagicMock()
|
||||
mock_v2_from_bytes.return_value = mock_prover
|
||||
result = get_prover_from_bytes("test.plot2", b"test_data")
|
||||
assert result == mock_prover
|
||||
|
||||
def test_get_prover_from_bytes_v1_plot(self) -> None:
|
||||
with patch("chia.plotting.prover.DiskProver") as mock_disk_prover_class:
|
||||
mock_disk_prover = MagicMock()
|
||||
@@ -102,5 +94,5 @@ class TestGetProverFromBytes:
|
||||
assert isinstance(result, V1Prover)
|
||||
|
||||
def test_get_prover_from_bytes_unsupported_extension(self) -> None:
|
||||
with pytest.raises(ValueError, match="Unsupported plot file"):
|
||||
with pytest.raises((RuntimeError, ValueError)):
|
||||
get_prover_from_bytes("test.txt", b"test_data")
|
||||
|
||||
@@ -5,6 +5,8 @@ from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
from chia_rs import ConsensusConstants
|
||||
from chia_rs.sized_bytes import bytes32
|
||||
from chia_rs.sized_ints import uint8, uint64
|
||||
|
||||
from chia.protocols.outbound_message import Message
|
||||
from chia.protocols.solver_protocol import SolverInfo
|
||||
@@ -21,7 +23,12 @@ async def test_solver_api_methods(blockchain_constants: ConsensusConstants, tmp_
|
||||
solver = solver_service._node
|
||||
solver_api = solver_service._api
|
||||
assert solver_api.ready() is True
|
||||
test_info = SolverInfo(partial_proof=b"test_partial_proof_42")
|
||||
test_info = SolverInfo(
|
||||
partial_proof=[uint64(1), uint64(2), uint64(3), uint64(4)],
|
||||
plot_id=bytes32.fromhex("abababababababababababababababababababababababababababababababab"),
|
||||
strength=uint8(5),
|
||||
size=uint8(28),
|
||||
)
|
||||
expected_proof = b"test_proof_data_12345"
|
||||
with patch.object(solver, "solve", return_value=expected_proof):
|
||||
api_result = await solver_api.solve(test_info)
|
||||
|
||||
@@ -155,9 +155,11 @@ partial_proof = harvester_protocol.PartialProofsData(
|
||||
bytes32.fromhex("42743566108589c11bb3811b347900b6351fd3e25bad6c956c0bf1c05a4d93fb"),
|
||||
bytes32.fromhex("8a346e8dc02e9b44c0571caa74fd99f163d4c5d7deaedac87125528721493f7a"),
|
||||
"plot-filename",
|
||||
[b"partial-proof1", b"partial-proof2"],
|
||||
[[uint64(1), uint64(2), uint64(3), uint64(4)], [uint64(2), uint64(3), uint64(4), uint64(5)]],
|
||||
uint8(4),
|
||||
uint8(32),
|
||||
uint8(5),
|
||||
bytes32.fromhex("346e8dc02e9b44c0571caa74fd99f163d4c5d7deaedac87125528721493f7a8a"),
|
||||
G1Element.from_bytes(
|
||||
bytes.fromhex(
|
||||
"a04c6b5ac7dfb935f6feecfdd72348ccf1d4be4fe7e26acf271ea3b7d308da61e0a308f7a62495328a81f5147b66634c"
|
||||
@@ -1116,6 +1118,11 @@ respond_compact_proof_of_time = timelord_protocol.RespondCompactProofOfTime(
|
||||
)
|
||||
|
||||
# SOLVER PROTOCOL
|
||||
solver_info = solver_protocol.SolverInfo(partial_proof=b"partial-proof")
|
||||
solver_info = solver_protocol.SolverInfo(
|
||||
partial_proof=[uint64(1), uint64(2), uint64(3), uint64(4)],
|
||||
plot_id=bytes32.fromhex("071bef40d098cfadc2614d8b57db924788f7f2ea0fde8cf4bfaeae2894caa442"),
|
||||
strength=uint8(5),
|
||||
size=uint8(28),
|
||||
)
|
||||
|
||||
solver_response = solver_protocol.SolverResponse(b"partial-proof", b"full-proof")
|
||||
solver_response = solver_protocol.SolverResponse([uint64(1), uint64(2), uint64(3), uint64(4)], b"full-proof")
|
||||
|
||||
Binary file not shown.
@@ -69,9 +69,11 @@ partial_proof_json: dict[str, Any] = {
|
||||
"challenge_hash": "0x42743566108589c11bb3811b347900b6351fd3e25bad6c956c0bf1c05a4d93fb",
|
||||
"sp_hash": "0x8a346e8dc02e9b44c0571caa74fd99f163d4c5d7deaedac87125528721493f7a",
|
||||
"plot_identifier": "plot-filename",
|
||||
"partial_proofs": ["0x7061727469616c2d70726f6f6631", "0x7061727469616c2d70726f6f6632"],
|
||||
"partial_proofs": [[1, 2, 3, 4], [2, 3, 4, 5]],
|
||||
"signage_point_index": 4,
|
||||
"plot_size": 32,
|
||||
"strength": 5,
|
||||
"plot_id": "0x346e8dc02e9b44c0571caa74fd99f163d4c5d7deaedac87125528721493f7a8a",
|
||||
"pool_public_key": "0xa04c6b5ac7dfb935f6feecfdd72348ccf1d4be4fe7e26acf271ea3b7d308da61e0a308f7a62495328a81f5147b66634c",
|
||||
"pool_contract_puzzle_hash": "0x91240fbacdf93b44c0571caa74fd99f163d4c5d7deaedac87125528721493f7a",
|
||||
"plot_public_key": "0xa04c6b5ac7dfb935f6feecfdd72348ccf1d4be4fe7e26acf271ea3b7d308da61e0a308f7a62495328a81f5147b66634c",
|
||||
@@ -2730,9 +2732,11 @@ error_without_data_json: dict[str, Any] = {"code": 1, "message": "Unknown", "dat
|
||||
|
||||
error_with_data_json: dict[str, Any] = {"code": 1, "message": "Unknown", "data": "0x65787472612064617461"}
|
||||
|
||||
solver_info_json: dict[str, Any] = {"partial_proof": "0x7061727469616c2d70726f6f66"}
|
||||
|
||||
solver_response_json: dict[str, Any] = {
|
||||
"partial_proof": "0x7061727469616c2d70726f6f66",
|
||||
"proof": "0x66756c6c2d70726f6f66",
|
||||
solver_info_json: dict[str, Any] = {
|
||||
"partial_proof": [1, 2, 3, 4],
|
||||
"plot_id": "0x071bef40d098cfadc2614d8b57db924788f7f2ea0fde8cf4bfaeae2894caa442",
|
||||
"strength": 5,
|
||||
"size": 28,
|
||||
}
|
||||
|
||||
solver_response_json: dict[str, Any] = {"partial_proof": [1, 2, 3, 4], "proof": "0x66756c6c2d70726f6f66"}
|
||||
|
||||
@@ -56,7 +56,6 @@ test_constants = ConsensusConstants(
|
||||
BLOCKS_CACHE_SIZE=uint32(4608 + (128 * 4)),
|
||||
WEIGHT_PROOF_RECENT_BLOCKS=uint32(1000),
|
||||
MAX_BLOCK_COUNT_PER_REQUESTS=uint32(32),
|
||||
MAX_GENERATOR_SIZE=uint32(1000000),
|
||||
MAX_GENERATOR_REF_LIST_SIZE=uint32(512),
|
||||
POOL_SUB_SLOT_ITERS=uint64(37600000000),
|
||||
HARD_FORK_HEIGHT=uint32(5496000),
|
||||
@@ -66,11 +65,10 @@ test_constants = ConsensusConstants(
|
||||
PLOT_FILTER_64_HEIGHT=uint32(15592000),
|
||||
PLOT_FILTER_32_HEIGHT=uint32(20643000),
|
||||
PLOT_STRENGTH_INITIAL=uint8(2),
|
||||
PLOT_STRENGTH_4_HEIGHT=uint32(0xFFFFFFFF),
|
||||
PLOT_STRENGTH_5_HEIGHT=uint32(0xFFFFFFFF),
|
||||
PLOT_STRENGTH_6_HEIGHT=uint32(0xFFFFFFFF),
|
||||
PLOT_STRENGTH_7_HEIGHT=uint32(0xFFFFFFFF),
|
||||
PLOT_STRENGTH_8_HEIGHT=uint32(0xFFFFFFFF),
|
||||
QUALITY_PROOF_SCAN_FILTER=uint8(5),
|
||||
PLOT_FILTER_V2_FIRST_ADJUSTMENT_HEIGHT=uint32(0xFFFFFFFA),
|
||||
PLOT_FILTER_V2_SECOND_ADJUSTMENT_HEIGHT=uint32(0xFFFFFFFB),
|
||||
PLOT_FILTER_V2_THIRD_ADJUSTMENT_HEIGHT=uint32(0xFFFFFFFC),
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -76,11 +76,11 @@ DEFAULT_CONSTANTS = ConsensusConstants(
|
||||
# inclusive, so the max allowed range of 32 is a request for 33 blocks
|
||||
# (which is allowed)
|
||||
MAX_BLOCK_COUNT_PER_REQUESTS=uint32(32),
|
||||
MAX_GENERATOR_SIZE=uint32(1000000),
|
||||
MAX_GENERATOR_REF_LIST_SIZE=uint32(512), # Number of references allowed in the block generator ref list
|
||||
POOL_SUB_SLOT_ITERS=uint64(37600000000), # iters limit * NUM_SPS
|
||||
# June 2024
|
||||
HARD_FORK_HEIGHT=uint32(5496000),
|
||||
# TODO: todo_v2_plots finalize fork height
|
||||
HARD_FORK2_HEIGHT=uint32(0xFFFFFFFA),
|
||||
# starting at the hard fork 2 height, v1 plots will gradually be phased out,
|
||||
# and stop working entirely after this many blocks
|
||||
@@ -92,11 +92,11 @@ DEFAULT_CONSTANTS = ConsensusConstants(
|
||||
# June 2033
|
||||
PLOT_FILTER_32_HEIGHT=uint32(20643000),
|
||||
PLOT_STRENGTH_INITIAL=uint8(2),
|
||||
PLOT_STRENGTH_4_HEIGHT=uint32(0xFFFFFFFB),
|
||||
PLOT_STRENGTH_5_HEIGHT=uint32(0xFFFFFFFC),
|
||||
PLOT_STRENGTH_6_HEIGHT=uint32(0xFFFFFFFD),
|
||||
PLOT_STRENGTH_7_HEIGHT=uint32(0xFFFFFFFE),
|
||||
PLOT_STRENGTH_8_HEIGHT=uint32(0xFFFFFFFF),
|
||||
QUALITY_PROOF_SCAN_FILTER=uint8(5),
|
||||
# TODO: todo_v2_plots finalize plot filter schedule
|
||||
PLOT_FILTER_V2_FIRST_ADJUSTMENT_HEIGHT=uint32(0xFFFFFFFB),
|
||||
PLOT_FILTER_V2_SECOND_ADJUSTMENT_HEIGHT=uint32(0xFFFFFFFC),
|
||||
PLOT_FILTER_V2_THIRD_ADJUSTMENT_HEIGHT=uint32(0xFFFFFFFD),
|
||||
)
|
||||
|
||||
|
||||
|
||||
+17
-14
@@ -507,11 +507,17 @@ class FarmerAPI:
|
||||
|
||||
# Process each partial proof chain through solver service to get full proofs
|
||||
for partial_proof in partial_proof_data.partial_proofs:
|
||||
solver_info = SolverInfo(partial_proof=partial_proof)
|
||||
solver_info = SolverInfo(
|
||||
partial_proof=partial_proof,
|
||||
plot_id=partial_proof_data.plot_id,
|
||||
strength=partial_proof_data.strength,
|
||||
size=partial_proof_data.plot_size,
|
||||
)
|
||||
|
||||
key = bytes(partial_proof)
|
||||
try:
|
||||
# store pending request data for matching with response
|
||||
self.farmer.pending_solver_requests[partial_proof] = {
|
||||
self.farmer.pending_solver_requests[key] = {
|
||||
"proof_data": partial_proof_data,
|
||||
"peer": peer,
|
||||
}
|
||||
@@ -519,15 +525,13 @@ class FarmerAPI:
|
||||
# send solve request to all solver connections
|
||||
msg = make_msg(ProtocolMessageTypes.solve, solver_info)
|
||||
await self.farmer.server.send_to_all([msg], NodeType.SOLVER)
|
||||
self.farmer.log.debug(f"Sent solve request for partial proof {partial_proof.hex()[:10]}...")
|
||||
self.farmer.log.debug(f"Sent solve request for partial proof {partial_proof[:5]}...")
|
||||
|
||||
except Exception as e:
|
||||
self.farmer.log.error(
|
||||
f"Failed to call solver service for partial proof {partial_proof.hex()[:10]}...: {e}"
|
||||
)
|
||||
self.farmer.log.error(f"Failed to call solver service for partial proof {partial_proof[:5]}...: {e}")
|
||||
# clean up pending request
|
||||
if partial_proof in self.farmer.pending_solver_requests:
|
||||
del self.farmer.pending_solver_requests[partial_proof]
|
||||
if key in self.farmer.pending_solver_requests:
|
||||
del self.farmer.pending_solver_requests[key]
|
||||
|
||||
@metadata.request()
|
||||
async def solution_response(self, response: SolverResponse, peer: WSChiaConnection) -> None:
|
||||
@@ -539,14 +543,13 @@ class FarmerAPI:
|
||||
|
||||
# find the matching pending request using partial_proof
|
||||
|
||||
if response.partial_proof not in self.farmer.pending_solver_requests:
|
||||
self.farmer.log.warning(
|
||||
f"Received solver response for unknown partial proof {response.partial_proof.hex()}"
|
||||
)
|
||||
key = bytes(response.partial_proof)
|
||||
if key not in self.farmer.pending_solver_requests:
|
||||
self.farmer.log.warning(f"Received solver response for unknown partial proof {response.partial_proof[:5]}")
|
||||
return
|
||||
|
||||
# get the original request data
|
||||
request_data = self.farmer.pending_solver_requests.pop(response.partial_proof)
|
||||
request_data = self.farmer.pending_solver_requests.pop(key)
|
||||
proof_data = request_data["proof_data"]
|
||||
original_peer = request_data["peer"]
|
||||
partial_proof = response.partial_proof
|
||||
@@ -554,7 +557,7 @@ class FarmerAPI:
|
||||
# create the proof of space with the solver's proof
|
||||
proof_bytes = response.proof
|
||||
if proof_bytes is None or len(proof_bytes) == 0:
|
||||
self.farmer.log.warning(f"Received empty proof from solver for proof {partial_proof.hex()}...")
|
||||
self.farmer.log.warning(f"Received empty proof from solver for proof {partial_proof[:5]}...")
|
||||
return
|
||||
|
||||
sp_challenge_hash = proof_data.challenge_hash
|
||||
|
||||
@@ -16,7 +16,7 @@ from chia.consensus.pot_iterations import (
|
||||
calculate_sp_interval_iters,
|
||||
)
|
||||
from chia.harvester.harvester import Harvester
|
||||
from chia.plotting.prover import PlotVersion
|
||||
from chia.plotting.prover import PlotVersion, V1Prover, V2Prover, V2Quality
|
||||
from chia.plotting.util import PlotInfo, parse_plot_info
|
||||
from chia.protocols import harvester_protocol
|
||||
from chia.protocols.farmer_protocol import FarmingInfo
|
||||
@@ -28,11 +28,9 @@ from chia.server.ws_connection import WSChiaConnection
|
||||
from chia.types.blockchain_format.proof_of_space import (
|
||||
calculate_pos_challenge,
|
||||
calculate_prefix_bits,
|
||||
calculate_required_plot_strength,
|
||||
generate_plot_public_key,
|
||||
make_pos,
|
||||
passes_plot_filter,
|
||||
quality_for_partial_proof,
|
||||
)
|
||||
from chia.wallet.derive_keys import master_sk_to_local_sk
|
||||
|
||||
@@ -153,10 +151,6 @@ class HarvesterAPI:
|
||||
start = time.monotonic()
|
||||
assert len(new_challenge.challenge_hash) == 32
|
||||
|
||||
required_plot_strength = calculate_required_plot_strength(
|
||||
self.harvester.constants, new_challenge.last_tx_height
|
||||
)
|
||||
|
||||
loop = asyncio.get_running_loop()
|
||||
|
||||
def blocking_lookup_v2_partial_proofs(filename: Path, plot_info: PlotInfo) -> Optional[PartialProofsData]:
|
||||
@@ -168,12 +162,12 @@ class HarvesterAPI:
|
||||
new_challenge.challenge_hash,
|
||||
new_challenge.sp_hash,
|
||||
)
|
||||
partial_proofs = plot_info.prover.get_partial_proofs_for_challenge(
|
||||
sp_challenge_hash, required_plot_strength
|
||||
qualities = plot_info.prover.get_qualities_for_challenge(
|
||||
sp_challenge_hash, self.harvester.constants.QUALITY_PROOF_SCAN_FILTER
|
||||
)
|
||||
|
||||
# If no partial proofs are found, return None
|
||||
if len(partial_proofs) == 0:
|
||||
if len(qualities) == 0:
|
||||
return None
|
||||
|
||||
# Get the appropriate difficulty for this plot
|
||||
@@ -191,11 +185,10 @@ class HarvesterAPI:
|
||||
good_partial_proofs = []
|
||||
sp_interval_iters = calculate_sp_interval_iters(self.harvester.constants, sub_slot_iters)
|
||||
|
||||
for partial_proof in partial_proofs:
|
||||
quality_str = quality_for_partial_proof(partial_proof, new_challenge.challenge_hash)
|
||||
for quality in qualities:
|
||||
required_iters: uint64 = calculate_iterations_quality(
|
||||
self.harvester.constants,
|
||||
quality_str,
|
||||
quality.get_string(),
|
||||
plot_info.prover.get_size(),
|
||||
difficulty,
|
||||
new_challenge.sp_hash,
|
||||
@@ -203,8 +196,14 @@ class HarvesterAPI:
|
||||
new_challenge.last_tx_height,
|
||||
)
|
||||
|
||||
if required_iters < sp_interval_iters:
|
||||
good_partial_proofs.append(partial_proof)
|
||||
if required_iters >= sp_interval_iters:
|
||||
continue
|
||||
|
||||
assert isinstance(plot_info.prover, V2Prover)
|
||||
assert isinstance(quality, V2Quality)
|
||||
|
||||
partial_proof = plot_info.prover.get_partial_proof(quality)
|
||||
good_partial_proofs.append(partial_proof)
|
||||
|
||||
if len(good_partial_proofs) == 0:
|
||||
return None
|
||||
@@ -214,10 +213,12 @@ class HarvesterAPI:
|
||||
return PartialProofsData(
|
||||
new_challenge.challenge_hash,
|
||||
new_challenge.sp_hash,
|
||||
good_partial_proofs[0].hex() + str(filename.resolve()),
|
||||
str(filename.resolve()),
|
||||
good_partial_proofs,
|
||||
new_challenge.signage_point_index,
|
||||
size,
|
||||
plot_info.prover.get_strength(),
|
||||
plot_id,
|
||||
plot_info.pool_public_key,
|
||||
plot_info.pool_contract_puzzle_hash,
|
||||
plot_info.plot_public_key,
|
||||
@@ -238,7 +239,9 @@ class HarvesterAPI:
|
||||
new_challenge.sp_hash,
|
||||
)
|
||||
try:
|
||||
quality_strings = plot_info.prover.get_qualities_for_challenge(sp_challenge_hash)
|
||||
qualities = plot_info.prover.get_qualities_for_challenge(
|
||||
sp_challenge_hash, self.harvester.constants.QUALITY_PROOF_SCAN_FILTER
|
||||
)
|
||||
except RuntimeError as e:
|
||||
if str(e) == "Timeout waiting for context queue.":
|
||||
self.harvester.log.warning(
|
||||
@@ -264,7 +267,7 @@ class HarvesterAPI:
|
||||
return []
|
||||
|
||||
responses: list[tuple[bytes32, ProofOfSpace]] = []
|
||||
if quality_strings is not None:
|
||||
if len(qualities) > 0:
|
||||
difficulty = new_challenge.difficulty
|
||||
sub_slot_iters = new_challenge.sub_slot_iters
|
||||
if plot_info.pool_contract_puzzle_hash is not None:
|
||||
@@ -277,10 +280,10 @@ class HarvesterAPI:
|
||||
sub_slot_iters = pool_difficulty.sub_slot_iters
|
||||
|
||||
# Found proofs of space (on average 1 is expected per plot)
|
||||
for index, quality_str in enumerate(quality_strings):
|
||||
for index, quality in enumerate(qualities):
|
||||
required_iters: uint64 = calculate_iterations_quality(
|
||||
self.harvester.constants,
|
||||
quality_str,
|
||||
quality.get_string(),
|
||||
plot_info.prover.get_size(),
|
||||
difficulty,
|
||||
new_challenge.sp_hash,
|
||||
@@ -292,6 +295,7 @@ class HarvesterAPI:
|
||||
# Found a very good proof of space! will fetch the whole proof from disk,
|
||||
# then send to farmer
|
||||
try:
|
||||
assert isinstance(plot_info.prover, V1Prover)
|
||||
proof_xs = plot_info.prover.get_full_proof(
|
||||
sp_challenge_hash, index, self.harvester.parallel_read
|
||||
)
|
||||
@@ -327,6 +331,7 @@ class HarvesterAPI:
|
||||
)
|
||||
continue
|
||||
|
||||
quality_str = bytes32(quality.get_string())
|
||||
responses.append(
|
||||
(
|
||||
quality_str,
|
||||
|
||||
@@ -7,16 +7,15 @@ from collections.abc import Sequence
|
||||
from pathlib import Path
|
||||
from threading import Lock
|
||||
from time import monotonic, sleep
|
||||
from typing import Optional, Union
|
||||
from typing import Optional
|
||||
|
||||
from chia_rs import G1Element
|
||||
from chia_rs.sized_bytes import bytes32
|
||||
from chia_rs import G1Element, solve_proof
|
||||
from chia_rs.sized_ints import uint8, uint32
|
||||
from chiapos import Verifier
|
||||
|
||||
from chia.consensus.default_constants import DEFAULT_CONSTANTS
|
||||
from chia.plotting.manager import PlotManager
|
||||
from chia.plotting.prover import PlotVersion
|
||||
from chia.plotting.prover import QualityProtocol, V1Prover, V2Prover, V2Quality
|
||||
from chia.plotting.util import (
|
||||
PlotInfo,
|
||||
PlotRefreshEvents,
|
||||
@@ -26,10 +25,6 @@ from chia.plotting.util import (
|
||||
get_plot_filenames,
|
||||
parse_plot_info,
|
||||
)
|
||||
from chia.types.blockchain_format.proof_of_space import (
|
||||
quality_for_partial_proof,
|
||||
solve_proof,
|
||||
)
|
||||
from chia.util.bech32m import encode_puzzle_hash
|
||||
from chia.util.config import load_config
|
||||
from chia.util.cpu import available_logical_cores
|
||||
@@ -176,18 +171,13 @@ def check_plots(
|
||||
|
||||
total_proofs = 0
|
||||
caught_exception: bool = False
|
||||
version = pr.get_version()
|
||||
for i in range(num_start, num_end):
|
||||
challenge = std_hash(i.to_bytes(32, "big"))
|
||||
# these are either qualities (v1) or partial proofs (v2)
|
||||
proofs: Sequence[Union[bytes32, bytes]]
|
||||
qualities: Sequence[QualityProtocol]
|
||||
# Some plot errors cause get_qualities_for_challenge to throw a RuntimeError
|
||||
try:
|
||||
quality_start_time = round(monotonic() * 1000)
|
||||
if version == PlotVersion.V1:
|
||||
proofs = pr.get_qualities_for_challenge(challenge)
|
||||
else:
|
||||
proofs = pr.get_partial_proofs_for_challenge(challenge, DEFAULT_CONSTANTS.PLOT_STRENGTH_INITIAL)
|
||||
qualities = pr.get_qualities_for_challenge(challenge, DEFAULT_CONSTANTS.PLOT_STRENGTH_INITIAL)
|
||||
quality_spent_time = round(monotonic() * 1000) - quality_start_time
|
||||
if quality_spent_time > 8000:
|
||||
log.warning(
|
||||
@@ -215,18 +205,22 @@ def check_plots(
|
||||
caught_exception = True
|
||||
break
|
||||
|
||||
for index, proof in enumerate(proofs):
|
||||
for index, quality in enumerate(qualities):
|
||||
# Other plot errors cause get_full_proof or validate_proof to throw an AssertionError
|
||||
try:
|
||||
proof_start_time = round(monotonic() * 1000)
|
||||
if version == PlotVersion.V1:
|
||||
quality_str = bytes32(proof)
|
||||
quality_str = quality.get_string()
|
||||
|
||||
if isinstance(pr, V1Prover):
|
||||
full_proof = pr.get_full_proof(challenge, index, parallel_read)
|
||||
proof_spent_time = round(monotonic() * 1000) - proof_start_time
|
||||
else:
|
||||
quality_str = quality_for_partial_proof(proof, challenge)
|
||||
elif isinstance(pr, V2Prover):
|
||||
assert isinstance(quality, V2Quality)
|
||||
partial_proof = pr.get_partial_proof(quality)
|
||||
proof_spent_time = round(monotonic() * 1000) - proof_start_time
|
||||
full_proof = solve_proof(proof)
|
||||
size = pr.get_size().size_v2
|
||||
assert size is not None
|
||||
full_proof = solve_proof(partial_proof, pr.get_id(), pr.get_strength(), size)
|
||||
|
||||
if proof_spent_time > 15000:
|
||||
log.warning(
|
||||
|
||||
+56
-39
@@ -1,11 +1,12 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from enum import IntEnum
|
||||
from typing import TYPE_CHECKING, ClassVar, Protocol, cast
|
||||
|
||||
from chia_rs import PlotSize
|
||||
from chia_rs import PlotSize, Prover, QualityProof
|
||||
from chia_rs.sized_bytes import bytes32
|
||||
from chia_rs.sized_ints import uint8
|
||||
from chia_rs.sized_ints import uint8, uint64
|
||||
from chiapos import DiskProver
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -19,46 +20,65 @@ class PlotVersion(IntEnum):
|
||||
V2 = 2
|
||||
|
||||
|
||||
class QualityProtocol(Protocol):
|
||||
def get_string(self) -> bytes32: ...
|
||||
|
||||
|
||||
class ProverProtocol(Protocol):
|
||||
def get_filename(self) -> str: ...
|
||||
def get_size(self) -> PlotSize: ...
|
||||
def get_strength(self) -> uint8: ...
|
||||
def get_memo(self) -> bytes: ...
|
||||
def get_compression_level(self) -> uint8: ...
|
||||
def get_version(self) -> PlotVersion: ...
|
||||
def __bytes__(self) -> bytes: ...
|
||||
def get_id(self) -> bytes32: ...
|
||||
def get_qualities_for_challenge(self, challenge: bytes32) -> list[bytes32]: ...
|
||||
|
||||
# this is only supported by v2 plots
|
||||
def get_partial_proofs_for_challenge(self, challenge: bytes32, required_plot_strength: uint8) -> list[bytes]: ...
|
||||
|
||||
# this is only supported by v1 plots. v2 plots first get the partial proof
|
||||
# and turn it into a full proof by calling solve_proof(), or pass it to the solver service
|
||||
def get_full_proof(self, challenge: bytes32, index: int, parallel_read: bool = True) -> bytes: ...
|
||||
def get_qualities_for_challenge(
|
||||
self, challenge: bytes32, proof_fragment_filter: uint8
|
||||
) -> list[QualityProtocol]: ...
|
||||
|
||||
@classmethod
|
||||
def from_bytes(cls, data: bytes) -> ProverProtocol: ...
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class V2Quality(QualityProtocol):
|
||||
_quality_proof: QualityProof
|
||||
|
||||
def get_string(self) -> bytes32:
|
||||
return self._quality_proof.serialize()
|
||||
|
||||
|
||||
class V2Prover:
|
||||
"""Placeholder for future V2 plot format support"""
|
||||
|
||||
_prover: Prover
|
||||
|
||||
if TYPE_CHECKING:
|
||||
_protocol_check: ClassVar[ProverProtocol] = cast("V2Prover", None)
|
||||
|
||||
def __init__(self, filename: str):
|
||||
self._filename = filename
|
||||
@classmethod
|
||||
def from_filename(cls, path: str) -> V2Prover:
|
||||
return V2Prover(Prover(path))
|
||||
|
||||
@classmethod
|
||||
def from_bytes(cls, data: bytes) -> V2Prover:
|
||||
return V2Prover(Prover.from_bytes(data))
|
||||
|
||||
def __init__(self, prover: Prover):
|
||||
self._prover = prover
|
||||
|
||||
def get_filename(self) -> str:
|
||||
return str(self._filename)
|
||||
return self._prover.get_filename()
|
||||
|
||||
def get_size(self) -> PlotSize:
|
||||
# TODO: todo_v2_plots get k size from plot
|
||||
raise NotImplementedError("V2 plot format is not yet implemented")
|
||||
return PlotSize.make_v2(self._prover.size())
|
||||
|
||||
def get_strength(self) -> uint8:
|
||||
return uint8(self._prover.get_strength())
|
||||
|
||||
def get_memo(self) -> bytes:
|
||||
# TODO: todo_v2_plots
|
||||
raise NotImplementedError("V2 plot format is not yet implemented")
|
||||
return self._prover.get_memo()
|
||||
|
||||
def get_compression_level(self) -> uint8:
|
||||
# v2 plots are never compressed
|
||||
@@ -68,27 +88,24 @@ class V2Prover:
|
||||
return PlotVersion.V2
|
||||
|
||||
def __bytes__(self) -> bytes:
|
||||
# TODO: todo_v2_plots Implement prover serialization for caching
|
||||
raise NotImplementedError("V2 plot format is not yet implemented")
|
||||
return self._prover.to_bytes()
|
||||
|
||||
def get_id(self) -> bytes32:
|
||||
# TODO: Extract plot ID from V2 plot file
|
||||
raise NotImplementedError("V2 plot format is not yet implemented")
|
||||
return self._prover.plot_id()
|
||||
|
||||
def get_qualities_for_challenge(self, challenge: bytes32) -> list[bytes32]:
|
||||
raise AssertionError("V2 plot format does not support qualities directly, use partial proofs")
|
||||
def get_qualities_for_challenge(self, challenge: bytes32, proof_fragment_filter: uint8) -> list[QualityProtocol]:
|
||||
return [V2Quality(q) for q in self._prover.get_qualities_for_challenge(challenge, proof_fragment_filter)]
|
||||
|
||||
def get_partial_proofs_for_challenge(self, challenge: bytes, required_plot_strength: uint8) -> list[bytes]:
|
||||
# TODO: todo_v2_plots Implement plot partial proof lookup
|
||||
raise NotImplementedError("V2 plot format is not yet implemented")
|
||||
def get_partial_proof(self, quality: V2Quality) -> list[uint64]:
|
||||
return self._prover.get_partial_proof(quality._quality_proof)[0]
|
||||
|
||||
def get_full_proof(self, challenge: bytes32, index: int, parallel_read: bool = True) -> bytes:
|
||||
raise AssertionError("V2 plot format require solver to get full proof")
|
||||
|
||||
@classmethod
|
||||
def from_bytes(cls, data: bytes) -> V2Prover:
|
||||
# TODO: todo_v2_plots Implement prover deserialization from cache
|
||||
raise NotImplementedError("V2 plot format is not yet implemented")
|
||||
@dataclass(frozen=True)
|
||||
class V1Quality(QualityProtocol):
|
||||
_quality: bytes32
|
||||
|
||||
def get_string(self) -> bytes32:
|
||||
return self._quality
|
||||
|
||||
|
||||
class V1Prover:
|
||||
@@ -106,6 +123,9 @@ class V1Prover:
|
||||
def get_size(self) -> PlotSize:
|
||||
return PlotSize.make_v1(uint8(self._disk_prover.get_size()))
|
||||
|
||||
def get_strength(self) -> uint8:
|
||||
raise AssertionError("V1 plot format doesn't use strength")
|
||||
|
||||
def get_memo(self) -> bytes:
|
||||
return bytes(self._disk_prover.get_memo())
|
||||
|
||||
@@ -121,11 +141,8 @@ class V1Prover:
|
||||
def get_id(self) -> bytes32:
|
||||
return bytes32(self._disk_prover.get_id())
|
||||
|
||||
def get_qualities_for_challenge(self, challenge: bytes32) -> list[bytes32]:
|
||||
return [bytes32(quality) for quality in self._disk_prover.get_qualities_for_challenge(challenge)]
|
||||
|
||||
def get_partial_proofs_for_challenge(self, challenge: bytes32, required_plot_strength: uint8) -> list[bytes]:
|
||||
raise AssertionError("V1 plot format doesn't use partial proofs")
|
||||
def get_qualities_for_challenge(self, challenge: bytes32, proof_fragment_filter: uint8) -> list[QualityProtocol]:
|
||||
return [V1Quality(bytes32(quality)) for quality in self._disk_prover.get_qualities_for_challenge(challenge)]
|
||||
|
||||
def get_full_proof(self, challenge: bytes32, index: int, parallel_read: bool = True) -> bytes:
|
||||
return bytes(self._disk_prover.get_full_proof(challenge, index, parallel_read))
|
||||
@@ -137,7 +154,7 @@ class V1Prover:
|
||||
|
||||
def get_prover_from_bytes(filename: str, prover_data: bytes) -> ProverProtocol:
|
||||
if filename.endswith(".plot2"):
|
||||
return V2Prover.from_bytes(prover_data)
|
||||
return V2Prover(Prover.from_bytes(prover_data))
|
||||
elif filename.endswith(".plot"):
|
||||
return V1Prover(DiskProver.from_bytes(prover_data))
|
||||
else:
|
||||
@@ -146,7 +163,7 @@ def get_prover_from_bytes(filename: str, prover_data: bytes) -> ProverProtocol:
|
||||
|
||||
def get_prover_from_file(filename: str) -> ProverProtocol:
|
||||
if filename.endswith(".plot2"):
|
||||
return V2Prover(filename)
|
||||
return V2Prover(Prover(filename))
|
||||
elif filename.endswith(".plot"):
|
||||
return V1Prover(DiskProver(filename))
|
||||
else:
|
||||
|
||||
@@ -83,9 +83,11 @@ class PartialProofsData(Streamable):
|
||||
challenge_hash: bytes32
|
||||
sp_hash: bytes32
|
||||
plot_identifier: str
|
||||
partial_proofs: list[bytes] # 16 * k bits blobs instead of 32-byte quality strings
|
||||
partial_proofs: list[list[uint64]] # 16 * k bits blobs instead of 32-byte quality strings
|
||||
signage_point_index: uint8
|
||||
plot_size: uint8
|
||||
strength: uint8
|
||||
plot_id: bytes32
|
||||
pool_public_key: Optional[G1Element]
|
||||
pool_contract_puzzle_hash: Optional[bytes32]
|
||||
plot_public_key: G1Element
|
||||
|
||||
@@ -2,17 +2,23 @@ from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
|
||||
from chia_rs.sized_bytes import bytes32
|
||||
from chia_rs.sized_ints import uint8, uint64
|
||||
|
||||
from chia.util.streamable import Streamable, streamable
|
||||
|
||||
|
||||
@streamable
|
||||
@dataclass(frozen=True)
|
||||
class SolverInfo(Streamable):
|
||||
partial_proof: bytes # 16 * k bits blob, k (plot size) can be derived from this
|
||||
partial_proof: list[uint64] # 64 proof fragments
|
||||
plot_id: bytes32
|
||||
strength: uint8
|
||||
size: uint8 # k-size
|
||||
|
||||
|
||||
@streamable
|
||||
@dataclass(frozen=True)
|
||||
class SolverResponse(Streamable):
|
||||
partial_proof: bytes
|
||||
partial_proof: list[uint64]
|
||||
proof: bytes
|
||||
|
||||
@@ -14,7 +14,7 @@ from collections.abc import Sequence
|
||||
from dataclasses import dataclass, replace
|
||||
from pathlib import Path
|
||||
from random import Random
|
||||
from typing import Any, Callable, Optional, Union
|
||||
from typing import Any, Callable, Optional
|
||||
|
||||
import anyio
|
||||
from chia_puzzles_py.programs import CHIALISP_DESERIALISATION, ROM_BOOTSTRAP_GENERATOR
|
||||
@@ -37,6 +37,7 @@ from chia_rs import (
|
||||
SubSlotProofs,
|
||||
UnfinishedBlock,
|
||||
solution_generator,
|
||||
solve_proof,
|
||||
)
|
||||
from chia_rs.sized_bytes import bytes32
|
||||
from chia_rs.sized_ints import uint8, uint16, uint32, uint64, uint128
|
||||
@@ -64,7 +65,7 @@ from chia.daemon.keychain_proxy import KeychainProxy, connect_to_keychain_and_va
|
||||
from chia.full_node.bundle_tools import simple_solution_generator, simple_solution_generator_backrefs
|
||||
from chia.plotting.create_plots import PlotKeys, create_plots
|
||||
from chia.plotting.manager import PlotManager
|
||||
from chia.plotting.prover import PlotVersion
|
||||
from chia.plotting.prover import PlotVersion, QualityProtocol, V1Prover, V2Prover, V2Quality
|
||||
from chia.plotting.util import (
|
||||
Params,
|
||||
PlotRefreshEvents,
|
||||
@@ -92,13 +93,10 @@ from chia.types.blockchain_format.program import DEFAULT_FLAGS, INFINITE_COST, P
|
||||
from chia.types.blockchain_format.proof_of_space import (
|
||||
calculate_pos_challenge,
|
||||
calculate_prefix_bits,
|
||||
calculate_required_plot_strength,
|
||||
generate_plot_public_key,
|
||||
generate_taproot_sk,
|
||||
make_pos,
|
||||
passes_plot_filter,
|
||||
quality_for_partial_proof,
|
||||
solve_proof,
|
||||
)
|
||||
from chia.types.blockchain_format.serialized_program import SerializedProgram
|
||||
from chia.types.blockchain_format.vdf import VDFInfo, VDFProof
|
||||
@@ -1505,8 +1503,6 @@ class BlockTools:
|
||||
rng = random.Random()
|
||||
rng.seed(seed)
|
||||
|
||||
required_plot_strength = calculate_required_plot_strength(constants, prev_transaction_b_height)
|
||||
|
||||
for plot_info in self.plot_manager.plots.values():
|
||||
plot_id: bytes32 = plot_info.prover.get_id()
|
||||
if force_plot_id is not None and plot_id != force_plot_id:
|
||||
@@ -1515,32 +1511,28 @@ class BlockTools:
|
||||
if not passes_plot_filter(prefix_bits, plot_id, challenge_hash, signage_point):
|
||||
continue
|
||||
|
||||
# v2 plots aren't valid until after the hard fork
|
||||
if (
|
||||
prev_transaction_b_height < constants.HARD_FORK2_HEIGHT
|
||||
and plot_info.prover.get_version() == PlotVersion.V2
|
||||
):
|
||||
continue
|
||||
if plot_info.prover.get_version() == PlotVersion.V2:
|
||||
# v2 plots aren't valid until after the hard fork
|
||||
if prev_transaction_b_height < constants.HARD_FORK2_HEIGHT:
|
||||
continue
|
||||
|
||||
if plot_info.prover.get_strength() < constants.PLOT_STRENGTH_INITIAL:
|
||||
self.log.warn(
|
||||
f"Plot strength ({plot_info.prover.get_strength()}) too low, "
|
||||
f"cannot be used for farming: {plot_info.prover.get_filename()}"
|
||||
)
|
||||
continue
|
||||
|
||||
new_challenge: bytes32 = calculate_pos_challenge(plot_id, challenge_hash, signage_point)
|
||||
|
||||
# these are either qualities (v1) or partial proofs (v2)
|
||||
proofs: Sequence[Union[bytes32, bytes]]
|
||||
v = plot_info.prover.get_version()
|
||||
if v == PlotVersion.V1:
|
||||
proofs = plot_info.prover.get_qualities_for_challenge(new_challenge)
|
||||
else:
|
||||
proofs = plot_info.prover.get_partial_proofs_for_challenge(new_challenge, required_plot_strength)
|
||||
|
||||
for proof_index, proof in enumerate(proofs):
|
||||
if v == PlotVersion.V2:
|
||||
quality_str = quality_for_partial_proof(proof, new_challenge)
|
||||
elif v == PlotVersion.V1:
|
||||
quality_str = bytes32(proof)
|
||||
qualities: Sequence[QualityProtocol] = plot_info.prover.get_qualities_for_challenge(
|
||||
new_challenge, constants.QUALITY_PROOF_SCAN_FILTER
|
||||
)
|
||||
|
||||
for idx, quality in enumerate(qualities):
|
||||
required_iters = calculate_iterations_quality(
|
||||
constants,
|
||||
quality_str,
|
||||
quality.get_string(),
|
||||
plot_info.prover.get_size(),
|
||||
difficulty,
|
||||
signage_point,
|
||||
@@ -1550,11 +1542,16 @@ class BlockTools:
|
||||
if required_iters >= calculate_sp_interval_iters(constants, sub_slot_iters):
|
||||
continue
|
||||
|
||||
proof_xs: bytes
|
||||
if v == PlotVersion.V1:
|
||||
proof_xs = plot_info.prover.get_full_proof(new_challenge, proof_index)
|
||||
else:
|
||||
proof_xs = solve_proof(proof)
|
||||
proof = b""
|
||||
if isinstance(plot_info.prover, V1Prover):
|
||||
proof = plot_info.prover.get_full_proof(new_challenge, idx)
|
||||
elif isinstance(plot_info.prover, V2Prover):
|
||||
assert isinstance(quality, V2Quality)
|
||||
partial_proof = plot_info.prover.get_partial_proof(quality)
|
||||
k_size = plot_info.prover.get_size().size_v2
|
||||
strength = plot_info.prover.get_strength()
|
||||
assert k_size is not None
|
||||
proof = solve_proof(partial_proof, plot_id, strength, k_size)
|
||||
|
||||
# Look up local_sk from plot to save locked memory
|
||||
(
|
||||
@@ -1576,7 +1573,7 @@ class BlockTools:
|
||||
plot_info.pool_contract_puzzle_hash,
|
||||
plot_pk,
|
||||
plot_info.prover.get_size(),
|
||||
proof_xs,
|
||||
proof,
|
||||
)
|
||||
found_proofs.append((required_iters, proof_of_space))
|
||||
random_sample = found_proofs
|
||||
|
||||
@@ -8,13 +8,14 @@ from concurrent.futures.thread import ThreadPoolExecutor
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING, Any, ClassVar, Optional, cast
|
||||
|
||||
from chia_rs import ConsensusConstants
|
||||
from chia_rs import ConsensusConstants, solve_proof
|
||||
from chia_rs.sized_bytes import bytes32
|
||||
from chia_rs.sized_ints import uint64
|
||||
|
||||
from chia.protocols.outbound_message import NodeType
|
||||
from chia.rpc.rpc_server import StateChangedProtocol, default_get_connections
|
||||
from chia.server.server import ChiaServer
|
||||
from chia.server.ws_connection import WSChiaConnection
|
||||
from chia.types.blockchain_format.proof_of_space import solve_proof
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@@ -67,10 +68,10 @@ class Solver:
|
||||
self.executor.shutdown(wait=True)
|
||||
self.log.info("Solver service shutdown complete")
|
||||
|
||||
def solve(self, partial_proof: bytes) -> Optional[bytes]:
|
||||
self.log.debug(f"Solve request: partial={partial_proof.hex()}")
|
||||
def solve(self, partial_proof: list[uint64], plot_id: bytes32, strength: int, size: int) -> Optional[bytes]:
|
||||
self.log.info(f"Solve request: partial={partial_proof[:5]} plot-id: {plot_id} k: {size}")
|
||||
try:
|
||||
return solve_proof(partial_proof)
|
||||
return solve_proof(partial_proof, plot_id, strength, size)
|
||||
except Exception:
|
||||
self.log.exception("solve_proof()")
|
||||
return None
|
||||
|
||||
@@ -40,12 +40,12 @@ class SolverAPI:
|
||||
self.log.error("Solver is not started")
|
||||
return None
|
||||
|
||||
self.log.debug(f"Solving partial {request.partial_proof.hex()}")
|
||||
self.log.debug(f"Solving partial {request.partial_proof[:5]}")
|
||||
|
||||
try:
|
||||
proof = self.solver.solve(request.partial_proof)
|
||||
proof = self.solver.solve(request.partial_proof, request.plot_id, request.strength, request.size)
|
||||
if proof is None:
|
||||
self.log.warning(f"Solver returned no proof for parital {request.partial_proof.hex()}")
|
||||
self.log.warning(f"Solver returned no proof for parital {request.partial_proof[:5]}")
|
||||
return None
|
||||
|
||||
self.log.debug(f"Successfully solved partial proof, returning {len(proof)} byte proof")
|
||||
@@ -55,5 +55,5 @@ class SolverAPI:
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
self.log.error(f"Error solving parital {request.partial_proof.hex()}: {e}")
|
||||
self.log.error(f"Error solving parital {request.partial_proof[:5]}: {e}")
|
||||
return None
|
||||
|
||||
@@ -24,12 +24,6 @@ def validate_proof_v2(
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
# this is compute intensive, solving a partial proof returning a full proof
|
||||
def solve_proof(partial_proof: bytes) -> bytes:
|
||||
# TODO: todo_v2_plots call into new chiapos library
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
# given a partial proof, computes the quality. This is used to compute required iters.
|
||||
def quality_for_partial_proof(partial_proof: bytes, challenge: bytes32) -> bytes32:
|
||||
# TODO: todo_v2_plots call into new chiapos library
|
||||
@@ -142,8 +136,9 @@ def verify_and_get_quality_string(
|
||||
# === V2 plots ===
|
||||
assert plot_size.size_v2 is not None
|
||||
|
||||
required_plot_strength = calculate_required_plot_strength(constants, height)
|
||||
return validate_proof_v2(plot_id, plot_size.size_v2, required_plot_strength, pos.challenge, bytes(pos.proof))
|
||||
return validate_proof_v2(
|
||||
plot_id, plot_size.size_v2, constants.PLOT_STRENGTH_INITIAL, pos.challenge, bytes(pos.proof)
|
||||
)
|
||||
|
||||
|
||||
def passes_plot_filter(
|
||||
@@ -164,8 +159,13 @@ def passes_plot_filter(
|
||||
|
||||
|
||||
def calculate_prefix_bits(constants: ConsensusConstants, height: uint32, plot_size: PlotSize) -> int:
|
||||
# v2 plots have a constant plot filter size
|
||||
if plot_size.size_v2 is not None:
|
||||
if height >= constants.PLOT_FILTER_V2_THIRD_ADJUSTMENT_HEIGHT:
|
||||
return constants.NUMBER_ZERO_BITS_PLOT_FILTER_V2 + 3
|
||||
if height >= constants.PLOT_FILTER_V2_SECOND_ADJUSTMENT_HEIGHT:
|
||||
return constants.NUMBER_ZERO_BITS_PLOT_FILTER_V2 + 2
|
||||
if height >= constants.PLOT_FILTER_V2_FIRST_ADJUSTMENT_HEIGHT:
|
||||
return constants.NUMBER_ZERO_BITS_PLOT_FILTER_V2 + 1
|
||||
return constants.NUMBER_ZERO_BITS_PLOT_FILTER_V2
|
||||
|
||||
prefix_bits = int(constants.NUMBER_ZERO_BITS_PLOT_FILTER_V1)
|
||||
@@ -181,21 +181,6 @@ def calculate_prefix_bits(constants: ConsensusConstants, height: uint32, plot_si
|
||||
return max(0, prefix_bits)
|
||||
|
||||
|
||||
def calculate_required_plot_strength(constants: ConsensusConstants, height: uint32) -> uint8:
|
||||
if height < constants.PLOT_STRENGTH_4_HEIGHT:
|
||||
return constants.PLOT_STRENGTH_INITIAL
|
||||
if height < constants.PLOT_STRENGTH_5_HEIGHT:
|
||||
return uint8(4)
|
||||
if height < constants.PLOT_STRENGTH_6_HEIGHT:
|
||||
return uint8(5)
|
||||
if height < constants.PLOT_STRENGTH_7_HEIGHT:
|
||||
return uint8(6)
|
||||
if height < constants.PLOT_STRENGTH_8_HEIGHT:
|
||||
return uint8(7)
|
||||
else:
|
||||
return uint8(8)
|
||||
|
||||
|
||||
def calculate_plot_filter_input(plot_id: bytes32, challenge_hash: bytes32, signage_point: bytes32) -> bytes32:
|
||||
return std_hash(plot_id + challenge_hash + signage_point)
|
||||
|
||||
|
||||
+29
-29
@@ -1,4 +1,4 @@
|
||||
# This file is automatically @generated by Poetry 2.2.1 and should not be changed by hand.
|
||||
# This file is automatically @generated by Poetry 2.2.0 and should not be changed by hand.
|
||||
|
||||
[[package]]
|
||||
name = "aiofiles"
|
||||
@@ -876,38 +876,38 @@ pytest = ">=8.3.3,<9.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "chia-rs"
|
||||
version = "0.30.0"
|
||||
version = "0.32.0"
|
||||
description = ""
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "chia_rs-0.30.0-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:a2ca9669e0ffad97cc3e39e49839fef568013dcb4a645cfa802c68f5acb321c6"},
|
||||
{file = "chia_rs-0.30.0-cp310-cp310-macosx_13_0_x86_64.whl", hash = "sha256:ef12c719f4c6fb0d427b110f331e026b4bcb6fa95856a0095f0d885ebf50d0a9"},
|
||||
{file = "chia_rs-0.30.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:7d140a0de8ab59fa75421590550491ea042a8a6e17f1b789b92b7f267561c568"},
|
||||
{file = "chia_rs-0.30.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:b9dbd5b2265e8743c1038b7e8cfff6131ef8a56a68fc8675b11ba18d4a3d9f97"},
|
||||
{file = "chia_rs-0.30.0-cp310-cp310-win_amd64.whl", hash = "sha256:67e5b5a5f9acb42ff364dcf72e5fc7fab7c6e2daad26a99edd9b24a7d4c932e8"},
|
||||
{file = "chia_rs-0.30.0-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:2b995c05429343c8b91bdfa1cdca97e23b72393b1b54f0ab6703e63e74016f1d"},
|
||||
{file = "chia_rs-0.30.0-cp311-cp311-macosx_13_0_x86_64.whl", hash = "sha256:2cc43223e3e092621523e35a38320a87941886315d3eb29b69e0470c7546e1c2"},
|
||||
{file = "chia_rs-0.30.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:b30d3868b004dba2fbc59c004cb3345b598f9f5b500ce426d23ccb3aaa1f608b"},
|
||||
{file = "chia_rs-0.30.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:45284e3d4655c1b8fca2024c050777bf6919de429949e26c5ff83ffe553fbd87"},
|
||||
{file = "chia_rs-0.30.0-cp311-cp311-win_amd64.whl", hash = "sha256:d892e63730ec94ab16fbb21cb25e07889d8136973487252c7b65d2611d759346"},
|
||||
{file = "chia_rs-0.30.0-cp312-cp312-macosx_13_0_arm64.whl", hash = "sha256:004259970cba586f4bc70b6759ce9d1fc8310fdd96bb25d9e68e79a497a55bc9"},
|
||||
{file = "chia_rs-0.30.0-cp312-cp312-macosx_13_0_x86_64.whl", hash = "sha256:5c9ffcd52640edc31860e52ce482e91e2090b46373e70c07fe5828b99be7b10b"},
|
||||
{file = "chia_rs-0.30.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:b1850d32ee34cc92e3d912a445a528dc2cfde08e5eed2304fb050209f4637fa5"},
|
||||
{file = "chia_rs-0.30.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:3ce97f9baa4adc6233935b1138193446b81a0742993d7d49f186dbc61a8a2f91"},
|
||||
{file = "chia_rs-0.30.0-cp312-cp312-win_amd64.whl", hash = "sha256:9edd53c61d1462aae5a91265b9499afee19fea40a69c36f79d8ce7e519b3ad54"},
|
||||
{file = "chia_rs-0.30.0-cp313-cp313-macosx_13_0_arm64.whl", hash = "sha256:828477104cb13e57a1d82f286cb2a9961f711748da6b6459fbc522e14a6eeaa3"},
|
||||
{file = "chia_rs-0.30.0-cp313-cp313-macosx_13_0_x86_64.whl", hash = "sha256:707035a2596a48ada8a16b1daae7454360cfefc41074860ccf55dd6db0de1bcd"},
|
||||
{file = "chia_rs-0.30.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:3e1437b5af745b7f080882204c96b82ca50df394cca71ca4e977d86c0df5881a"},
|
||||
{file = "chia_rs-0.30.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:e3aa7eb08d34641d9059a2cd4d27ccf03e86c1b371b1ae465bbb5b1d84e1d3eb"},
|
||||
{file = "chia_rs-0.30.0-cp313-cp313-win_amd64.whl", hash = "sha256:6961a0c946217a6c25abcd5964e7e6d484f54456f70f226348b3a2a60b2c7840"},
|
||||
{file = "chia_rs-0.30.0-cp39-cp39-macosx_13_0_arm64.whl", hash = "sha256:5209a94bf27e3209292b5a18cd582f6a185180b42a1b70d0bf69463c41ac440e"},
|
||||
{file = "chia_rs-0.30.0-cp39-cp39-macosx_13_0_x86_64.whl", hash = "sha256:203d52fd1622b96e970ad9c047d516132b19bc136ecf62e526c4e8ca9f23de1e"},
|
||||
{file = "chia_rs-0.30.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:ef930b975b4f74b5c7089d263f9183826c5afdf076ae6fc5e765bafcad36b983"},
|
||||
{file = "chia_rs-0.30.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:68374a5b3e9e7d27a81d0d96b06053f24ace0238d60795ab7188ba1dee556112"},
|
||||
{file = "chia_rs-0.30.0-cp39-cp39-win_amd64.whl", hash = "sha256:de9da557ef7afd56dbc28b46d53747c39ce9cb919b78fb50be22ed335b22293d"},
|
||||
{file = "chia_rs-0.30.0.tar.gz", hash = "sha256:87937b76a0dab8cb304c641fb9af77a59c8270d59686b00d1a81766c4c8acfed"},
|
||||
{file = "chia_rs-0.32.0-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:3a423b3317246bb0337a9e73831932cec6757b9d71fe3e1556a1dbedf77f7a6a"},
|
||||
{file = "chia_rs-0.32.0-cp310-cp310-macosx_13_0_x86_64.whl", hash = "sha256:eecbf98f7fd6a29436c71b4d8901aaf1d5c15a7fb7c66f04c251595f8c915d9b"},
|
||||
{file = "chia_rs-0.32.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:508a81789a839212963601f06c2646e068436f8f1250d8379a33c107c4931497"},
|
||||
{file = "chia_rs-0.32.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:82d7334d4c9d15765dbda8c8e2a13fa88f44d3b2b97bded48717768edd595f25"},
|
||||
{file = "chia_rs-0.32.0-cp310-cp310-win_amd64.whl", hash = "sha256:e7095b5840b63d5d3e9f309b6adba53708c827711897ef0eba2ead9d8d137aee"},
|
||||
{file = "chia_rs-0.32.0-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:32b20eeb971628d13b3ca7605eb6d76e887f253bc25c2c77624fa2e96fb3a6fe"},
|
||||
{file = "chia_rs-0.32.0-cp311-cp311-macosx_13_0_x86_64.whl", hash = "sha256:be53d2533b0bcf3160d8c1c9d43a225f1951cff343dfc15a682ba3b98530da82"},
|
||||
{file = "chia_rs-0.32.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:4456c6cf824af867437e9176f7052fd96203ff50e1f17985bed85c994a06b0a4"},
|
||||
{file = "chia_rs-0.32.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:76c342357f2f931931354ac16564fe4d7996e6eced48fe2760e6f220a5ab6e93"},
|
||||
{file = "chia_rs-0.32.0-cp311-cp311-win_amd64.whl", hash = "sha256:aa4d7c1774bce3bb359b3a1441d88aa7aa0c0bd2122763789e58fa806bf2f67e"},
|
||||
{file = "chia_rs-0.32.0-cp312-cp312-macosx_13_0_arm64.whl", hash = "sha256:297ef6a57772e5c5c9ce825f7c2e43e6c52291cc2bbab705d9d64b6300b6f4e5"},
|
||||
{file = "chia_rs-0.32.0-cp312-cp312-macosx_13_0_x86_64.whl", hash = "sha256:0c94e1c9e6c5d71b25734d47d264514fb9167616377fbd4b518de5447331d3c5"},
|
||||
{file = "chia_rs-0.32.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:5523413a04eadbc7583504e22c0e9360ed64e0d51440adb1b48511a91c4fdfd2"},
|
||||
{file = "chia_rs-0.32.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:4b1131c0547e3be280b36562d84fd8433e805e5306fdaaba769d474b0fc02992"},
|
||||
{file = "chia_rs-0.32.0-cp312-cp312-win_amd64.whl", hash = "sha256:7016ecab7b06284abc4e926c7fa96146dafd20d830b84c697597b008b6dced2b"},
|
||||
{file = "chia_rs-0.32.0-cp313-cp313-macosx_13_0_arm64.whl", hash = "sha256:624a30a9a18400b6e4ce92020e6cbc34f393b3629825455da4c1593e856487ab"},
|
||||
{file = "chia_rs-0.32.0-cp313-cp313-macosx_13_0_x86_64.whl", hash = "sha256:e67e5b46eaeee5887f150abc33b7b24ef6af6b862afc4b0a4d255453ee978e57"},
|
||||
{file = "chia_rs-0.32.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:6e695e44428d2f9c02388578291d664dcd54d9fe4608adb51ae44931d210f02a"},
|
||||
{file = "chia_rs-0.32.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:846a51f87725524c0743ee809a21e876dfda3613624fd4b34dce40269d9e75bc"},
|
||||
{file = "chia_rs-0.32.0-cp313-cp313-win_amd64.whl", hash = "sha256:63bb1a87feb6c1782154d7deb292a461e36c010840026c4c733495d6935bdcdb"},
|
||||
{file = "chia_rs-0.32.0-cp39-cp39-macosx_13_0_arm64.whl", hash = "sha256:5b768d1585bfb6fa8a7f61106ddd5b4f9a7a274a3ebd86b6a03896af29e280da"},
|
||||
{file = "chia_rs-0.32.0-cp39-cp39-macosx_13_0_x86_64.whl", hash = "sha256:5feabc844caa2ee2a39fd8c40f57497c164f71c2b58ff0a045510529ee1259bf"},
|
||||
{file = "chia_rs-0.32.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:65b084624ded4382d98cb8e7de8517ec062338df0af4578316fbd1a42ef33ab0"},
|
||||
{file = "chia_rs-0.32.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:89e2a8d93571fc0067e0f7fe4f7a43f62277696fa4e1a6c493eb89aa3af8700b"},
|
||||
{file = "chia_rs-0.32.0-cp39-cp39-win_amd64.whl", hash = "sha256:565b4e657936cff798ef684c0e3f496f0e189f98ab37c02d7b1018ab97e23a6b"},
|
||||
{file = "chia_rs-0.32.0.tar.gz", hash = "sha256:42b4901a0ce1fc94971d2c33b585a950a5528360560619e427bc9d7f534085e9"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@@ -3997,4 +3997,4 @@ upnp = ["miniupnpc"]
|
||||
[metadata]
|
||||
lock-version = "2.1"
|
||||
python-versions = ">=3.10, <4"
|
||||
content-hash = "593d5a538eed9036f2a2a58bfbf9069cb973bb34a54eb13ef1382cf4c92a0a1b"
|
||||
content-hash = "6ed8a051283de31228deb72a90abdf55ef4d6aa8fb70cd8173950a6b93c710fd"
|
||||
|
||||
+1
-1
@@ -53,7 +53,7 @@ boto3 = ">=1.35.43" # AWS S3 for Data Layer S3 plugin
|
||||
chiabip158 = ">=1.5.2" # bip158-style wallet filters
|
||||
chiapos = ">=2.0.10" # proof of space
|
||||
chia-puzzles-py = ">=0.20.1"
|
||||
chia_rs = ">=0.30, <0.31"
|
||||
chia_rs = ">=0.32, <0.33"
|
||||
chiavdf = ">=1.1.10" # timelord and vdf verification
|
||||
click = ">=8.1.7" # For the CLI
|
||||
clvm = ">=0.9.14"
|
||||
|
||||
Reference in New Issue
Block a user