test_state.py 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720
  1. # -*- coding: utf-8 -*-
  2. # Copyright 2014-2016 OpenMarket Ltd
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. from mock import Mock
  16. from twisted.internet import defer
  17. from synapse.api.auth import Auth
  18. from synapse.api.constants import EventTypes, Membership
  19. from synapse.api.room_versions import RoomVersions
  20. from synapse.events import make_event_from_dict
  21. from synapse.events.snapshot import EventContext
  22. from synapse.state import StateHandler, StateResolutionHandler
  23. from tests import unittest
  24. from .utils import MockClock, default_config
  25. _next_event_id = 1000
  26. def create_event(
  27. name=None,
  28. type=None,
  29. state_key=None,
  30. depth=2,
  31. event_id=None,
  32. prev_events=[],
  33. **kwargs
  34. ):
  35. global _next_event_id
  36. if not event_id:
  37. _next_event_id += 1
  38. event_id = "$%s:test" % (_next_event_id,)
  39. if not name:
  40. if state_key is not None:
  41. name = "<%s-%s, %s>" % (type, state_key, event_id)
  42. else:
  43. name = "<%s, %s>" % (type, event_id)
  44. d = {
  45. "event_id": event_id,
  46. "type": type,
  47. "sender": "@user_id:example.com",
  48. "room_id": "!room_id:example.com",
  49. "depth": depth,
  50. "prev_events": prev_events,
  51. }
  52. if state_key is not None:
  53. d["state_key"] = state_key
  54. d.update(kwargs)
  55. event = make_event_from_dict(d)
  56. return event
  57. class StateGroupStore:
  58. def __init__(self):
  59. self._event_to_state_group = {}
  60. self._group_to_state = {}
  61. self._event_id_to_event = {}
  62. self._next_group = 1
  63. async def get_state_groups_ids(self, room_id, event_ids):
  64. groups = {}
  65. for event_id in event_ids:
  66. group = self._event_to_state_group.get(event_id)
  67. if group:
  68. groups[group] = self._group_to_state[group]
  69. return groups
  70. async def store_state_group(
  71. self, event_id, room_id, prev_group, delta_ids, current_state_ids
  72. ):
  73. state_group = self._next_group
  74. self._next_group += 1
  75. self._group_to_state[state_group] = dict(current_state_ids)
  76. return state_group
  77. async def get_events(self, event_ids, **kwargs):
  78. return {
  79. e_id: self._event_id_to_event[e_id]
  80. for e_id in event_ids
  81. if e_id in self._event_id_to_event
  82. }
  83. async def get_state_group_delta(self, name):
  84. return (None, None)
  85. def register_events(self, events):
  86. for e in events:
  87. self._event_id_to_event[e.event_id] = e
  88. def register_event_context(self, event, context):
  89. self._event_to_state_group[event.event_id] = context.state_group
  90. def register_event_id_state_group(self, event_id, state_group):
  91. self._event_to_state_group[event_id] = state_group
  92. async def get_room_version_id(self, room_id):
  93. return RoomVersions.V1.identifier
  94. class DictObj(dict):
  95. def __init__(self, **kwargs):
  96. super().__init__(kwargs)
  97. self.__dict__ = self
  98. class Graph:
  99. def __init__(self, nodes, edges):
  100. events = {}
  101. clobbered = set(events.keys())
  102. for event_id, fields in nodes.items():
  103. refs = edges.get(event_id)
  104. if refs:
  105. clobbered.difference_update(refs)
  106. prev_events = [(r, {}) for r in refs]
  107. else:
  108. prev_events = []
  109. events[event_id] = create_event(
  110. event_id=event_id, prev_events=prev_events, **fields
  111. )
  112. self._leaves = clobbered
  113. self._events = sorted(events.values(), key=lambda e: e.depth)
  114. def walk(self):
  115. return iter(self._events)
  116. def get_leaves(self):
  117. return (self._events[i] for i in self._leaves)
  118. class StateTestCase(unittest.TestCase):
  119. def setUp(self):
  120. self.store = StateGroupStore()
  121. storage = Mock(main=self.store, state=self.store)
  122. hs = Mock(
  123. spec_set=[
  124. "config",
  125. "get_datastore",
  126. "get_storage",
  127. "get_auth",
  128. "get_state_handler",
  129. "get_clock",
  130. "get_state_resolution_handler",
  131. "hostname",
  132. ]
  133. )
  134. hs.config = default_config("tesths", True)
  135. hs.get_datastore.return_value = self.store
  136. hs.get_state_handler.return_value = None
  137. hs.get_clock.return_value = MockClock()
  138. hs.get_auth.return_value = Auth(hs)
  139. hs.get_state_resolution_handler = lambda: StateResolutionHandler(hs)
  140. hs.get_storage.return_value = storage
  141. self.state = StateHandler(hs)
  142. self.event_id = 0
  143. @defer.inlineCallbacks
  144. def test_branch_no_conflict(self):
  145. graph = Graph(
  146. nodes={
  147. "START": DictObj(
  148. type=EventTypes.Create, state_key="", content={}, depth=1
  149. ),
  150. "A": DictObj(type=EventTypes.Message, depth=2),
  151. "B": DictObj(type=EventTypes.Message, depth=3),
  152. "C": DictObj(type=EventTypes.Name, state_key="", depth=3),
  153. "D": DictObj(type=EventTypes.Message, depth=4),
  154. },
  155. edges={"A": ["START"], "B": ["A"], "C": ["A"], "D": ["B", "C"]},
  156. )
  157. self.store.register_events(graph.walk())
  158. context_store = {} # type: dict[str, EventContext]
  159. for event in graph.walk():
  160. context = yield defer.ensureDeferred(
  161. self.state.compute_event_context(event)
  162. )
  163. self.store.register_event_context(event, context)
  164. context_store[event.event_id] = context
  165. ctx_c = context_store["C"]
  166. ctx_d = context_store["D"]
  167. prev_state_ids = yield defer.ensureDeferred(ctx_d.get_prev_state_ids())
  168. self.assertEqual(2, len(prev_state_ids))
  169. self.assertEqual(ctx_c.state_group, ctx_d.state_group_before_event)
  170. self.assertEqual(ctx_d.state_group_before_event, ctx_d.state_group)
  171. @defer.inlineCallbacks
  172. def test_branch_basic_conflict(self):
  173. graph = Graph(
  174. nodes={
  175. "START": DictObj(
  176. type=EventTypes.Create,
  177. state_key="",
  178. content={"creator": "@user_id:example.com"},
  179. depth=1,
  180. ),
  181. "A": DictObj(
  182. type=EventTypes.Member,
  183. state_key="@user_id:example.com",
  184. content={"membership": Membership.JOIN},
  185. membership=Membership.JOIN,
  186. depth=2,
  187. ),
  188. "B": DictObj(type=EventTypes.Name, state_key="", depth=3),
  189. "C": DictObj(type=EventTypes.Name, state_key="", depth=4),
  190. "D": DictObj(type=EventTypes.Message, depth=5),
  191. },
  192. edges={"A": ["START"], "B": ["A"], "C": ["A"], "D": ["B", "C"]},
  193. )
  194. self.store.register_events(graph.walk())
  195. context_store = {}
  196. for event in graph.walk():
  197. context = yield defer.ensureDeferred(
  198. self.state.compute_event_context(event)
  199. )
  200. self.store.register_event_context(event, context)
  201. context_store[event.event_id] = context
  202. # C ends up winning the resolution between B and C
  203. ctx_c = context_store["C"]
  204. ctx_d = context_store["D"]
  205. prev_state_ids = yield defer.ensureDeferred(ctx_d.get_prev_state_ids())
  206. self.assertSetEqual({"START", "A", "C"}, set(prev_state_ids.values()))
  207. self.assertEqual(ctx_c.state_group, ctx_d.state_group_before_event)
  208. self.assertEqual(ctx_d.state_group_before_event, ctx_d.state_group)
  209. @defer.inlineCallbacks
  210. def test_branch_have_banned_conflict(self):
  211. graph = Graph(
  212. nodes={
  213. "START": DictObj(
  214. type=EventTypes.Create,
  215. state_key="",
  216. content={"creator": "@user_id:example.com"},
  217. depth=1,
  218. ),
  219. "A": DictObj(
  220. type=EventTypes.Member,
  221. state_key="@user_id:example.com",
  222. content={"membership": Membership.JOIN},
  223. membership=Membership.JOIN,
  224. depth=2,
  225. ),
  226. "B": DictObj(type=EventTypes.Name, state_key="", depth=3),
  227. "C": DictObj(
  228. type=EventTypes.Member,
  229. state_key="@user_id_2:example.com",
  230. content={"membership": Membership.BAN},
  231. membership=Membership.BAN,
  232. depth=4,
  233. ),
  234. "D": DictObj(
  235. type=EventTypes.Name,
  236. state_key="",
  237. depth=4,
  238. sender="@user_id_2:example.com",
  239. ),
  240. "E": DictObj(type=EventTypes.Message, depth=5),
  241. },
  242. edges={"A": ["START"], "B": ["A"], "C": ["B"], "D": ["B"], "E": ["C", "D"]},
  243. )
  244. self.store.register_events(graph.walk())
  245. context_store = {}
  246. for event in graph.walk():
  247. context = yield defer.ensureDeferred(
  248. self.state.compute_event_context(event)
  249. )
  250. self.store.register_event_context(event, context)
  251. context_store[event.event_id] = context
  252. # C ends up winning the resolution between C and D because bans win over other
  253. # changes
  254. ctx_c = context_store["C"]
  255. ctx_e = context_store["E"]
  256. prev_state_ids = yield defer.ensureDeferred(ctx_e.get_prev_state_ids())
  257. self.assertSetEqual({"START", "A", "B", "C"}, set(prev_state_ids.values()))
  258. self.assertEqual(ctx_c.state_group, ctx_e.state_group_before_event)
  259. self.assertEqual(ctx_e.state_group_before_event, ctx_e.state_group)
  260. @defer.inlineCallbacks
  261. def test_branch_have_perms_conflict(self):
  262. userid1 = "@user_id:example.com"
  263. userid2 = "@user_id2:example.com"
  264. nodes = {
  265. "A1": DictObj(
  266. type=EventTypes.Create,
  267. state_key="",
  268. content={"creator": userid1},
  269. depth=1,
  270. ),
  271. "A2": DictObj(
  272. type=EventTypes.Member,
  273. state_key=userid1,
  274. content={"membership": Membership.JOIN},
  275. membership=Membership.JOIN,
  276. ),
  277. "A3": DictObj(
  278. type=EventTypes.Member,
  279. state_key=userid2,
  280. content={"membership": Membership.JOIN},
  281. membership=Membership.JOIN,
  282. ),
  283. "A4": DictObj(
  284. type=EventTypes.PowerLevels,
  285. state_key="",
  286. content={
  287. "events": {"m.room.name": 50},
  288. "users": {userid1: 100, userid2: 60},
  289. },
  290. ),
  291. "A5": DictObj(type=EventTypes.Name, state_key=""),
  292. "B": DictObj(
  293. type=EventTypes.PowerLevels,
  294. state_key="",
  295. content={"events": {"m.room.name": 50}, "users": {userid2: 30}},
  296. ),
  297. "C": DictObj(type=EventTypes.Name, state_key="", sender=userid2),
  298. "D": DictObj(type=EventTypes.Message),
  299. }
  300. edges = {
  301. "A2": ["A1"],
  302. "A3": ["A2"],
  303. "A4": ["A3"],
  304. "A5": ["A4"],
  305. "B": ["A5"],
  306. "C": ["A5"],
  307. "D": ["B", "C"],
  308. }
  309. self._add_depths(nodes, edges)
  310. graph = Graph(nodes, edges)
  311. self.store.register_events(graph.walk())
  312. context_store = {}
  313. for event in graph.walk():
  314. context = yield defer.ensureDeferred(
  315. self.state.compute_event_context(event)
  316. )
  317. self.store.register_event_context(event, context)
  318. context_store[event.event_id] = context
  319. # B ends up winning the resolution between B and C because power levels
  320. # win over other changes.
  321. ctx_b = context_store["B"]
  322. ctx_d = context_store["D"]
  323. prev_state_ids = yield defer.ensureDeferred(ctx_d.get_prev_state_ids())
  324. self.assertSetEqual({"A1", "A2", "A3", "A5", "B"}, set(prev_state_ids.values()))
  325. self.assertEqual(ctx_b.state_group, ctx_d.state_group_before_event)
  326. self.assertEqual(ctx_d.state_group_before_event, ctx_d.state_group)
  327. def _add_depths(self, nodes, edges):
  328. def _get_depth(ev):
  329. node = nodes[ev]
  330. if "depth" not in node:
  331. prevs = edges[ev]
  332. depth = max(_get_depth(prev) for prev in prevs) + 1
  333. node["depth"] = depth
  334. return node["depth"]
  335. for n in nodes:
  336. _get_depth(n)
  337. @defer.inlineCallbacks
  338. def test_annotate_with_old_message(self):
  339. event = create_event(type="test_message", name="event")
  340. old_state = [
  341. create_event(type="test1", state_key="1"),
  342. create_event(type="test1", state_key="2"),
  343. create_event(type="test2", state_key=""),
  344. ]
  345. context = yield defer.ensureDeferred(
  346. self.state.compute_event_context(event, old_state=old_state)
  347. )
  348. prev_state_ids = yield defer.ensureDeferred(context.get_prev_state_ids())
  349. self.assertCountEqual((e.event_id for e in old_state), prev_state_ids.values())
  350. current_state_ids = yield defer.ensureDeferred(context.get_current_state_ids())
  351. self.assertCountEqual(
  352. (e.event_id for e in old_state), current_state_ids.values()
  353. )
  354. self.assertIsNotNone(context.state_group_before_event)
  355. self.assertEqual(context.state_group_before_event, context.state_group)
  356. @defer.inlineCallbacks
  357. def test_annotate_with_old_state(self):
  358. event = create_event(type="state", state_key="", name="event")
  359. old_state = [
  360. create_event(type="test1", state_key="1"),
  361. create_event(type="test1", state_key="2"),
  362. create_event(type="test2", state_key=""),
  363. ]
  364. context = yield defer.ensureDeferred(
  365. self.state.compute_event_context(event, old_state=old_state)
  366. )
  367. prev_state_ids = yield defer.ensureDeferred(context.get_prev_state_ids())
  368. self.assertCountEqual((e.event_id for e in old_state), prev_state_ids.values())
  369. current_state_ids = yield defer.ensureDeferred(context.get_current_state_ids())
  370. self.assertCountEqual(
  371. (e.event_id for e in old_state + [event]), current_state_ids.values()
  372. )
  373. self.assertIsNotNone(context.state_group_before_event)
  374. self.assertNotEqual(context.state_group_before_event, context.state_group)
  375. self.assertEqual(context.state_group_before_event, context.prev_group)
  376. self.assertEqual({("state", ""): event.event_id}, context.delta_ids)
  377. @defer.inlineCallbacks
  378. def test_trivial_annotate_message(self):
  379. prev_event_id = "prev_event_id"
  380. event = create_event(
  381. type="test_message", name="event2", prev_events=[(prev_event_id, {})]
  382. )
  383. old_state = [
  384. create_event(type="test1", state_key="1"),
  385. create_event(type="test1", state_key="2"),
  386. create_event(type="test2", state_key=""),
  387. ]
  388. group_name = yield defer.ensureDeferred(
  389. self.store.store_state_group(
  390. prev_event_id,
  391. event.room_id,
  392. None,
  393. None,
  394. {(e.type, e.state_key): e.event_id for e in old_state},
  395. )
  396. )
  397. self.store.register_event_id_state_group(prev_event_id, group_name)
  398. context = yield defer.ensureDeferred(self.state.compute_event_context(event))
  399. current_state_ids = yield defer.ensureDeferred(context.get_current_state_ids())
  400. self.assertEqual(
  401. {e.event_id for e in old_state}, set(current_state_ids.values())
  402. )
  403. self.assertEqual(group_name, context.state_group)
  404. @defer.inlineCallbacks
  405. def test_trivial_annotate_state(self):
  406. prev_event_id = "prev_event_id"
  407. event = create_event(
  408. type="state", state_key="", name="event2", prev_events=[(prev_event_id, {})]
  409. )
  410. old_state = [
  411. create_event(type="test1", state_key="1"),
  412. create_event(type="test1", state_key="2"),
  413. create_event(type="test2", state_key=""),
  414. ]
  415. group_name = yield defer.ensureDeferred(
  416. self.store.store_state_group(
  417. prev_event_id,
  418. event.room_id,
  419. None,
  420. None,
  421. {(e.type, e.state_key): e.event_id for e in old_state},
  422. )
  423. )
  424. self.store.register_event_id_state_group(prev_event_id, group_name)
  425. context = yield defer.ensureDeferred(self.state.compute_event_context(event))
  426. prev_state_ids = yield defer.ensureDeferred(context.get_prev_state_ids())
  427. self.assertEqual({e.event_id for e in old_state}, set(prev_state_ids.values()))
  428. self.assertIsNotNone(context.state_group)
  429. @defer.inlineCallbacks
  430. def test_resolve_message_conflict(self):
  431. prev_event_id1 = "event_id1"
  432. prev_event_id2 = "event_id2"
  433. event = create_event(
  434. type="test_message",
  435. name="event3",
  436. prev_events=[(prev_event_id1, {}), (prev_event_id2, {})],
  437. )
  438. creation = create_event(type=EventTypes.Create, state_key="")
  439. old_state_1 = [
  440. creation,
  441. create_event(type="test1", state_key="1"),
  442. create_event(type="test1", state_key="2"),
  443. create_event(type="test2", state_key=""),
  444. ]
  445. old_state_2 = [
  446. creation,
  447. create_event(type="test1", state_key="1"),
  448. create_event(type="test3", state_key="2"),
  449. create_event(type="test4", state_key=""),
  450. ]
  451. self.store.register_events(old_state_1)
  452. self.store.register_events(old_state_2)
  453. context = yield self._get_context(
  454. event, prev_event_id1, old_state_1, prev_event_id2, old_state_2
  455. )
  456. current_state_ids = yield defer.ensureDeferred(context.get_current_state_ids())
  457. self.assertEqual(len(current_state_ids), 6)
  458. self.assertIsNotNone(context.state_group)
  459. @defer.inlineCallbacks
  460. def test_resolve_state_conflict(self):
  461. prev_event_id1 = "event_id1"
  462. prev_event_id2 = "event_id2"
  463. event = create_event(
  464. type="test4",
  465. state_key="",
  466. name="event",
  467. prev_events=[(prev_event_id1, {}), (prev_event_id2, {})],
  468. )
  469. creation = create_event(type=EventTypes.Create, state_key="")
  470. old_state_1 = [
  471. creation,
  472. create_event(type="test1", state_key="1"),
  473. create_event(type="test1", state_key="2"),
  474. create_event(type="test2", state_key=""),
  475. ]
  476. old_state_2 = [
  477. creation,
  478. create_event(type="test1", state_key="1"),
  479. create_event(type="test3", state_key="2"),
  480. create_event(type="test4", state_key=""),
  481. ]
  482. store = StateGroupStore()
  483. store.register_events(old_state_1)
  484. store.register_events(old_state_2)
  485. self.store.get_events = store.get_events
  486. context = yield self._get_context(
  487. event, prev_event_id1, old_state_1, prev_event_id2, old_state_2
  488. )
  489. current_state_ids = yield defer.ensureDeferred(context.get_current_state_ids())
  490. self.assertEqual(len(current_state_ids), 6)
  491. self.assertIsNotNone(context.state_group)
  492. @defer.inlineCallbacks
  493. def test_standard_depth_conflict(self):
  494. prev_event_id1 = "event_id1"
  495. prev_event_id2 = "event_id2"
  496. event = create_event(
  497. type="test4",
  498. name="event",
  499. prev_events=[(prev_event_id1, {}), (prev_event_id2, {})],
  500. )
  501. member_event = create_event(
  502. type=EventTypes.Member,
  503. state_key="@user_id:example.com",
  504. content={"membership": Membership.JOIN},
  505. )
  506. power_levels = create_event(
  507. type=EventTypes.PowerLevels,
  508. state_key="",
  509. content={"users": {"@foo:bar": "100", "@user_id:example.com": "100"}},
  510. )
  511. creation = create_event(
  512. type=EventTypes.Create, state_key="", content={"creator": "@foo:bar"}
  513. )
  514. old_state_1 = [
  515. creation,
  516. power_levels,
  517. member_event,
  518. create_event(type="test1", state_key="1", depth=1),
  519. ]
  520. old_state_2 = [
  521. creation,
  522. power_levels,
  523. member_event,
  524. create_event(type="test1", state_key="1", depth=2),
  525. ]
  526. store = StateGroupStore()
  527. store.register_events(old_state_1)
  528. store.register_events(old_state_2)
  529. self.store.get_events = store.get_events
  530. context = yield self._get_context(
  531. event, prev_event_id1, old_state_1, prev_event_id2, old_state_2
  532. )
  533. current_state_ids = yield defer.ensureDeferred(context.get_current_state_ids())
  534. self.assertEqual(old_state_2[3].event_id, current_state_ids[("test1", "1")])
  535. # Reverse the depth to make sure we are actually using the depths
  536. # during state resolution.
  537. old_state_1 = [
  538. creation,
  539. power_levels,
  540. member_event,
  541. create_event(type="test1", state_key="1", depth=2),
  542. ]
  543. old_state_2 = [
  544. creation,
  545. power_levels,
  546. member_event,
  547. create_event(type="test1", state_key="1", depth=1),
  548. ]
  549. store.register_events(old_state_1)
  550. store.register_events(old_state_2)
  551. context = yield self._get_context(
  552. event, prev_event_id1, old_state_1, prev_event_id2, old_state_2
  553. )
  554. current_state_ids = yield defer.ensureDeferred(context.get_current_state_ids())
  555. self.assertEqual(old_state_1[3].event_id, current_state_ids[("test1", "1")])
  556. @defer.inlineCallbacks
  557. def _get_context(
  558. self, event, prev_event_id_1, old_state_1, prev_event_id_2, old_state_2
  559. ):
  560. sg1 = yield defer.ensureDeferred(
  561. self.store.store_state_group(
  562. prev_event_id_1,
  563. event.room_id,
  564. None,
  565. None,
  566. {(e.type, e.state_key): e.event_id for e in old_state_1},
  567. )
  568. )
  569. self.store.register_event_id_state_group(prev_event_id_1, sg1)
  570. sg2 = yield defer.ensureDeferred(
  571. self.store.store_state_group(
  572. prev_event_id_2,
  573. event.room_id,
  574. None,
  575. None,
  576. {(e.type, e.state_key): e.event_id for e in old_state_2},
  577. )
  578. )
  579. self.store.register_event_id_state_group(prev_event_id_2, sg2)
  580. result = yield defer.ensureDeferred(self.state.compute_event_context(event))
  581. return result