Skip to content

Commit bd665b2

Browse files
fix: align ResponseCode enum with response_code.proto (#2625)
Signed-off-by: Mounil Kanakhara <mounilkankhara@gmail.com> Co-authored-by: Sophie Bulloch <133720349+exploreriii@users.noreply.github.com>
1 parent 043dbb7 commit bd665b2

2 files changed

Lines changed: 101 additions & 2 deletions

File tree

src/hiero_sdk_python/response_code.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ class ResponseCode(IntEnum):
117117
EXPIRATION_REDUCTION_NOT_ALLOWED = 110
118118
MAX_GAS_LIMIT_EXCEEDED = 111
119119
MAX_FILE_SIZE_EXCEEDED = 112
120+
RECEIVER_SIG_REQUIRED = 113
120121

121122
INVALID_TOPIC_ID = 150
122123
INVALID_ADMIN_KEY = 155
@@ -307,6 +308,8 @@ class ResponseCode(IntEnum):
307308
INVALID_NODE_ACCOUNT_ID = 341
308309
INVALID_NODE_DESCRIPTION = 342
309310
INVALID_SERVICE_ENDPOINT = 343
311+
INVALID_GOSSIP_CA_CERTIFICATE = 344
312+
# Deprecated alias, misspelled: use INVALID_GOSSIP_CA_CERTIFICATE instead.
310313
INVALID_GOSSIP_CAE_CERTIFICATE = 344
311314
INVALID_GRPC_CERTIFICATE = 345
312315
INVALID_MAX_AUTO_ASSOCIATIONS = 346
@@ -319,19 +322,23 @@ class ResponseCode(IntEnum):
319322
TOKEN_REFERENCE_REPEATED = 353
320323
INVALID_OWNER_ID = 354
321324
TOKEN_REFERENCE_LIST_SIZE_LIMIT_EXCEEDED = 355
322-
INVALID_IPV4_ADDRESS = 356
323-
SERVICE_ENDPOINTS_EXCEEDED_LIMIT = 357
325+
SERVICE_ENDPOINTS_EXCEEDED_LIMIT = 356
326+
INVALID_IPV4_ADDRESS = 357
324327
EMPTY_TOKEN_REFERENCE_LIST = 358
325328
UPDATE_NODE_ACCOUNT_NOT_ALLOWED = 359
326329
TOKEN_HAS_NO_METADATA_OR_SUPPLY_KEY = 360
327330
EMPTY_PENDING_AIRDROP_ID_LIST = 361
328331
PENDING_AIRDROP_ID_REPEATED = 362
332+
PENDING_AIRDROP_ID_LIST_TOO_LONG = 363
333+
# Deprecated alias: use PENDING_AIRDROP_ID_LIST_TOO_LONG instead.
329334
MAX_PENDING_AIRDROP_ID_EXCEEDED = 363
330335
PENDING_NFT_AIRDROP_ALREADY_EXISTS = 364
331336
ACCOUNT_HAS_PENDING_AIRDROPS = 365
332337
THROTTLED_AT_CONSENSUS = 366
333338
INVALID_PENDING_AIRDROP_ID = 367
334339
TOKEN_AIRDROP_WITH_FALLBACK_ROYALTY = 368
340+
INVALID_TOKEN_IN_PENDING_AIRDROP = 369
341+
# Deprecated alias: use INVALID_TOKEN_IN_PENDING_AIRDROP instead.
335342
INVALID_TOKEN_ID_PENDING_AIRDROP = 369
336343
SCHEDULE_EXPIRY_IS_BUSY = 370
337344
INVALID_GRPC_CERTIFICATE_HASH = 371

tests/unit/response_code_test.py

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
from __future__ import annotations
2+
3+
import pytest
4+
5+
from hiero_sdk_python.response_code import ResponseCode
6+
7+
8+
pytestmark = pytest.mark.unit
9+
10+
11+
@pytest.mark.parametrize(
12+
("code", "expected_name"),
13+
[
14+
# Previously swapped with each other (356 <-> 357).
15+
(356, "SERVICE_ENDPOINTS_EXCEEDED_LIMIT"),
16+
(357, "INVALID_IPV4_ADDRESS"),
17+
# Previously carried a misspelled or non-canonical name.
18+
(344, "INVALID_GOSSIP_CA_CERTIFICATE"),
19+
(363, "PENDING_AIRDROP_ID_LIST_TOO_LONG"),
20+
(369, "INVALID_TOKEN_IN_PENDING_AIRDROP"),
21+
# Previously missing entirely, so the network's code surfaced as UNKNOWN_CODE_113.
22+
(113, "RECEIVER_SIG_REQUIRED"),
23+
],
24+
)
25+
def test_code_resolves_to_canonical_proto_name(code: int, expected_name: str) -> None:
26+
"""Each corrected code resolves to the name used in response_code.proto."""
27+
member = ResponseCode(code)
28+
assert member.name == expected_name
29+
assert member is ResponseCode[expected_name]
30+
31+
32+
@pytest.mark.parametrize(
33+
("deprecated_name", "canonical_name", "value"),
34+
[
35+
("INVALID_GOSSIP_CAE_CERTIFICATE", "INVALID_GOSSIP_CA_CERTIFICATE", 344),
36+
("MAX_PENDING_AIRDROP_ID_EXCEEDED", "PENDING_AIRDROP_ID_LIST_TOO_LONG", 363),
37+
("INVALID_TOKEN_ID_PENDING_AIRDROP", "INVALID_TOKEN_IN_PENDING_AIRDROP", 369),
38+
],
39+
)
40+
def test_renamed_codes_keep_working_deprecated_alias(deprecated_name: str, canonical_name: str, value: int) -> None:
41+
"""The old names still resolve, so existing user code keeps working."""
42+
alias = getattr(ResponseCode, deprecated_name)
43+
assert alias == value
44+
assert alias is getattr(ResponseCode, canonical_name)
45+
# An alias is reachable by name but is not a member in its own right.
46+
assert deprecated_name in ResponseCode.__members__
47+
assert deprecated_name not in {member.name for member in ResponseCode}
48+
49+
50+
@pytest.mark.parametrize(
51+
("code", "expected_name"),
52+
[
53+
(86, "INVALID_RECEIVE_RECORD_THRESHOLD"),
54+
(87, "INVALID_SEND_RECORD_THRESHOLD"),
55+
(284, "INVALID_PROXY_ACCOUNT_ID"),
56+
(291, "CANNOT_APPROVE_FOR_ALL_FUNGIBLE_COMMON"),
57+
(296, "SPENDER_ACCOUNT_REPEATED_IN_ALLOWANCES"),
58+
(297, "REPEATED_SERIAL_NUMS_IN_NFT_ALLOWANCES"),
59+
(302, "REPEATED_ALLOWANCES_TO_DELETE"),
60+
],
61+
)
62+
def test_codes_deprecated_in_the_protobuf_are_still_defined(code: int, expected_name: str) -> None:
63+
"""Codes marked [deprecated = true] in the proto remain defined, as the proto still defines them."""
64+
member = ResponseCode(code)
65+
assert member.name == expected_name
66+
assert member is ResponseCode[expected_name]
67+
# Deprecated in the protobuf is not the same as an alias: these are members in their own right.
68+
assert expected_name in {m.name for m in ResponseCode}
69+
70+
71+
def test_unknown_code_still_falls_back() -> None:
72+
"""The _missing_ hook is unaffected by the corrected members."""
73+
unknown = ResponseCode(9999)
74+
assert unknown.name == "UNKNOWN_CODE_9999"
75+
assert unknown.is_unknown
76+
assert not ResponseCode.SUCCESS.is_unknown
77+
78+
79+
@pytest.mark.parametrize(
80+
("code", "expected_name"),
81+
[
82+
(344, "INVALID_GOSSIP_CA_CERTIFICATE"),
83+
(356, "SERVICE_ENDPOINTS_EXCEEDED_LIMIT"),
84+
(113, "RECEIVER_SIG_REQUIRED"),
85+
(9999, "UNKNOWN_CODE_9999"),
86+
],
87+
)
88+
def test_deprecated_get_name_still_returns_the_canonical_name(code: int, expected_name: str) -> None:
89+
"""The deprecated get_name helper keeps working, and still warns, for corrected and unknown codes."""
90+
with pytest.warns(FutureWarning):
91+
name = ResponseCode.get_name(code)
92+
assert name == expected_name, f"get_name({code}) must return {expected_name!r}, got {name!r}"

0 commit comments

Comments
 (0)