Fix v12 rooms when using frozen dicts (#19235)

Fix #19233 

Synapse fails to handle events in v12 rooms when the server is run with
the `{use_frozen_dicts: True}` config.
This PR fixes the issue, and adds tests which cover room creation,
joining, and joining over federation, with both frozen and not frozen
config settings, by extending the existing `test_send_join` federation
tests.

This approach to testing was chosen as it is a simple way to get high
level integration style test coverage, without going through all our
existing tests and trying to retroactively add in coverage when using
frozen dicts.
This should provide an easy place for future room versions to extend the
suite of tests and reduce the chance of introducing subtle bugs like
this in the future.

### Pull Request Checklist

<!-- Please read
https://element-hq.github.io/synapse/latest/development/contributing_guide.html
before submitting your pull request -->

* [x] Pull request is based on the develop branch
* [x] Pull request includes a [changelog
file](https://element-hq.github.io/synapse/latest/development/contributing_guide.html#changelog).
The entry should:
- Be a short description of your change which makes sense to users.
"Fixed a bug that prevented receiving messages from other servers."
instead of "Moved X method from `EventStore` to `EventWorkerStore`.".
  - Use markdown where necessary, mostly for `code blocks`.
  - End with either a period (.) or an exclamation mark (!).
  - Start with a capital letter.
- Feel free to credit yourself, by adding a sentence "Contributed by
@github_username." or "Contributed by [Your Name]." to the end of the
entry.
* [x] [Code
style](https://element-hq.github.io/synapse/latest/code_style.html) is
correct (run the
[linters](https://element-hq.github.io/synapse/latest/development/contributing_guide.html#run-the-linters))
This commit is contained in:
Devon Hudson 2025-12-01 18:26:43 +00:00 committed by GitHub
parent afdf9af6b5
commit 08e1b63b30
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 49 additions and 12 deletions

1
changelog.d/19235.bugfix Normal file
View File

@ -0,0 +1 @@
Fix v12 rooms when running with `use_frozen_dicts: True`.

View File

@ -548,7 +548,7 @@ class FrozenEventV4(FrozenEventV3):
assert create_event_id not in self._dict["auth_events"] assert create_event_id not in self._dict["auth_events"]
if self.type == EventTypes.Create and self.get_state_key() == "": if self.type == EventTypes.Create and self.get_state_key() == "":
return self._dict["auth_events"] # should be [] return self._dict["auth_events"] # should be []
return self._dict["auth_events"] + [create_event_id] return [*self._dict["auth_events"], create_event_id]
def _event_type_from_format_version( def _event_type_from_format_version(

View File

@ -30,6 +30,7 @@ from synapse.api.constants import EventTypes, Membership
from synapse.api.errors import FederationError from synapse.api.errors import FederationError
from synapse.api.room_versions import KNOWN_ROOM_VERSIONS, RoomVersions from synapse.api.room_versions import KNOWN_ROOM_VERSIONS, RoomVersions
from synapse.config.server import DEFAULT_ROOM_VERSION from synapse.config.server import DEFAULT_ROOM_VERSION
from synapse.crypto.event_signing import add_hashes_and_signatures
from synapse.events import EventBase, make_event_from_dict from synapse.events import EventBase, make_event_from_dict
from synapse.federation.federation_base import event_from_pdu_json from synapse.federation.federation_base import event_from_pdu_json
from synapse.http.types import QueryParams from synapse.http.types import QueryParams
@ -356,19 +357,44 @@ class SendJoinFederationTests(unittest.FederatingHomeserverTestCase):
self.assertEqual(channel.code, HTTPStatus.OK, channel.json_body) self.assertEqual(channel.code, HTTPStatus.OK, channel.json_body)
return channel.json_body return channel.json_body
def test_send_join(self) -> None: def _test_send_join_common(self, room_version: str) -> None:
"""happy-path test of send_join""" """happy-path test of send_join"""
joining_user = "@misspiggy:" + self.OTHER_SERVER_NAME creator_user_id = self.register_user(f"kermit_v{room_version}", "test")
join_result = self._make_join(joining_user) tok = self.login(f"kermit_v{room_version}", "test")
room_id = self.helper.create_room_as(
room_creator=creator_user_id, tok=tok, room_version=room_version
)
# Second member joins
second_member_user_id = self.register_user(f"fozzie_v{room_version}", "bear")
tok2 = self.login(f"fozzie_v{room_version}", "bear")
self.helper.join(room_id, second_member_user_id, tok=tok2)
# Make join for remote user
joining_user = "@misspiggy:" + self.OTHER_SERVER_NAME
channel = self.make_signed_federation_request(
"GET",
f"/_matrix/federation/v1/make_join/{room_id}/{joining_user}?ver={room_version}",
)
self.assertEqual(channel.code, HTTPStatus.OK, channel.json_body)
join_result = channel.json_body
# Sign and send the join
join_event_dict = join_result["event"] join_event_dict = join_result["event"]
self.add_hashes_and_signatures_from_other_server( self.add_hashes_and_signatures_from_other_server(
join_event_dict, join_event_dict,
KNOWN_ROOM_VERSIONS[DEFAULT_ROOM_VERSION], KNOWN_ROOM_VERSIONS[room_version],
) )
if room_version in ["1", "2"]:
add_hashes_and_signatures(
KNOWN_ROOM_VERSIONS[room_version],
join_event_dict,
signature_name=self.hs.hostname,
signing_key=self.hs.signing_key,
)
channel = self.make_signed_federation_request( channel = self.make_signed_federation_request(
"PUT", "PUT",
f"/_matrix/federation/v2/send_join/{self._room_id}/x", f"/_matrix/federation/v2/send_join/{room_id}/x",
content=join_event_dict, content=join_event_dict,
) )
self.assertEqual(channel.code, HTTPStatus.OK, channel.json_body) self.assertEqual(channel.code, HTTPStatus.OK, channel.json_body)
@ -384,8 +410,8 @@ class SendJoinFederationTests(unittest.FederatingHomeserverTestCase):
("m.room.power_levels", ""), ("m.room.power_levels", ""),
("m.room.join_rules", ""), ("m.room.join_rules", ""),
("m.room.history_visibility", ""), ("m.room.history_visibility", ""),
("m.room.member", "@kermit:test"), ("m.room.member", f"@kermit_v{room_version}:test"),
("m.room.member", "@fozzie:test"), ("m.room.member", f"@fozzie_v{room_version}:test"),
# nb: *not* the joining user # nb: *not* the joining user
], ],
) )
@ -398,18 +424,28 @@ class SendJoinFederationTests(unittest.FederatingHomeserverTestCase):
returned_auth_chain_events, returned_auth_chain_events,
[ [
("m.room.create", ""), ("m.room.create", ""),
("m.room.member", "@kermit:test"), ("m.room.member", f"@kermit_v{room_version}:test"),
("m.room.power_levels", ""), ("m.room.power_levels", ""),
("m.room.join_rules", ""), ("m.room.join_rules", ""),
], ],
) )
# the room should show that the new user is a member # the room should show that the new user is a member
r = self.get_success( r = self.get_success(self._storage_controllers.state.get_current_state(room_id))
self._storage_controllers.state.get_current_state(self._room_id)
)
self.assertEqual(r[("m.room.member", joining_user)].membership, "join") self.assertEqual(r[("m.room.member", joining_user)].membership, "join")
@parameterized.expand([(k,) for k in KNOWN_ROOM_VERSIONS.keys()])
@override_config({"use_frozen_dicts": True})
def test_send_join_with_frozen_dicts(self, room_version: str) -> None:
"""Test send_join with USE_FROZEN_DICTS=True"""
self._test_send_join_common(room_version)
@parameterized.expand([(k,) for k in KNOWN_ROOM_VERSIONS.keys()])
@override_config({"use_frozen_dicts": False})
def test_send_join_without_frozen_dicts(self, room_version: str) -> None:
"""Test send_join with USE_FROZEN_DICTS=False"""
self._test_send_join_common(room_version)
def test_send_join_partial_state(self) -> None: def test_send_join_partial_state(self) -> None:
"""/send_join should return partial state, if requested""" """/send_join should return partial state, if requested"""
joining_user = "@misspiggy:" + self.OTHER_SERVER_NAME joining_user = "@misspiggy:" + self.OTHER_SERVER_NAME