Skip to content

Commit 7c28c0c

Browse files
committed
documented workings of TermnalOpsSyncAgent.
1 parent 524bed6 commit 7c28c0c

File tree

1 file changed

+81
-0
lines changed

1 file changed

+81
-0
lines changed

src/mesh/agents/state/TerminalOpsSyncAgent.ts

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,87 @@ import { PeerGroupAgent } from '../peer/PeerGroupAgent';
1717
import { RNGImpl } from 'crypto/random';
1818
import { MultiMap } from 'util/multimap';
1919

20+
/*
21+
22+
*Introduction*
23+
24+
The TerminalOpsSyncAgent's purpose is to synchronize the state of a MutableObject by keeping track
25+
of its "terminal ops". A MutableObject represents the initial state of the object, which is then
26+
updated by creating MutationOp instances that point to it through their "target" field.
27+
28+
The agent will be instantiated to sync a particular MutableObject present in the local store, and
29+
will perform state reconcilaition with any connected peers that either advertise new states
30+
through gossiping or request MutationOps in response to its own state advertisements.
31+
32+
The TerminalOpsSyncAgent only deals with actual state sync. The gossiping of new states is done
33+
by other agents (typically the StateGossipAgent, which batches together the states of all the
34+
objects that a peer wants to sync with a particular PeerGroup). The local TerminalOpsSyncAgent and
35+
StateGossipAgent communicate trough the local broadcasting mechanism of the AgentPod they share.
36+
37+
38+
*State by terminal ops*
39+
40+
The TerminalOpsSyncAgent uses the "prevOps" field in the MutationOp object to discard all the ops
41+
that have any following ops -that is another op that points to them through its "prevOps" field-
42+
and use the set of remaining "terminal ops" as a way to represent the state of the MutableObject
43+
being synchronized. This set of terminal ops can be obtained easily and quickly from the store
44+
itself.
45+
46+
*State broadcasting*
47+
48+
After discovering that the state of the object has changed, the agent will broadcast a message to
49+
the local agent pod informing of the update. Any gossiping agents active in the pod will pick up
50+
the update and inform any connected peers. Conversely, if any gossip agent picks up any state update
51+
from a connected peer, it will also broadcast a message on the local agent pod. The
52+
TermninalOpsSyncAgent will check the received state and start synchronizing with such a peer if
53+
necessary.
54+
55+
*State sync*
56+
57+
After determining (via gossip results broadcaste on the local pod by a gossiping agent) that it
58+
needs to perform state sync, the TerminalOpsSyncAgent exchanges a series of messages with the
59+
TerminalOpsSyncAgent on the peer that has advertised a new state. Since the state is just the
60+
set of "terminal ops" on the other end, the agent will just ask for any of this "terminal ops"
61+
that are missing on the local store. Since an op can only be persisted to the store once all
62+
its prevOps have been already persisted, the agent may need to make several calls until it can
63+
reconcile the local state with the remote one, following the trail of prevOps until all the
64+
dependencies of the terminalOps have been fetched. There are 4 types of messages used in this
65+
task:
66+
67+
The SendStateMessage is sent in reply to a RequestStateMessage, and it will send the set of
68+
terminalOps in full (gossiping usually would send just a hash of the terminalOp set).
69+
70+
The SendOpsMessage is sent in reply to the RequestObjsMessage, and will send the literalized
71+
version of the objects and their dependencies.
72+
73+
*Security measures, optimizations*
74+
75+
When sending state (in the form of literalized objects) the agent may omit some dependencies
76+
of the objects being sent, expecting the receiving peer to already have them in its store
77+
(e.g., the identities and public keys that are referenced again and again by the ops being
78+
applied to the target object). And of course, there may be more prevOps that the other end
79+
discovers as a result of the received objects, and that it also needs to request.
80+
81+
There are two security measures in place to prevent object exfiltration:
82+
83+
Rule 1. Every requested object needs to be referenced (probably indirectly) from an op that has the
84+
object being synchronized as its target.
85+
Rule 2. Every an object A that is sent, and has a reference B that is optimized away from the sent
86+
message, must provide also a proof that the sender has B locally in its store.
87+
88+
The purpose of Rule 1 is preventing an adversary from requesting arbitrary objects that have no
89+
relation to the object being synchronized.
90+
91+
The purpose of Rule 2 is a bit more subtle: an adversary may construct a legitimate MutationOp that
92+
he then applies to the object being syncronized in such a way that the op references some object
93+
that he wants to steal from another peer (perhaps an object
94+
unrelated to the one being synchronized). So even if the attacker knows the hash of the object that
95+
he wants to steal, and is able to construct a MutationOp that will be accepted by the type of the
96+
mutations that the mutable object accepts, he will not be able to provide the proof of ownership
97+
that is required for sending incomplete operations.
98+
99+
100+
*/
20101

21102
enum TerminalOpsSyncAgentMessageType {
22103
RequestState = 'request-state',

0 commit comments

Comments
 (0)