mirror of
https://github.com/matrix-org/matrix-spec
synced 2025-12-31 21:18:38 +01:00
The "Room Specification" (or "Room Version Specification") is the specification that defines which room versions do what and are intended to be documents which speak the truth about how rooms operate under the hood. The approach taken here is a bit different than other specifications. For starters, the specification is versioned in this project instead of relying on the matrix.org repository to track compiled HTML. This is done for a couple reasons, the first being we're still developing the v1 specification while concurrently making a v2 spec and the second being trying to reduce the reliance on matrix.org's repository for specifications. Because the room spec is built into versions, some changes needed to be made. The `targets.yaml` now has a special syntax for indicating what version something is at, and the changelog generator can handle rendering different versions of the same changelog (as parsed from the RST). Some additional work has been put in to the changelog parsing to allow us to reference the v1 room spec as "v1" without having to sacrifice clarity in the changelog headings. Finally, this moves the state resolution algorithms into the versioned spec as a result of MSC1759 (https://github.com/matrix-org/matrix-doc/pull/1759). Note: this does not introduce the concept of versioned schemas (tabs) that I was previously working with. There's currently no use for them, so they are shelved elsewhere.
182 lines
8.1 KiB
ReStructuredText
182 lines
8.1 KiB
ReStructuredText
.. Copyright 2018 New Vector Ltd
|
|
..
|
|
.. Licensed under the Apache License, Version 2.0 (the "License");
|
|
.. you may not use this file except in compliance with the License.
|
|
.. You may obtain a copy of the License at
|
|
..
|
|
.. http://www.apache.org/licenses/LICENSE-2.0
|
|
..
|
|
.. Unless required by applicable law or agreed to in writing, software
|
|
.. distributed under the License is distributed on an "AS IS" BASIS,
|
|
.. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
.. See the License for the specific language governing permissions and
|
|
.. limitations under the License.
|
|
|
|
|
|
.. Note: This document appended to the end of the intro, so this next line
|
|
.. appears under "Other Room Versions".
|
|
|
|
This is the specification for **room version 2** (``"2"``).
|
|
|
|
.. Warning::
|
|
|
|
Room version 2 is under development and cannot be relied on in production
|
|
environments.
|
|
|
|
|
|
Changelog
|
|
---------
|
|
|
|
.. topic:: Room version 2
|
|
{{rooms_changelog_v2}}
|
|
|
|
This version of the specification is generated from
|
|
`matrix-doc <https://github.com/matrix-org/matrix-doc>`_ as of Git commit
|
|
`{{git_version}} <https://github.com/matrix-org/matrix-doc/tree/{{git_rev}}>`_.
|
|
|
|
For the full historical changelog, see
|
|
https://github.com/matrix-org/matrix-doc/blob/master/changelogs/rooms.rst
|
|
|
|
|
|
Server implementation components
|
|
--------------------------------
|
|
|
|
.. WARNING::
|
|
The information contained in this section is strictly for server implementors.
|
|
Applications which use the Client-Server API are generally unaffected by the
|
|
details contained here, and can safely ignore their presence.
|
|
|
|
|
|
The algorithms defined here should only apply to version 2 rooms. Other algorithms
|
|
may be used by other room versions, and as such servers should be aware of which
|
|
version room they are dealing with prior to executing a given algorithm.
|
|
|
|
|
|
State resolution
|
|
~~~~~~~~~~~~~~~~
|
|
|
|
The room state :math:`S'(E)` after an event :math:`E` is defined in terms of
|
|
the room state :math:`S(E)` before :math:`E`, and depends on whether
|
|
:math:`E` is a state event or a message event:
|
|
|
|
* If :math:`E` is a message event, then :math:`S'(E) = S(E)`.
|
|
|
|
* If :math:`E` is a state event, then :math:`S'(E)` is :math:`S(E)`, except
|
|
that its entry corresponding to :math:`E`'s ``event_type`` and ``state_key``
|
|
is replaced by :math:`E`'s ``event_id``.
|
|
|
|
The room state :math:`S(E)` before :math:`E` is the *resolution* of the set of
|
|
states :math:`\{ S'(E_1), S'(E_2), … \}` consisting of the states after each of
|
|
:math:`E`'s ``prev_event``\s :math:`\{ E_1, E_2, … \}`, where the resolution of
|
|
a set of states is given in the algorithm below.
|
|
|
|
Definitions
|
|
+++++++++++
|
|
|
|
The state resolution algorithm for version 2 rooms uses the following
|
|
definitions, given the set of room states :math:`\{ S_1, S_2, \ldots \}`:
|
|
|
|
Power events
|
|
A *power event* is a state event with type ``m.room.power_levels`` or
|
|
``m.room.join_rules``, or a state event with type ``m.room.member`` where the
|
|
``membership`` is ``leave`` or ``ban`` and the ``sender`` does not match the
|
|
``state_key``. The idea behind this is that power events are events that have
|
|
may remove someone's ability to do something in the room.
|
|
|
|
Unconflicted state map and conflicted state set
|
|
The *unconflicted state map* is the state where the value of each key exists
|
|
and is the same in each state :math:`S_i`. The *conflicted state set* is the
|
|
set of all other state events. Note that the unconflicted state map only has
|
|
one event per ``(event_type, state_key)``, whereas the conflicted state set
|
|
may have multiple events.
|
|
|
|
Auth difference
|
|
The *auth difference* is calculated by first calculating the full auth chain
|
|
for each state :math:`S_i`, that is the union of the auth chains for each
|
|
event in :math:`S_i`, and then taking every event that doesn't appear in
|
|
every auth chain. If :math:`C_i` is the full auth chain of :math:`S_i`, then
|
|
the auth difference is :math:`\cup C_i - \cap C_i`.
|
|
|
|
Full conflicted set
|
|
The *full conflicted set* is the union of the conflicted state set and the
|
|
auth difference.
|
|
|
|
Reverse topological power ordering
|
|
The *reverse topological power ordering* of a set of events is the
|
|
lexicographically smallest topological ordering based on the DAG formed by
|
|
auth events. The reverse topological power ordering is ordered from earliest
|
|
event to latest. For comparing two topological orderings to determine which
|
|
is the lexicographically smallest, the following comparison relation on
|
|
events is used: for events :math:`x` and :math:`y`, :math:`x<y` if
|
|
|
|
1. :math:`x`'s sender has *greater* power level than :math:`y`'s sender,
|
|
when looking at their respective ``auth_event``\s; or
|
|
2. the senders have the same power level, but :math:`x`'s
|
|
``origin_server_ts`` is *less* than :math:`y`'s ``origin_server_ts``; or
|
|
3. the senders have the same power level and the events have the same
|
|
``origin_server_ts``, but :math:`x`'s ``event_id`` is *less* than
|
|
:math:`y`'s ``event_id``.
|
|
|
|
The reverse topological power ordering can be found by sorting the events
|
|
using Kahn's algorithm for topological sorting, and at each step selecting,
|
|
among all the candidate vertices, the smallest vertex using the above
|
|
comparison relation.
|
|
|
|
Mainline ordering
|
|
Given an ``m.room.power_levels`` event :math:`P`, the *mainline of* :math:`P`
|
|
is the list of events generated by starting with :math:`P` and recursively
|
|
taking the ``m.room.power_levels`` events from the ``auth_events``, ordered
|
|
such that :math:`P` is last. Given another event :math:`e`, the *closest
|
|
mainline event to* :math:`e` is the first event encountered in the mainline
|
|
when iteratively descending through the ``m.room.power_levels`` events in the
|
|
``auth_events`` starting at :math:`e`. If no mainline event is encountered
|
|
when iteratively descending through the ``m.room.power_levels`` events, then
|
|
the closest mainline event to :math:`e` can be considered to be a dummy event
|
|
that is before any other event in the mainline of :math:`P` for the purposes
|
|
of condition 1 below.
|
|
|
|
The *mainline ordering based on* :math:`P` of a set of events is the
|
|
ordering, from smallest to largest, using the following comparision relation
|
|
on events: for events :math:`x` and :math:`y`, :math:`x<y` if
|
|
|
|
1. the closest mainline event to :math:`x` appears *before* the closest
|
|
mainline event to :math:`y`; or
|
|
2. the closest mainline events are the same, but :math:`x`\'s
|
|
``origin_server_ts`` is *less* than :math:`y`\'s ``origin_server_ts``; or
|
|
3. the closest mainline events are the same and the events have the same
|
|
``origin_server_ts``, but :math:`x`\'s ``event_id`` is *less* than
|
|
:math:`y`\'s ``event_id``.
|
|
|
|
Iterative auth checks
|
|
The *iterative auth checks algorithm* takes as input an initial room state
|
|
and a sorted list of state events, and constructs a new room state by
|
|
iterating through the event list and applying the state event to the room
|
|
state if the state event is allowed by the `authorization rules`_. If the
|
|
state event is not allowed by the authorization rules, then the event is
|
|
ignored. If a ``(event_type, state_key)`` key that is required for checking
|
|
the authorization rules is not present in the state, then the appropriate
|
|
state event from the event's ``auth_events`` is used.
|
|
|
|
Algorithm
|
|
+++++++++
|
|
|
|
The *resolution* of a set of states is obtained as follows:
|
|
|
|
1. Take all *power events* and any events in their auth chains, recursively,
|
|
that appear in the *full conflicted set* and order them by the *reverse
|
|
topological power ordering*.
|
|
2. Apply the *iterative auth checks algorithm* on the *unconflicted state map*
|
|
and the list of events from the previous step to get a partially resolved
|
|
state.
|
|
3. Take all remaining events that weren't picked in step 1 and order them by
|
|
the mainline ordering based on the power level in the partially resolved
|
|
state obtained in step 2.
|
|
4. Apply the *iterative auth checks algorithm* on the partial resolved
|
|
state and the list of events from the previous step.
|
|
5. Update the result by replacing any event with the event with the same key
|
|
from the *unconflicted state map*, if such an event exists, to get the final
|
|
resolved state.
|
|
|
|
|
|
.. _`authorization rules`: ../server_server/unstable.html#authorization-rules
|