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

Commit

Permalink
Merge pull request #6343 from matrix-org/rav/event_auth/4
Browse files Browse the repository at this point in the history
* commit '651d930f1':
  remove confusing fixme
  newsfile
  Use get_events_as_list rather than lots of calls to get_event
  Update some docstrings and comments
  Simplify _update_auth_events_and_context_for_auth
  • Loading branch information
anoadragon453 committed Mar 18, 2020
2 parents 926fc8f + 651d930 commit 68096ca
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 37 deletions.
1 change: 1 addition & 0 deletions changelog.d/6343.misc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Refactor some code in the event authentication path for clarity.
81 changes: 44 additions & 37 deletions synapse/handlers/federation.py
Original file line number Diff line number Diff line change
Expand Up @@ -2047,8 +2047,10 @@ def do_auth(self, origin, event, context, auth_events):
auth_events (dict[(str, str)->synapse.events.EventBase]):
Map from (event_type, state_key) to event
What we expect the event's auth_events to be, based on the event's
position in the dag. I think? maybe??
Normally, our calculated auth_events based on the state of the room
at the event's position in the DAG, though occasionally (eg if the
event is an outlier), may be the auth events claimed by the remote
server.
Also NB that this function adds entries to it.
Returns:
Expand Down Expand Up @@ -2098,30 +2100,35 @@ def _update_auth_events_and_context_for_auth(
origin (str):
event (synapse.events.EventBase):
context (synapse.events.snapshot.EventContext):
auth_events (dict[(str, str)->synapse.events.EventBase]):
Map from (event_type, state_key) to event
Normally, our calculated auth_events based on the state of the room
at the event's position in the DAG, though occasionally (eg if the
event is an outlier), may be the auth events claimed by the remote
server.
Also NB that this function adds entries to it.
Returns:
defer.Deferred[EventContext]: updated context
"""
event_auth_events = set(event.auth_event_ids())

if event.is_state():
event_key = (event.type, event.state_key)
else:
event_key = None

# if the event's auth_events refers to events which are not in our
# calculated auth_events, we need to fetch those events from somewhere.
#
# we start by fetching them from the store, and then try calling /event_auth/.
# missing_auth is the set of the event's auth_events which we don't yet have
# in auth_events.
missing_auth = event_auth_events.difference(
e.event_id for e in auth_events.values()
)

# if we have missing events, we need to fetch those events from somewhere.
#
# we start by checking if they are in the store, and then try calling /event_auth/.
if missing_auth:
# TODO: can we use store.have_seen_events here instead?
have_events = yield self.store.get_seen_events_with_rejections(missing_auth)
logger.debug("Got events %s from store", have_events)
logger.debug("Found events %s in the store", have_events)
missing_auth.difference_update(have_events.keys())
else:
have_events = {}
Expand Down Expand Up @@ -2176,15 +2183,17 @@ def _update_auth_events_and_context_for_auth(
event.auth_event_ids()
)
except Exception:
# FIXME:
logger.exception("Failed to get auth chain")

if event.internal_metadata.is_outlier():
# XXX: given that, for an outlier, we'll be working with the
# event's *claimed* auth events rather than those we calculated:
# (a) is there any point in this test, since different_auth below will
# obviously be empty
# (b) alternatively, why don't we do it earlier?
logger.info("Skipping auth_event fetch for outlier")
return context

# FIXME: Assumes we have and stored all the state for all the
# prev_events
different_auth = event_auth_events.difference(
e.event_id for e in auth_events.values()
)
Expand All @@ -2198,27 +2207,22 @@ def _update_auth_events_and_context_for_auth(
different_auth,
)

# now we state-resolve between our own idea of the auth events, and the remote's
# idea of them.

room_version = yield self.store.get_room_version(event.room_id)
different_event_ids = [
d for d in different_auth if d in have_events and not have_events[d]
]

different_events = yield make_deferred_yieldable(
defer.gatherResults(
[
run_in_background(
self.store.get_event, d, allow_none=True, allow_rejected=False
)
for d in different_auth
if d in have_events and not have_events[d]
],
consumeErrors=True,
)
).addErrback(unwrapFirstError)
if different_event_ids:
# XXX: currently this checks for redactions but I'm not convinced that is
# necessary?
different_events = yield self.store.get_events_as_list(different_event_ids)

if different_events:
local_view = dict(auth_events)
remote_view = dict(auth_events)
remote_view.update(
{(d.type, d.state_key): d for d in different_events if d}
)
remote_view.update({(d.type, d.state_key): d for d in different_events})

new_state = yield self.state_handler.resolve_events(
room_version,
Expand All @@ -2238,13 +2242,13 @@ def _update_auth_events_and_context_for_auth(
auth_events.update(new_state)

context = yield self._update_context_for_auth_events(
event, context, auth_events, event_key
event, context, auth_events
)

return context

@defer.inlineCallbacks
def _update_context_for_auth_events(self, event, context, auth_events, event_key):
def _update_context_for_auth_events(self, event, context, auth_events):
"""Update the state_ids in an event context after auth event resolution,
storing the changes as a new state group.
Expand All @@ -2253,18 +2257,21 @@ def _update_context_for_auth_events(self, event, context, auth_events, event_key
context (synapse.events.snapshot.EventContext): initial event context
auth_events (dict[(str, str)->str]): Events to update in the event
auth_events (dict[(str, str)->EventBase]): Events to update in the event
context.
event_key ((str, str)): (type, state_key) for the current event.
this will not be included in the current_state in the context.
Returns:
Deferred[EventContext]: new event context
"""
# exclude the state key of the new event from the current_state in the context.
if event.is_state():
event_key = (event.type, event.state_key)
else:
event_key = None
state_updates = {
k: a.event_id for k, a in iteritems(auth_events) if k != event_key
}

current_state_ids = yield context.get_current_state_ids(self.store)
current_state_ids = dict(current_state_ids)

Expand Down

0 comments on commit 68096ca

Please sign in to comment.