Skip to content
This repository was archived by the owner on Apr 26, 2024. It is now read-only.

Commit 85551b7

Browse files
authored
Factor out common code for persisting fetched auth events (#10896)
* Factor more stuff out of `_get_events_and_persist` It turns out that the event-sorting algorithm in `_get_events_and_persist` is also useful in other circumstances. Here we move the current `_auth_and_persist_fetched_events` to `_auth_and_persist_fetched_events_inner`, and then factor the sorting part out to `_auth_and_persist_fetched_events`. * `_get_remote_auth_chain_for_event`: remove redundant `outlier` assignment `get_event_auth` returns events with the outlier flag already set, so this is redundant (though we need to update a test where `get_event_auth` is mocked). * `_get_remote_auth_chain_for_event`: move existing-event tests earlier Move a couple of tests outside the loop. This is a bit inefficient for now, but a future commit will make it better. It should be functionally identical. * `_get_remote_auth_chain_for_event`: use `_auth_and_persist_fetched_events` We can use the same codepath for persisting the events fetched as part of an auth chain as for those fetched individually by `_get_events_and_persist` for building the state at a backwards extremity. * `_get_remote_auth_chain_for_event`: use a dict for efficiency `_auth_and_persist_fetched_events` sorts the events itself, so we no longer need to care about maintaining the ordering from `get_event_auth` (and no longer need to sort by depth in `get_event_auth`). That means that we can use a map, making it easier to filter out events we already have, etc. * changelog * `_auth_and_persist_fetched_events`: improve docstring
1 parent 261c976 commit 85551b7

File tree

4 files changed

+55
-58
lines changed

4 files changed

+55
-58
lines changed

changelog.d/10896.misc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Clean up some of the federation event authentication code for clarity.

synapse/federation/federation_client.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -501,8 +501,6 @@ async def get_event_auth(
501501
destination, auth_chain, outlier=True, room_version=room_version
502502
)
503503

504-
signed_auth.sort(key=lambda e: e.depth)
505-
506504
return signed_auth
507505

508506
def _is_unknown_endpoint(

synapse/handlers/federation_event.py

Lines changed: 48 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1080,7 +1080,7 @@ async def _get_events_and_persist(
10801080

10811081
room_version = await self._store.get_room_version(room_id)
10821082

1083-
event_map: Dict[str, EventBase] = {}
1083+
events: List[EventBase] = []
10841084

10851085
async def get_event(event_id: str) -> None:
10861086
with nested_logging_context(event_id):
@@ -1098,8 +1098,7 @@ async def get_event(event_id: str) -> None:
10981098
event_id,
10991099
)
11001100
return
1101-
1102-
event_map[event.event_id] = event
1101+
events.append(event)
11031102

11041103
except Exception as e:
11051104
logger.warning(
@@ -1110,11 +1109,29 @@ async def get_event(event_id: str) -> None:
11101109
)
11111110

11121111
await concurrently_execute(get_event, event_ids, 5)
1113-
logger.info("Fetched %i events of %i requested", len(event_map), len(event_ids))
1112+
logger.info("Fetched %i events of %i requested", len(events), len(event_ids))
1113+
await self._auth_and_persist_fetched_events(destination, room_id, events)
1114+
1115+
async def _auth_and_persist_fetched_events(
1116+
self, origin: str, room_id: str, events: Iterable[EventBase]
1117+
) -> None:
1118+
"""Persist the events fetched by _get_events_and_persist or _get_remote_auth_chain_for_event
1119+
1120+
The events to be persisted must be outliers.
1121+
1122+
We first sort the events to make sure that we process each event's auth_events
1123+
before the event itself, and then auth and persist them.
1124+
1125+
Notifies about the events where appropriate.
1126+
1127+
Params:
1128+
origin: where the events came from
1129+
room_id: the room that the events are meant to be in (though this has
1130+
not yet been checked)
1131+
events: the events that have been fetched
1132+
"""
1133+
event_map = {event.event_id: event for event in events}
11141134

1115-
# we now need to auth the events in an order which ensures that each event's
1116-
# auth_events are authed before the event itself.
1117-
#
11181135
# XXX: it might be possible to kick this process off in parallel with fetching
11191136
# the events.
11201137
while event_map:
@@ -1141,30 +1158,26 @@ async def get_event(event_id: str) -> None:
11411158
"Persisting %i of %i remaining events", len(roots), len(event_map)
11421159
)
11431160

1144-
await self._auth_and_persist_fetched_events(destination, room_id, roots)
1161+
await self._auth_and_persist_fetched_events_inner(origin, room_id, roots)
11451162

11461163
for ev in roots:
11471164
del event_map[ev.event_id]
11481165

1149-
async def _auth_and_persist_fetched_events(
1166+
async def _auth_and_persist_fetched_events_inner(
11501167
self, origin: str, room_id: str, fetched_events: Collection[EventBase]
11511168
) -> None:
1152-
"""Persist the events fetched by _get_events_and_persist.
1169+
"""Helper for _auth_and_persist_fetched_events
11531170
1154-
The events should not depend on one another, e.g. this should be used to persist
1155-
a bunch of outliers, but not a chunk of individual events that depend
1156-
on each other for state calculations.
1157-
1158-
We also assume that all of the auth events for all of the events have already
1159-
been persisted.
1171+
Persists a batch of events where we have (theoretically) already persisted all
1172+
of their auth events.
11601173
11611174
Notifies about the events where appropriate.
11621175
11631176
Params:
11641177
origin: where the events came from
11651178
room_id: the room that the events are meant to be in (though this has
11661179
not yet been checked)
1167-
event_id: map from event_id -> event for the fetched events
1180+
fetched_events: the events to persist
11681181
"""
11691182
# get all the auth events for all the events in this batch. By now, they should
11701183
# have been persisted.
@@ -1558,53 +1571,33 @@ async def _get_remote_auth_chain_for_event(
15581571
event_id: the event for which we are lacking auth events
15591572
"""
15601573
try:
1561-
remote_auth_chain = await self._federation_client.get_event_auth(
1562-
destination, room_id, event_id
1563-
)
1574+
remote_event_map = {
1575+
e.event_id: e
1576+
for e in await self._federation_client.get_event_auth(
1577+
destination, room_id, event_id
1578+
)
1579+
}
15641580
except RequestSendFailed as e1:
15651581
# The other side isn't around or doesn't implement the
15661582
# endpoint, so lets just bail out.
15671583
logger.info("Failed to get event auth from remote: %s", e1)
15681584
return
15691585

1570-
seen_remotes = await self._store.have_seen_events(
1571-
room_id, [e.event_id for e in remote_auth_chain]
1572-
)
1586+
logger.info("/event_auth returned %i events", len(remote_event_map))
15731587

1574-
for auth_event in remote_auth_chain:
1575-
if auth_event.event_id in seen_remotes:
1576-
continue
1588+
# `event` may be returned, but we should not yet process it.
1589+
remote_event_map.pop(event_id, None)
15771590

1578-
if auth_event.event_id == event_id:
1579-
continue
1591+
# nor should we reprocess any events we have already seen.
1592+
seen_remotes = await self._store.have_seen_events(
1593+
room_id, remote_event_map.keys()
1594+
)
1595+
for s in seen_remotes:
1596+
remote_event_map.pop(s, None)
15801597

1581-
try:
1582-
auth_ids = auth_event.auth_event_ids()
1583-
auth = {
1584-
(e.type, e.state_key): e
1585-
for e in remote_auth_chain
1586-
if e.event_id in auth_ids or e.type == EventTypes.Create
1587-
}
1588-
auth_event.internal_metadata.outlier = True
1589-
1590-
logger.debug(
1591-
"_check_event_auth %s missing_auth: %s",
1592-
event_id,
1593-
auth_event.event_id,
1594-
)
1595-
missing_auth_event_context = EventContext.for_outlier()
1596-
missing_auth_event_context = await self._check_event_auth(
1597-
destination,
1598-
auth_event,
1599-
missing_auth_event_context,
1600-
claimed_auth_event_map=auth,
1601-
)
1602-
await self.persist_events_and_notify(
1603-
room_id,
1604-
[(auth_event, missing_auth_event_context)],
1605-
)
1606-
except AuthError:
1607-
pass
1598+
await self._auth_and_persist_fetched_events(
1599+
destination, room_id, remote_event_map.values()
1600+
)
16081601

16091602
async def _update_context_for_auth_events(
16101603
self, event: EventBase, context: EventContext, auth_events: StateMap[EventBase]

tests/handlers/test_federation.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,12 @@ def test_backfill_floating_outlier_membership_auth(self):
308308
async def get_event_auth(
309309
destination: str, room_id: str, event_id: str
310310
) -> List[EventBase]:
311-
return auth_events
311+
return [
312+
event_from_pdu_json(
313+
ae.get_pdu_json(), room_version=room_version, outlier=True
314+
)
315+
for ae in auth_events
316+
]
312317

313318
self.handler.federation_client.get_event_auth = get_event_auth
314319

0 commit comments

Comments
 (0)