Distribution Protocol
The Converge Distribution Protocol is a peer to peer message based protocol that all nodes use to exchange data with each other. It can run over any transport that can reliably pass sufficiently large datagrams.
Operations
The protocol is based on granting and invoking capabilities. These capabilities are represented by byte strings that are meaningful to the recipient, but opaque to any callers. The only requirement is that they be unforgeable, so they may be anything from an encrypted and authenticated payload to random bytes indexing into a local database.
Give
The give
message provides the peer with a capability and an explanation as to how the capability may be used.
It does not request any response.
Explain
The explain
message requests an explanation as to how a set of capabilities may be used with this peer.
This explanation takes the form of replies of give
messages.
Note that the peer should always return a give
message,
even if it just explains that the capability is meaningless.
Delegate
Requests a capability that has the functionality of the greatest lower bound of the provided capability and explanation.
For example, a capability that can fetch
anything could be delegated into one that can only fetch a specific reference.
Select
FIXME: not sure what i think of including this one
The select
message requests a list of capabilities the peer grants the requestor that match a particular explanation.
This does not list all the capabilities that are valid for the requestor to use,
merely those specifically recorded as granted to that requestor.
These capabilities are returned in give
messages.
This enables peers to host public content without distributing capabilities beforehand.
Invoke
Invokes this capability, providing any required parameters. Invocation also includes any capabilities needed to respond, along with their explanations.
Capabilities
The actual distribution and synchronization of data takes place over invoke messages.
Not all nodes must support every capability, but they must not give out capabilities that they do not support.
This generally means that they must support fetch
and write
.
They also may support additional capabilities not listed here!
Fetch
The fetch
capability requests that the peer find a particular object and send its contents back.
It has two parameters:
- the set of references to objects that can be requested
- the probability of forwarding the request to other peers
Each invocation of a fetch
capability provides a write
capability,
scoped to enable the peer to reply with the requested object.
Write
The write
capability provides the contents of an object and some of its children to a peer.
It has just one parameter:
- the set of references to objects that can be sent
Each invocation of a write
capability includes the contents of the object and its children, and provides a fetch
capability,
scoped to allow the peer to fetch any children or parents listed but not included on any of the included objects.
Subscribe
The subscribe
capability requests that a peer proactively inform this node of any new [versions][version] of a particular [braid].
It has two parameters:
- the set of [braid references][braid] that can be subscribed to
- whether the peer will subscribe to this braid on other peers
Each invocation of a subscribe
capability provides a write
capability,
scoped to enable the peer to reply with the requested object.
Pin
The pin
capability creates a new pin,
requesting that a peer maintain one or more copy of a set of objects and objects related to them.
It has four parameters:
- the set of references to objects to be pinned
- the set of references to objects to be excluded from this pin
- the pin filter, describing which related objects to implicitly pin
- how many copies to pin
Each invocation of a pin
capability provides either a subscribe
or fetch
capability,
scoped to enable the peer to subscribe to changes on, or request, the pinned objects.
The pin
capability responds with a repin
capability, to change that pin.
Pin Filters
The types of recursive pinning that might be constructed are unbounded, which entails an equally complex task of applying those pins or explaining them to the user. Following the operator's notes on pinning, we must support at least:
- pinning only the latest versions of an object
- pinning the latest versions and all objects they reference
- pinning historical versions (following first parents) and all objects they reference
- pinning all versions and all objects they reference
There are options here to support either those options directly, or create a tiny DSL that can make those options and others. Something like:
data Pin
= Pin Word8 -- pin this number of copies
| Repeat (Maybe Word) Pin -- apply the pin, when it's done, apply it again, if a count is supplied, limit to that many times
| Branch [Pin] -- apply the pins, all starting from the same location
| FirstParent Pin -- go to the first parent, and apply the contained pin
) Parents Pin -- go to each parent, and apply the pin
) References Pin -- go to each reference, and apply the pin
| IsBlob Pin -- if the current reference is a blob, apply the contained pin, otherwise do nothing
| IsVersion Pin -- if the current reference is a version, apply the contained pin, otherwise do nothing
| IsBraid Pin -- if the current reference is a braid, apply the contained pin, otherwise do nothing
This is much more flexible, but seems unnecessarily complex.
Repin
The repin
capability modifies a pin.
It has two parameters:
- the set of objects to add to the pin
- the set of objects to exclude from the pin