1
0

test_state.py 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719
  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. ]
  132. )
  133. hs.config = default_config("tesths", True)
  134. hs.get_datastore.return_value = self.store
  135. hs.get_state_handler.return_value = None
  136. hs.get_clock.return_value = MockClock()
  137. hs.get_auth.return_value = Auth(hs)
  138. hs.get_state_resolution_handler = lambda: StateResolutionHandler(hs)
  139. hs.get_storage.return_value = storage
  140. self.state = StateHandler(hs)
  141. self.event_id = 0
  142. @defer.inlineCallbacks
  143. def test_branch_no_conflict(self):
  144. graph = Graph(
  145. nodes={
  146. "START": DictObj(
  147. type=EventTypes.Create, state_key="", content={}, depth=1
  148. ),
  149. "A": DictObj(type=EventTypes.Message, depth=2),
  150. "B": DictObj(type=EventTypes.Message, depth=3),
  151. "C": DictObj(type=EventTypes.Name, state_key="", depth=3),
  152. "D": DictObj(type=EventTypes.Message, depth=4),
  153. },
  154. edges={"A": ["START"], "B": ["A"], "C": ["A"], "D": ["B", "C"]},
  155. )
  156. self.store.register_events(graph.walk())
  157. context_store = {} # type: dict[str, EventContext]
  158. for event in graph.walk():
  159. context = yield defer.ensureDeferred(
  160. self.state.compute_event_context(event)
  161. )
  162. self.store.register_event_context(event, context)
  163. context_store[event.event_id] = context
  164. ctx_c = context_store["C"]
  165. ctx_d = context_store["D"]
  166. prev_state_ids = yield defer.ensureDeferred(ctx_d.get_prev_state_ids())
  167. self.assertEqual(2, len(prev_state_ids))
  168. self.assertEqual(ctx_c.state_group, ctx_d.state_group_before_event)
  169. self.assertEqual(ctx_d.state_group_before_event, ctx_d.state_group)
  170. @defer.inlineCallbacks
  171. def test_branch_basic_conflict(self):
  172. graph = Graph(
  173. nodes={
  174. "START": DictObj(
  175. type=EventTypes.Create,
  176. state_key="",
  177. content={"creator": "@user_id:example.com"},
  178. depth=1,
  179. ),
  180. "A": DictObj(
  181. type=EventTypes.Member,
  182. state_key="@user_id:example.com",
  183. content={"membership": Membership.JOIN},
  184. membership=Membership.JOIN,
  185. depth=2,
  186. ),
  187. "B": DictObj(type=EventTypes.Name, state_key="", depth=3),
  188. "C": DictObj(type=EventTypes.Name, state_key="", depth=4),
  189. "D": DictObj(type=EventTypes.Message, depth=5),
  190. },
  191. edges={"A": ["START"], "B": ["A"], "C": ["A"], "D": ["B", "C"]},
  192. )
  193. self.store.register_events(graph.walk())
  194. context_store = {}
  195. for event in graph.walk():
  196. context = yield defer.ensureDeferred(
  197. self.state.compute_event_context(event)
  198. )
  199. self.store.register_event_context(event, context)
  200. context_store[event.event_id] = context
  201. # C ends up winning the resolution between B and C
  202. ctx_c = context_store["C"]
  203. ctx_d = context_store["D"]
  204. prev_state_ids = yield defer.ensureDeferred(ctx_d.get_prev_state_ids())
  205. self.assertSetEqual({"START", "A", "C"}, set(prev_state_ids.values()))
  206. self.assertEqual(ctx_c.state_group, ctx_d.state_group_before_event)
  207. self.assertEqual(ctx_d.state_group_before_event, ctx_d.state_group)
  208. @defer.inlineCallbacks
  209. def test_branch_have_banned_conflict(self):
  210. graph = Graph(
  211. nodes={
  212. "START": DictObj(
  213. type=EventTypes.Create,
  214. state_key="",
  215. content={"creator": "@user_id:example.com"},
  216. depth=1,
  217. ),
  218. "A": DictObj(
  219. type=EventTypes.Member,
  220. state_key="@user_id:example.com",
  221. content={"membership": Membership.JOIN},
  222. membership=Membership.JOIN,
  223. depth=2,
  224. ),
  225. "B": DictObj(type=EventTypes.Name, state_key="", depth=3),
  226. "C": DictObj(
  227. type=EventTypes.Member,
  228. state_key="@user_id_2:example.com",
  229. content={"membership": Membership.BAN},
  230. membership=Membership.BAN,
  231. depth=4,
  232. ),
  233. "D": DictObj(
  234. type=EventTypes.Name,
  235. state_key="",
  236. depth=4,
  237. sender="@user_id_2:example.com",
  238. ),
  239. "E": DictObj(type=EventTypes.Message, depth=5),
  240. },
  241. edges={"A": ["START"], "B": ["A"], "C": ["B"], "D": ["B"], "E": ["C", "D"]},
  242. )
  243. self.store.register_events(graph.walk())
  244. context_store = {}
  245. for event in graph.walk():
  246. context = yield defer.ensureDeferred(
  247. self.state.compute_event_context(event)
  248. )
  249. self.store.register_event_context(event, context)
  250. context_store[event.event_id] = context
  251. # C ends up winning the resolution between C and D because bans win over other
  252. # changes
  253. ctx_c = context_store["C"]
  254. ctx_e = context_store["E"]
  255. prev_state_ids = yield defer.ensureDeferred(ctx_e.get_prev_state_ids())
  256. self.assertSetEqual({"START", "A", "B", "C"}, set(prev_state_ids.values()))
  257. self.assertEqual(ctx_c.state_group, ctx_e.state_group_before_event)
  258. self.assertEqual(ctx_e.state_group_before_event, ctx_e.state_group)
  259. @defer.inlineCallbacks
  260. def test_branch_have_perms_conflict(self):
  261. userid1 = "@user_id:example.com"
  262. userid2 = "@user_id2:example.com"
  263. nodes = {
  264. "A1": DictObj(
  265. type=EventTypes.Create,
  266. state_key="",
  267. content={"creator": userid1},
  268. depth=1,
  269. ),
  270. "A2": DictObj(
  271. type=EventTypes.Member,
  272. state_key=userid1,
  273. content={"membership": Membership.JOIN},
  274. membership=Membership.JOIN,
  275. ),
  276. "A3": DictObj(
  277. type=EventTypes.Member,
  278. state_key=userid2,
  279. content={"membership": Membership.JOIN},
  280. membership=Membership.JOIN,
  281. ),
  282. "A4": DictObj(
  283. type=EventTypes.PowerLevels,
  284. state_key="",
  285. content={
  286. "events": {"m.room.name": 50},
  287. "users": {userid1: 100, userid2: 60},
  288. },
  289. ),
  290. "A5": DictObj(type=EventTypes.Name, state_key=""),
  291. "B": DictObj(
  292. type=EventTypes.PowerLevels,
  293. state_key="",
  294. content={"events": {"m.room.name": 50}, "users": {userid2: 30}},
  295. ),
  296. "C": DictObj(type=EventTypes.Name, state_key="", sender=userid2),
  297. "D": DictObj(type=EventTypes.Message),
  298. }
  299. edges = {
  300. "A2": ["A1"],
  301. "A3": ["A2"],
  302. "A4": ["A3"],
  303. "A5": ["A4"],
  304. "B": ["A5"],
  305. "C": ["A5"],
  306. "D": ["B", "C"],
  307. }
  308. self._add_depths(nodes, edges)
  309. graph = Graph(nodes, edges)
  310. self.store.register_events(graph.walk())
  311. context_store = {}
  312. for event in graph.walk():
  313. context = yield defer.ensureDeferred(
  314. self.state.compute_event_context(event)
  315. )
  316. self.store.register_event_context(event, context)
  317. context_store[event.event_id] = context
  318. # B ends up winning the resolution between B and C because power levels
  319. # win over other changes.
  320. ctx_b = context_store["B"]
  321. ctx_d = context_store["D"]
  322. prev_state_ids = yield defer.ensureDeferred(ctx_d.get_prev_state_ids())
  323. self.assertSetEqual({"A1", "A2", "A3", "A5", "B"}, set(prev_state_ids.values()))
  324. self.assertEqual(ctx_b.state_group, ctx_d.state_group_before_event)
  325. self.assertEqual(ctx_d.state_group_before_event, ctx_d.state_group)
  326. def _add_depths(self, nodes, edges):
  327. def _get_depth(ev):
  328. node = nodes[ev]
  329. if "depth" not in node:
  330. prevs = edges[ev]
  331. depth = max(_get_depth(prev) for prev in prevs) + 1
  332. node["depth"] = depth
  333. return node["depth"]
  334. for n in nodes:
  335. _get_depth(n)
  336. @defer.inlineCallbacks
  337. def test_annotate_with_old_message(self):
  338. event = create_event(type="test_message", name="event")
  339. old_state = [
  340. create_event(type="test1", state_key="1"),
  341. create_event(type="test1", state_key="2"),
  342. create_event(type="test2", state_key=""),
  343. ]
  344. context = yield defer.ensureDeferred(
  345. self.state.compute_event_context(event, old_state=old_state)
  346. )
  347. prev_state_ids = yield defer.ensureDeferred(context.get_prev_state_ids())
  348. self.assertCountEqual((e.event_id for e in old_state), prev_state_ids.values())
  349. current_state_ids = yield defer.ensureDeferred(context.get_current_state_ids())
  350. self.assertCountEqual(
  351. (e.event_id for e in old_state), current_state_ids.values()
  352. )
  353. self.assertIsNotNone(context.state_group_before_event)
  354. self.assertEqual(context.state_group_before_event, context.state_group)
  355. @defer.inlineCallbacks
  356. def test_annotate_with_old_state(self):
  357. event = create_event(type="state", state_key="", name="event")
  358. old_state = [
  359. create_event(type="test1", state_key="1"),
  360. create_event(type="test1", state_key="2"),
  361. create_event(type="test2", state_key=""),
  362. ]
  363. context = yield defer.ensureDeferred(
  364. self.state.compute_event_context(event, old_state=old_state)
  365. )
  366. prev_state_ids = yield defer.ensureDeferred(context.get_prev_state_ids())
  367. self.assertCountEqual((e.event_id for e in old_state), prev_state_ids.values())
  368. current_state_ids = yield defer.ensureDeferred(context.get_current_state_ids())
  369. self.assertCountEqual(
  370. (e.event_id for e in old_state + [event]), current_state_ids.values()
  371. )
  372. self.assertIsNotNone(context.state_group_before_event)
  373. self.assertNotEqual(context.state_group_before_event, context.state_group)
  374. self.assertEqual(context.state_group_before_event, context.prev_group)
  375. self.assertEqual({("state", ""): event.event_id}, context.delta_ids)
  376. @defer.inlineCallbacks
  377. def test_trivial_annotate_message(self):
  378. prev_event_id = "prev_event_id"
  379. event = create_event(
  380. type="test_message", name="event2", prev_events=[(prev_event_id, {})]
  381. )
  382. old_state = [
  383. create_event(type="test1", state_key="1"),
  384. create_event(type="test1", state_key="2"),
  385. create_event(type="test2", state_key=""),
  386. ]
  387. group_name = yield defer.ensureDeferred(
  388. self.store.store_state_group(
  389. prev_event_id,
  390. event.room_id,
  391. None,
  392. None,
  393. {(e.type, e.state_key): e.event_id for e in old_state},
  394. )
  395. )
  396. self.store.register_event_id_state_group(prev_event_id, group_name)
  397. context = yield defer.ensureDeferred(self.state.compute_event_context(event))
  398. current_state_ids = yield defer.ensureDeferred(context.get_current_state_ids())
  399. self.assertEqual(
  400. {e.event_id for e in old_state}, set(current_state_ids.values())
  401. )
  402. self.assertEqual(group_name, context.state_group)
  403. @defer.inlineCallbacks
  404. def test_trivial_annotate_state(self):
  405. prev_event_id = "prev_event_id"
  406. event = create_event(
  407. type="state", state_key="", name="event2", prev_events=[(prev_event_id, {})]
  408. )
  409. old_state = [
  410. create_event(type="test1", state_key="1"),
  411. create_event(type="test1", state_key="2"),
  412. create_event(type="test2", state_key=""),
  413. ]
  414. group_name = yield defer.ensureDeferred(
  415. self.store.store_state_group(
  416. prev_event_id,
  417. event.room_id,
  418. None,
  419. None,
  420. {(e.type, e.state_key): e.event_id for e in old_state},
  421. )
  422. )
  423. self.store.register_event_id_state_group(prev_event_id, group_name)
  424. context = yield defer.ensureDeferred(self.state.compute_event_context(event))
  425. prev_state_ids = yield defer.ensureDeferred(context.get_prev_state_ids())
  426. self.assertEqual({e.event_id for e in old_state}, set(prev_state_ids.values()))
  427. self.assertIsNotNone(context.state_group)
  428. @defer.inlineCallbacks
  429. def test_resolve_message_conflict(self):
  430. prev_event_id1 = "event_id1"
  431. prev_event_id2 = "event_id2"
  432. event = create_event(
  433. type="test_message",
  434. name="event3",
  435. prev_events=[(prev_event_id1, {}), (prev_event_id2, {})],
  436. )
  437. creation = create_event(type=EventTypes.Create, state_key="")
  438. old_state_1 = [
  439. creation,
  440. create_event(type="test1", state_key="1"),
  441. create_event(type="test1", state_key="2"),
  442. create_event(type="test2", state_key=""),
  443. ]
  444. old_state_2 = [
  445. creation,
  446. create_event(type="test1", state_key="1"),
  447. create_event(type="test3", state_key="2"),
  448. create_event(type="test4", state_key=""),
  449. ]
  450. self.store.register_events(old_state_1)
  451. self.store.register_events(old_state_2)
  452. context = yield self._get_context(
  453. event, prev_event_id1, old_state_1, prev_event_id2, old_state_2
  454. )
  455. current_state_ids = yield defer.ensureDeferred(context.get_current_state_ids())
  456. self.assertEqual(len(current_state_ids), 6)
  457. self.assertIsNotNone(context.state_group)
  458. @defer.inlineCallbacks
  459. def test_resolve_state_conflict(self):
  460. prev_event_id1 = "event_id1"
  461. prev_event_id2 = "event_id2"
  462. event = create_event(
  463. type="test4",
  464. state_key="",
  465. name="event",
  466. prev_events=[(prev_event_id1, {}), (prev_event_id2, {})],
  467. )
  468. creation = create_event(type=EventTypes.Create, state_key="")
  469. old_state_1 = [
  470. creation,
  471. create_event(type="test1", state_key="1"),
  472. create_event(type="test1", state_key="2"),
  473. create_event(type="test2", state_key=""),
  474. ]
  475. old_state_2 = [
  476. creation,
  477. create_event(type="test1", state_key="1"),
  478. create_event(type="test3", state_key="2"),
  479. create_event(type="test4", state_key=""),
  480. ]
  481. store = StateGroupStore()
  482. store.register_events(old_state_1)
  483. store.register_events(old_state_2)
  484. self.store.get_events = store.get_events
  485. context = yield self._get_context(
  486. event, prev_event_id1, old_state_1, prev_event_id2, old_state_2
  487. )
  488. current_state_ids = yield defer.ensureDeferred(context.get_current_state_ids())
  489. self.assertEqual(len(current_state_ids), 6)
  490. self.assertIsNotNone(context.state_group)
  491. @defer.inlineCallbacks
  492. def test_standard_depth_conflict(self):
  493. prev_event_id1 = "event_id1"
  494. prev_event_id2 = "event_id2"
  495. event = create_event(
  496. type="test4",
  497. name="event",
  498. prev_events=[(prev_event_id1, {}), (prev_event_id2, {})],
  499. )
  500. member_event = create_event(
  501. type=EventTypes.Member,
  502. state_key="@user_id:example.com",
  503. content={"membership": Membership.JOIN},
  504. )
  505. power_levels = create_event(
  506. type=EventTypes.PowerLevels,
  507. state_key="",
  508. content={"users": {"@foo:bar": "100", "@user_id:example.com": "100"}},
  509. )
  510. creation = create_event(
  511. type=EventTypes.Create, state_key="", content={"creator": "@foo:bar"}
  512. )
  513. old_state_1 = [
  514. creation,
  515. power_levels,
  516. member_event,
  517. create_event(type="test1", state_key="1", depth=1),
  518. ]
  519. old_state_2 = [
  520. creation,
  521. power_levels,
  522. member_event,
  523. create_event(type="test1", state_key="1", depth=2),
  524. ]
  525. store = StateGroupStore()
  526. store.register_events(old_state_1)
  527. store.register_events(old_state_2)
  528. self.store.get_events = store.get_events
  529. context = yield self._get_context(
  530. event, prev_event_id1, old_state_1, prev_event_id2, old_state_2
  531. )
  532. current_state_ids = yield defer.ensureDeferred(context.get_current_state_ids())
  533. self.assertEqual(old_state_2[3].event_id, current_state_ids[("test1", "1")])
  534. # Reverse the depth to make sure we are actually using the depths
  535. # during state resolution.
  536. old_state_1 = [
  537. creation,
  538. power_levels,
  539. member_event,
  540. create_event(type="test1", state_key="1", depth=2),
  541. ]
  542. old_state_2 = [
  543. creation,
  544. power_levels,
  545. member_event,
  546. create_event(type="test1", state_key="1", depth=1),
  547. ]
  548. store.register_events(old_state_1)
  549. store.register_events(old_state_2)
  550. context = yield self._get_context(
  551. event, prev_event_id1, old_state_1, prev_event_id2, old_state_2
  552. )
  553. current_state_ids = yield defer.ensureDeferred(context.get_current_state_ids())
  554. self.assertEqual(old_state_1[3].event_id, current_state_ids[("test1", "1")])
  555. @defer.inlineCallbacks
  556. def _get_context(
  557. self, event, prev_event_id_1, old_state_1, prev_event_id_2, old_state_2
  558. ):
  559. sg1 = yield defer.ensureDeferred(
  560. self.store.store_state_group(
  561. prev_event_id_1,
  562. event.room_id,
  563. None,
  564. None,
  565. {(e.type, e.state_key): e.event_id for e in old_state_1},
  566. )
  567. )
  568. self.store.register_event_id_state_group(prev_event_id_1, sg1)
  569. sg2 = yield defer.ensureDeferred(
  570. self.store.store_state_group(
  571. prev_event_id_2,
  572. event.room_id,
  573. None,
  574. None,
  575. {(e.type, e.state_key): e.event_id for e in old_state_2},
  576. )
  577. )
  578. self.store.register_event_id_state_group(prev_event_id_2, sg2)
  579. result = yield defer.ensureDeferred(self.state.compute_event_context(event))
  580. return result