mirror of
https://github.com/Chia-Network/chia-blockchain.git
synced 2026-08-24 10:05:29 -05:00
* Use a separate config for pooling information * New PlotNFT drivers * PlotNFT2 Wallet * PlotNFT V2 RPCs and CLI * Integrate v2 pooling protocol into farmer * Comment by @cursor * Fix test * Comments by @cursor * whoops * Comments by @cursor * Comments by @cursor * Comments by @cursor * Some tidying * fix test for memo adjustment * tweak additional memos again * empirical testing with v1 pools * Add expiration to `GetAuthRequest` * Remove pyjwt dep * Revert `get_login_link` to old behavior * Add an extra derivation to auth key for v2 * unhardened * Fix login link test * Fix login link test again * Fix network protocol data * Comments by cursor * Fix test * Use correct pool url after redirect * Fix test for coverage * Upstream wallet fixes * Add `REMARK` option to `launch` * pre-commit * chmod * test coverage * Add wallet name * test coverage * moar test coverage * commentsby @cursor * moar test coverage * fix custody architecture namespace * Comments by @matt-o-how * Fix /GET farmer to omit the signature rather than None * Fix protocol test * fix test * comments by @cursor * diff minimizatino * event dispatch * Fix test deadlock * Comments by @cursor * test coverage * Comments by @cursor * Comments by @cursor
292 lines
9.1 KiB
Python
292 lines
9.1 KiB
Python
from __future__ import annotations
|
|
|
|
import ast
|
|
import inspect
|
|
from typing import Any, cast
|
|
|
|
import pytest
|
|
|
|
from chia.protocols import (
|
|
farmer_protocol,
|
|
full_node_protocol,
|
|
harvester_protocol,
|
|
introducer_protocol,
|
|
pool_protocol,
|
|
protocol_message_types,
|
|
shared_protocol,
|
|
solver_protocol,
|
|
timelord_protocol,
|
|
wallet_protocol,
|
|
)
|
|
|
|
# this test is to ensure the network protocol message regression test always
|
|
# stays up to date. It's a test for the test
|
|
|
|
|
|
def types_in_module(mod: Any) -> set[str]:
|
|
parsed = ast.parse(inspect.getsource(mod))
|
|
types = set()
|
|
for line in parsed.body:
|
|
if isinstance(line, ast.Assign):
|
|
name = cast(ast.Name, line.targets[0])
|
|
if inspect.isclass(getattr(mod, name.id)):
|
|
types.add(name.id)
|
|
elif isinstance(line, ast.ClassDef):
|
|
types.add(line.name)
|
|
return types
|
|
|
|
|
|
STANDARD_ADVICE = "Make sure to update the protocol message regression test to include the new message"
|
|
|
|
|
|
def test_missing_messages_state_machine() -> None:
|
|
from chia.protocols.protocol_state_machine import NO_REPLY_EXPECTED, VALID_REPLY_MESSAGE_MAP
|
|
|
|
# if these asserts fail, make sure to add the new network protocol messages
|
|
# to the visitor in build_network_protocol_files.py and rerun it. Then
|
|
# update this test
|
|
assert len(VALID_REPLY_MESSAGE_MAP) == 26, f"A message was added to the protocol state machine. {STANDARD_ADVICE}"
|
|
assert len(NO_REPLY_EXPECTED) == 10, f"A message was added to the protocol state machine. {STANDARD_ADVICE}"
|
|
|
|
|
|
def test_message_ids() -> None:
|
|
parsed = ast.parse(inspect.getsource(protocol_message_types))
|
|
message_ids: dict[int, str] = {}
|
|
for line in parsed.body:
|
|
if not isinstance(line, ast.ClassDef) or line.name != "ProtocolMessageTypes":
|
|
continue
|
|
for entry in line.body:
|
|
if not isinstance(entry, ast.Assign): # pragma: no cover
|
|
continue
|
|
assert isinstance(entry.value, ast.Constant)
|
|
assert isinstance(entry.targets[0], ast.Name)
|
|
message_id = entry.value.value
|
|
assert isinstance(message_id, int), f"message ID must be an int, got {type(message_id).__name__}"
|
|
message_name = entry.targets[0].id
|
|
if message_id in message_ids: # pragma: no cover
|
|
raise AssertionError(
|
|
f'protocol message ID clash between "{message_name}" and "{message_ids[message_id]}". '
|
|
f"Value {message_id}"
|
|
)
|
|
message_ids[message_id] = message_name
|
|
if message_id < 0 or message_id > 255: # pragma: no cover
|
|
raise AssertionError(f'message ID must fit in a uint8. "{message_name}" has value {message_id}')
|
|
break
|
|
assert len(message_ids) > 0
|
|
|
|
|
|
def test_missing_messages() -> None:
|
|
wallet_msgs = {
|
|
"CoinState",
|
|
"CoinStateFilters",
|
|
"CoinStateUpdate",
|
|
"MempoolItemsAdded",
|
|
"MempoolItemsRemoved",
|
|
"NewPeakWallet",
|
|
"PuzzleSolutionResponse",
|
|
"RegisterForCoinUpdates",
|
|
"RegisterForPhUpdates",
|
|
"RejectAdditionsRequest",
|
|
"RejectBlockHeaders",
|
|
"RejectCoinState",
|
|
"RejectHeaderBlocks",
|
|
"RejectHeaderRequest",
|
|
"RejectPuzzleSolution",
|
|
"RejectPuzzleState",
|
|
"RejectRemovalsRequest",
|
|
"RejectStateReason",
|
|
"RemovedMempoolItem",
|
|
"RequestAdditions",
|
|
"RequestBlockHeader",
|
|
"RequestBlockHeaders",
|
|
"RequestChildren",
|
|
"RequestCoinState",
|
|
"RequestCostInfo",
|
|
"RequestFeeEstimates",
|
|
"RequestHeaderBlocks",
|
|
"RequestPuzzleSolution",
|
|
"RequestPuzzleState",
|
|
"RequestRemovals",
|
|
"RequestRemoveCoinSubscriptions",
|
|
"RequestRemovePuzzleSubscriptions",
|
|
"RequestSESInfo",
|
|
"RespondAdditions",
|
|
"RespondBlockHeader",
|
|
"RespondBlockHeaders",
|
|
"RespondChildren",
|
|
"RespondCoinState",
|
|
"RespondCostInfo",
|
|
"RespondFeeEstimates",
|
|
"RespondHeaderBlocks",
|
|
"RespondPuzzleSolution",
|
|
"RespondPuzzleState",
|
|
"RespondRemovals",
|
|
"RespondRemoveCoinSubscriptions",
|
|
"RespondRemovePuzzleSubscriptions",
|
|
"RespondSESInfo",
|
|
"RespondToCoinUpdates",
|
|
"RespondToPhUpdates",
|
|
"SendTransaction",
|
|
"TransactionAck",
|
|
}
|
|
|
|
farmer_msgs = {
|
|
"DeclareProofOfSpace",
|
|
"FarmingInfo",
|
|
"SPSubSlotSourceData",
|
|
"SPVDFSourceData",
|
|
"SignagePointSourceData",
|
|
"NewSignagePoint",
|
|
"RequestSignedValues",
|
|
"SignedValues",
|
|
}
|
|
|
|
full_node_msgs = {
|
|
"NewCompactVDF",
|
|
"NewPeak",
|
|
"NewSignagePointOrEndOfSubSlot",
|
|
"NewTransaction",
|
|
"NewUnfinishedBlock",
|
|
"NewUnfinishedBlock2",
|
|
"RejectBlock",
|
|
"RejectBlocks",
|
|
"RequestBlock",
|
|
"RequestBlocks",
|
|
"RequestCompactVDF",
|
|
"RequestMempoolTransactions",
|
|
"RequestPeers",
|
|
"RequestProofOfWeight",
|
|
"RequestSignagePointOrEndOfSubSlot",
|
|
"RequestTransaction",
|
|
"RequestUnfinishedBlock",
|
|
"RequestUnfinishedBlock2",
|
|
"RespondBlock",
|
|
"RespondBlocks",
|
|
"RespondCompactVDF",
|
|
"RespondEndOfSubSlot",
|
|
"RespondPeers",
|
|
"RespondProofOfWeight",
|
|
"RespondSignagePoint",
|
|
"RespondTransaction",
|
|
"RespondUnfinishedBlock",
|
|
}
|
|
|
|
harvester_msgs = {
|
|
"HarvesterHandshake",
|
|
"ProofOfSpaceFeeInfo",
|
|
"NewProofOfSpace",
|
|
"NewSignagePointHarvester",
|
|
"NewSignagePointHarvester2",
|
|
"Plot",
|
|
"Plot2",
|
|
"PlotSyncDone",
|
|
"PlotSyncError",
|
|
"PlotSyncIdentifier",
|
|
"PlotSyncPathList",
|
|
"PlotSyncPlotList",
|
|
"PlotSyncPlotList2",
|
|
"PlotSyncResponse",
|
|
"PlotSyncStart",
|
|
"PoolDifficulty",
|
|
"RequestPlots",
|
|
"SigningDataKind",
|
|
"SignatureRequestSourceData",
|
|
"RequestSignatures",
|
|
"RespondPlots",
|
|
"RespondPlots2",
|
|
"RespondSignatures",
|
|
"PartialProofsData",
|
|
}
|
|
|
|
introducer_msgs = {"RequestPeersIntroducer", "RespondPeersIntroducer"}
|
|
|
|
pool_msgs = {
|
|
"AuthenticationPayloadV1",
|
|
"GetAuthRequest",
|
|
"GetFarmerRequestV1",
|
|
"GetFarmerRequestV2",
|
|
"GetAuthResponse",
|
|
"ErrorResponse",
|
|
"GetFarmerResponse",
|
|
"GetPoolInfoResponse",
|
|
"PoolErrorCode",
|
|
"PostFarmerPayload",
|
|
"PostFarmerRequest",
|
|
"PostFarmerResponse",
|
|
"PostPartialPayload",
|
|
"PostPartialRequest",
|
|
"PostPartialResponse",
|
|
"PutFarmerPayload",
|
|
"PutFarmerRequest",
|
|
"PutFarmerResponse",
|
|
}
|
|
|
|
timelord_msgs = {
|
|
"NewEndOfSubSlotVDF",
|
|
"NewInfusionPointVDF",
|
|
"NewPeakTimelord",
|
|
"NewSignagePointVDF",
|
|
"NewUnfinishedBlockTimelord",
|
|
"RequestCompactProofOfTime",
|
|
"RespondCompactProofOfTime",
|
|
}
|
|
|
|
solver_msgs = {"SolverInfo", "SolverResponse"}
|
|
|
|
shared_msgs = {"Handshake", "ConfigureWindowSizes", "Capability", "Error"}
|
|
|
|
# if these asserts fail, make sure to add the new network protocol messages
|
|
# to the visitor in build_network_protocol_files.py and rerun it. Then
|
|
# update this test
|
|
assert types_in_module(wallet_protocol) == wallet_msgs, (
|
|
f"message types were added or removed from wallet_protocol. {STANDARD_ADVICE}"
|
|
)
|
|
|
|
assert types_in_module(farmer_protocol) == farmer_msgs, (
|
|
f"message types were added or removed from farmer_protocol. {STANDARD_ADVICE}"
|
|
)
|
|
|
|
assert types_in_module(full_node_protocol) == full_node_msgs, (
|
|
f"message types were added or removed from full_node_protocol. {STANDARD_ADVICE}"
|
|
)
|
|
|
|
assert types_in_module(harvester_protocol) == harvester_msgs, (
|
|
f"message types were added or removed from harvester_protocol. {STANDARD_ADVICE}"
|
|
)
|
|
|
|
assert types_in_module(introducer_protocol) == introducer_msgs, (
|
|
f"message types were added or removed from introducer_protocol. {STANDARD_ADVICE}"
|
|
)
|
|
|
|
assert types_in_module(pool_protocol) == pool_msgs, (
|
|
f"message types were added or removed from pool_protocol. {STANDARD_ADVICE}"
|
|
)
|
|
|
|
assert types_in_module(timelord_protocol) == timelord_msgs, (
|
|
f"message types were added or removed from timelord_protocol. {STANDARD_ADVICE}"
|
|
)
|
|
|
|
assert types_in_module(solver_protocol) == solver_msgs, (
|
|
f"message types were added or removed from shared_protocol. {STANDARD_ADVICE}"
|
|
)
|
|
|
|
assert types_in_module(shared_protocol) == shared_msgs, (
|
|
f"message types were added or removed from shared_protocol. {STANDARD_ADVICE}"
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize("version", [1, 2])
|
|
def test_rate_limits_complete(version: int) -> None:
|
|
from chia.protocols.protocol_message_types import ProtocolMessageTypes
|
|
from chia.server.rate_limit_numbers import rate_limits
|
|
|
|
if version == 1:
|
|
composed = rate_limits[1]
|
|
elif version == 2:
|
|
composed = {
|
|
**rate_limits[1],
|
|
**rate_limits[2],
|
|
}
|
|
|
|
assert set(composed.keys()) == set(ProtocolMessageTypes)
|