use server time for advert freshness

This commit is contained in:
Jack Kingsman
2026-03-15 17:55:47 -07:00
parent 3f50a2ef07
commit 226dc4f59e
32 changed files with 29 additions and 7 deletions
+4 -3
View File
@@ -477,8 +477,9 @@ async def _process_advertisement(
path_len,
)
# Use device_role from advertisement for contact type (1=Chat, 2=Repeater, 3=Room, 4=Sensor)
# Use advert.timestamp for last_advert (sender's timestamp), receive timestamp for last_seen
# Use device_role from advertisement for contact type (1=Chat, 2=Repeater, 3=Room, 4=Sensor).
# Persist advert freshness fields using the server receive wall clock so
# route selection is not affected by sender clock skew.
contact_type = (
advert.device_role if advert.device_role > 0 else (existing.type if existing else 0)
)
@@ -498,7 +499,7 @@ async def _process_advertisement(
type=contact_type,
lat=advert.lat,
lon=advert.lon,
last_advert=advert.timestamp if advert.timestamp > 0 else timestamp,
last_advert=timestamp,
last_seen=timestamp,
last_path=path_hex,
last_path_len=path_len,
Binary file not shown.
Binary file not shown.
Binary file not shown.
+25 -4
View File
@@ -355,10 +355,10 @@ class TestAdvertisementPipeline:
assert contact.last_path_len == 1 # Still the shorter path
@pytest.mark.asyncio
async def test_advertisement_path_freshness_uses_last_advert_not_last_seen(
async def test_advertisement_path_freshness_uses_receive_time_not_sender_clock(
self, test_db, captured_broadcasts
):
"""Non-advert contact activity should not keep an old advert path artificially fresh."""
"""Sender clock skew should not keep an old advert path artificially fresh."""
from unittest.mock import MagicMock
from app.decoder import ParsedAdvertisement
@@ -385,22 +385,43 @@ class TestAdvertisementPipeline:
longer_packet_info.path_hash_size = 1
longer_packet_info.payload = b""
skewed_shorter_packet_info = MagicMock()
skewed_shorter_packet_info.path_length = 1
skewed_shorter_packet_info.path = bytes.fromhex("aa")
skewed_shorter_packet_info.path_hash_size = 1
skewed_shorter_packet_info.payload = b""
with patch("app.packet_processor.broadcast_event", mock_broadcast):
with patch("app.packet_processor.parse_advertisement") as mock_parse:
mock_parse.return_value = ParsedAdvertisement(
public_key=test_pubkey,
name="TestNode",
timestamp=1070,
timestamp=5000,
lat=None,
lon=None,
device_role=1,
)
await _process_advertisement(b"", timestamp=1070, packet_info=longer_packet_info)
await _process_advertisement(
b"", timestamp=1070, packet_info=skewed_shorter_packet_info
)
with patch("app.packet_processor.broadcast_event", mock_broadcast):
with patch("app.packet_processor.parse_advertisement") as mock_parse:
mock_parse.return_value = ParsedAdvertisement(
public_key=test_pubkey,
name="TestNode",
timestamp=5005,
lat=None,
lon=None,
device_role=1,
)
await _process_advertisement(b"", timestamp=1200, packet_info=longer_packet_info)
contact = await ContactRepository.get_by_key(test_pubkey)
assert contact is not None
assert contact.last_path_len == 3
assert contact.last_path == "aabbcc"
assert contact.last_advert == 1200
@pytest.mark.asyncio
async def test_advertisement_default_path_len_treated_as_infinity(