diff --git a/changelog.d/16968.bugfix b/changelog.d/16968.bugfix
new file mode 100644
index 0000000000..57ed851178
--- /dev/null
+++ b/changelog.d/16968.bugfix
@@ -0,0 +1 @@
+Prevent locking up when checking auth rules that are independent of room state for batched auth events. Contributed by @ggogel.
\ No newline at end of file
diff --git a/synapse/event_auth.py b/synapse/event_auth.py
index d922c8dc35..c8b06f760e 100644
--- a/synapse/event_auth.py
+++ b/synapse/event_auth.py
@@ -23,7 +23,20 @@
import collections.abc
import logging
import typing
-from typing import Any, Dict, Iterable, List, Mapping, Optional, Set, Tuple, Union
+from typing import (
+ Any,
+ ChainMap,
+ Dict,
+ Iterable,
+ List,
+ Mapping,
+ MutableMapping,
+ Optional,
+ Set,
+ Tuple,
+ Union,
+ cast,
+)
from canonicaljson import encode_canonical_json
from signedjson.key import decode_verify_key_bytes
@@ -175,12 +188,22 @@ async def check_state_independent_auth_rules(
return
# 2. Reject if event has auth_events that: ...
+ auth_events: ChainMap[str, EventBase] = ChainMap()
if batched_auth_events:
- # Copy the batched auth events to avoid mutating them.
- auth_events = dict(batched_auth_events)
- needed_auth_event_ids = set(event.auth_event_ids()) - batched_auth_events.keys()
+ # batched_auth_events can become very large. To avoid repeatedly copying it, which
+ # would significantly impact performance, we use a ChainMap.
+ # batched_auth_events must be cast to MutableMapping because .new_child() requires
+ # this type. This casting is safe as the mapping is never mutated.
+ auth_events = auth_events.new_child(
+ cast(MutableMapping[str, "EventBase"], batched_auth_events)
+ )
+ needed_auth_event_ids = [
+ event_id
+ for event_id in event.auth_event_ids()
+ if event_id not in batched_auth_events
+ ]
if needed_auth_event_ids:
- auth_events.update(
+ auth_events = auth_events.new_child(
await store.get_events(
needed_auth_event_ids,
redact_behaviour=EventRedactBehaviour.as_is,
@@ -188,10 +211,12 @@ async def check_state_independent_auth_rules(
)
)
else:
- auth_events = await store.get_events(
- event.auth_event_ids(),
- redact_behaviour=EventRedactBehaviour.as_is,
- allow_rejected=True,
+ auth_events = auth_events.new_child(
+ await store.get_events(
+ event.auth_event_ids(),
+ redact_behaviour=EventRedactBehaviour.as_is,
+ allow_rejected=True,
+ )
)
room_id = event.room_id
|