Fix path length calculation and hash mode handling in MessageHandler

- Improved error handling for `out_path_hash_mode` and `out_path_len` to ensure proper type conversion and validation.
- Added logic to derive `out_path_len` from `out_path` when it is missing, enhancing robustness against incomplete data.
- Updated tests to verify correct behavior when `out_path_hash_mode` is provided as a string and `out_path_len` is absent.
This commit is contained in:
agessaman
2026-04-05 11:07:52 -07:00
parent 3670f5db41
commit ba52c3ba07
2 changed files with 50 additions and 4 deletions
+39 -4
View File
@@ -2922,12 +2922,47 @@ class MessageHandler:
meshcore update_contact uses out_path_len | (out_path_hash_mode << 6); hash_mode -1 with
non-negative hop count produces a negative int and OverflowError on unsigned to_bytes.
"""
if contact_data.get('out_path_hash_mode', 0) != -1:
try:
hash_mode = int(contact_data.get('out_path_hash_mode', 0))
except (TypeError, ValueError):
return
opl = contact_data.get('out_path_len')
if opl is None or opl < 0 or opl == -1:
if hash_mode != -1:
return
bph = contact_data.get('out_bytes_per_hop', 1) or 1
opl: Optional[int]
raw_opl = contact_data.get('out_path_len')
try:
opl = None if raw_opl is None else int(raw_opl)
except (TypeError, ValueError):
opl = None
bph_raw = contact_data.get('out_bytes_per_hop', 1) or 1
try:
bph = int(bph_raw)
except (TypeError, ValueError):
bph = 1
if bph not in (1, 2, 3):
bph = 1
# Some NEW_CONTACT payloads omit out_path_len but include out_path + bytes_per_hop.
# Derive hop count here so meshcore doesn't combine a non-flood path with hash_mode=-1.
if opl is None:
out_path_hex = contact_data.get('out_path') or ''
if not isinstance(out_path_hex, str) or not out_path_hex:
return
if (len(out_path_hex) % 2) != 0:
return
path_bytes = len(out_path_hex) // 2
if path_bytes <= 0:
return
if (path_bytes % bph) == 0:
opl = path_bytes // bph
else:
opl = path_bytes
if opl < 0 or opl == -1:
return
try:
pb = encode_path_len_byte(opl, bph)
except ValueError:
@@ -95,6 +95,17 @@ class TestEnsureContactMeshcorePathEncoding:
assert c["out_path_len"] == 3
assert (c["out_path_len"] | (c["out_path_hash_mode"] << 6)) == 0x43
def test_fixes_when_hash_mode_is_string_and_out_path_len_missing(self, message_handler):
c = {
"out_path_hash_mode": "-1",
"out_path": "01020304",
"out_bytes_per_hop": 1,
}
message_handler._ensure_contact_meshcore_path_encoding(c)
assert c["out_path_hash_mode"] == 0
assert c["out_path_len"] == 4
assert (c["out_path_len"] | (c["out_path_hash_mode"] << 6)) == 0x04
class TestHandleNewContactAddContact:
"""handle_new_contact + mocked add_contact: path fields match wire encoding (no OverflowError)."""