specs/standards/core/sync.md

343 lines
16 KiB
Markdown
Raw Normal View History

2024-06-12 11:06:17 -04:00
---
title: WAKU-SYNC
name: Waku Sync
editor: Simon-Pierre Vivier <simvivier@status.im>
contributors:
- Prem Chaitanya Prathi <prem@status.im>
- Hanno Cornelius <hanno@status.im>
---
2024-12-06 09:57:29 -05:00
# Abstract
This specification explains `WAKU-SYNC`
which enables the synchronization of messages between nodes storing sets of [`14/WAKU2-MESSAGE`](https://rfc.vac.dev/waku/standards/core/14/message)s.
2024-06-12 11:06:17 -04:00
2024-12-06 09:57:29 -05:00
# Specification
2024-06-12 11:06:17 -04:00
Waku Sync consists of two libp2p protocols: `reconciliation` and `transfer`.
2024-12-11 16:44:01 -05:00
The Reconciliation protocol finds differences in sets of messages.
The Transfer protocol is used to exchange the differences found with other peers.
The end goal being that peers have the same set of messages.
2024-06-12 11:06:17 -04:00
2024-12-05 11:34:36 -05:00
#### Terminology
2024-06-12 11:06:17 -04:00
The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”,
“RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in [RFC2119](https://www.ietf.org/rfc/rfc2119.txt).
2024-12-06 09:57:29 -05:00
## Reconciliation
**Libp2p Protocol identifier**: `/vac/waku/reconciliation/1.0.0`
The `reconciliation` protocol finds the differences between two sets of [`14/WAKU2-MESSAGE`](https://rfc.vac.dev/waku/standards/core/14/message) on different nodes.
It assumes that each [`14/WAKU2-MESSAGE`](https://rfc.vac.dev/waku/standards/core/14/message) maps to a uniquely identifying `SyncID`,
which is maintained in an ordered set within each node.
An ordered set of `SyncID`s is termed a `Range`.
This implies that any contiguous subset of a `Range` is also a `Range`.
In other words, the `reconciliation` protocol allows two nodes to find differences between `Range`s of `SyncID`s,
which would map to an equivalent difference in cached [`14/WAKU2-MESSAGE`](https://rfc.vac.dev/waku/standards/core/14/message)s.
These terms, the wire protocol and message flows are explained below.
### Wire protocol
#### Reconcilation payload
Nodes participating in the `reconciliation` protocol exchange encoded `RangesData` messages.
The `RangesData` structure represents a complete `reconciliation` payload:
| Field | Type | Description |
|---------------|--------------------------|------------------------------------------|
| cluster | varint | Cluster ID of the sender |
| shards | seq[varint] | Shards supported by the sender |
| ranges | seq[Range] | Sequence of ranges |
The `cluster` and `shards` fields
represent the sharding elements as defined in [RELAY-SHARDING](https://github.com/waku-org/specs/blob/master/standards/core/relay-sharding.md#static-sharding).
The `ranges` field contain a sequence of ranges for reconciliation.
We identify the following subtypes:
##### Range
A `Range` represents a representation of the bounds, type and, optionally, an encoded representation of the content of a range.
| Field | Type | Description |
|---------------|--------------------------|------------------------------------------|
| bounds | RangeBounds | The bounds of the range |
| type | RangeType | The type of the range |
| Option(content)| Fingerprint OR ItemSet | Optional field depending on `type`. If set, possible values are a `Fingerprint` of the range, or the complete `ItemSet` in the range |
##### RangeBounds
`RangeBounds` defines a `Range` by two bounding `SyncID` values, forming a time-hash interval:
| Field | Type | Description |
|---------|---------|--------------------------------------|
| a | SyncID | Lower bound (inclusive) |
| b | SyncID | Upper bound (exclusive) |
The lower bound MUST be strictly smaller than the upper bound.
##### SyncID
A `SyncID` consists of a message timestamp and hash to uniquely identify a [`14/WAKU2-MESSAGE`](https://rfc.vac.dev/waku/standards/core/14/message).
| Field | Type | Description |
|-----------|------------|-------------------------------------------|
| timestamp | varint | Timestamp of the message (nanoseconds) |
| hash | seq[Byte] | 32-byte message hash |
The timestamp MUST be the time of message creation and
the hash MUST follow the [deterministic message hashing specification](https://rfc.vac.dev/waku/standards/core/14/message#deterministic-message-hashing).
SyncIDs MUST be totally ordered by timestamp first, then by hash to disambiguate messages with identical timestamps.
##### RangeType
A `RangeType` indicates the type of `content` encoding for the `Range`:
| Type | Value | Description |
|-------------|-------|-------------------------------------------------|
| Skip | 0 | Range has been processed and `content` field is empty |
| Fingerprint | 1 | Range is encoded in `content` field as a 32-byte `Fingerprint` |
| ItemSet | 2 | Range is encoded in `content` field as an `ItemSet` of `SyncID`s |
##### Fingerprint
A `Fingerprint` is a compact 32-byte representation of all message hashes within a `Range`.
It MUST be implemented as an XOR of all contained hashes,
extracted from the `SyncID`s present in the `Range`.
Fingerprints allow for efficient difference detection without transmitting complete message sets.
2024-12-05 11:34:36 -05:00
##### ItemSet
An `ItemSet` contains a full representation of all `SyncID`s within a `Range`
and a reconciliation status:
| Field | Type | Description |
|------------|------------|--------------------------------------|
| elements | seq[`SyncID`] | Sequence of `SyncID`s in the `Range` |
| reconciled | bool | Whether the `Range` has been reconciled |
2024-06-12 11:06:17 -04:00
2024-12-06 09:57:29 -05:00
#### Payload encoding
2024-09-03 11:52:48 -04:00
We can now define a heuristic for encoding the `RangesData` payload.
All varints MUST be encoded according to the [specified varint encoding](#varint-encoding) procedure.
Concatenate each of the following, in order:
1. Encode the cluster ID as a varint
2. Encode the number of shards as a varint
3. For each shard, encode the shard as a varint and concatenate it to the previous
4. Encode the `ranges`, according to ["Delta encoding for Ranges"](#delta-encoding-for-ranges).
##### Varint encoding
All variable integers (varints) MUST be encoded as little-endian base 128 variable-length integers (LEB128) and MUST be minimally encoded.
##### Delta encoding for Ranges
The `ranges` field contain a sequence of `Ranges`.
It can be delta encoded as follows:
For each `Range` element, concatenate the following:
1. From the `RangeBounds`, select only the `SyncID` representing the _upper bound_ of that range.
Inclusive lower bounds are omitted because they are always the same as the exclusive upper bounds of the previous range.
The first range is always assumed to have a lower bound `SyncID` of `0` (both the `timestamp` and `hash` are `0`).
2. [Delta encode](#delta-encoding-for-sequential-syncids) the selected `SyncID` by comparing it to the previous ranges' `SyncID`s.
The first range's `SyncID` will be fully encoded, as described in that section.
3. Encode the `RangeType` as a single byte and concatenate it to the delta encoded `SyncID`.
4. If the `RangeType` is:
- _Skip_: encode nothing more
- _Fingerprint_: encode the 32-byte fingerprint
- _ItemSet_:
- Encode the number of elements as a varint
- Delta encode the item set, according to ["Delta encoding for ItemSets"](#delta-encoding-for-itemsets)
##### Delta encoding for sequential SyncIDs
Sequential `SyncID`s can be delta encoded to minimize payload size.
Given an ordered sequence of `SyncID`s:
1. Encode the first timestamp in full
2. Delta encode subsequent timestamps, i.e., encode only the difference from the previous timestamp
3. If the timestamps are identical, encode a `SyncID` `hash` delta as follows:
3.1. Compared to the previous hash, truncate the hash up to and including the first differentiating byte
3.2. Encode the number of bytes in the truncated hash (as a single byte)
3.3. Encode the truncated hash
See the table below as an example:
2025-01-30 08:29:08 -05:00
| Timestamp | Hash | Encoded Timestamp (diff from previous) | Encoded Hash (length + all bytes up to first diff)
| - | - | - | -
| 1000 | 0x4a8a769a... | 1000 | -
| 1002 | 0x351c5e86... | 2 | -
| 1002 | 0x3560d9c4... | 0 | 0x023560
| 1003 | 0xbeabef25... | 1 | -
2024-10-07 11:41:55 -04:00
##### Delta encoding for ItemSets
An `ItemSet` is delta encoded as follows:
Concatenate each of the following, in order:
1. From the first `SyncID`, encode the timestamp in full
2. From the first `SyncID`, encode the hash in full
3. For each subsequent `SyncID`:
- Delta encode the timestamp, i.e., encode only the difference from the previous `SyncID`'s timestamp
- Append the encoded hash in full
4. Encode a single byte for the `reconciled` boolean (0 or 1)
### Reconciliation Message Flow
The `reconciliation` message flow is triggered by an `initiator` with an initial `RangesData` payload.
The selection of sync peers
and triggers for initiating a `reconciliation` is out of scope of this document.
The response to a `RangesData` payload is another `RangesData` payload, according to the heuristic below.
The syncing peers SHOULD continue exchanging `RangesData` payloads until all ranges have been processed.
The output of a `reconciliation` flow is a set of differences in `SyncID`s.
These could either be `SyncID`s present in the remote peer and missing locally,
or `SyncID`s present locally but missing in the remote peer.
Each sync peer MAY use the `transfer` protocol to exchange the full messages corresponding to these computed differences,
proactively transferring messages missing in the remote peer.
#### Initial Message
The initiator
1. Selects a time range to sync
2. Computes a fingerprint for the entire range
3. Constructs an initial `RangesData` payload with:
- The initiator's cluster ID
- The initiator's supported shards
- A single range of type `Fingerprint` covering the entire sync period
- The fingerprint for this range
4. [Delta encodes](#payload-encoding) the payload
5. Sends the payload using libp2p length-prefixed encoding
#### Responding to a `RangesData` payload
Each syncing peer performs the following in response to a `RangesData` payload:
The responder:
1. Receives and decodes the payload
2. If shards and cluster match, processes each range:
- If the received range is of type `Skip`, ignores it.
- If the received range is of type `Fingerprint`, computes the fingerprint over the local matching range
- If the local fingerprint matches the received fingerprint, includes this range in the response as type `Skip`
- If the local fingerprint does _not_ match the received fingerprint:
- If the corresponding range is small enough, includes this range in the response as type `ItemSet` with all `SyncID`s
- If the corresponding range is too large, divide it into subranges.
For each subrange, if the range is small enough, includes it in the response as type `ItemSet` with all `SyncID`s.
If the subrange is too large, includes it in the response as type `Fingerprint`.
- If the received range is of type `ItemSet`, compares it to the local items in the corresponding range
- If there are any differences between the local and remote items, adds these as part of the output of the `reconciliation` procedure.
At this point, the syncing peers MAY start to exchange the full messages corresponding to differences using the `transfer` protocol.
- If the received `ItemSet` is _not_ marked as `reconciled` by the remote peer, includes the corresponding local range in the response as type `ItemSet`.
- If the received `ItemSet` is marked as `reconciled` by the remote peer, includes the corresponding local range in the response as type `Skip`.
3. If shards or cluster don't match:
- Responds with an empty payload
4. Delta encodes the response
5. Sends the response using libp2p length-prefixed encoding
This process continues until the syncing peer crafts an empty response,
i.e., when all ranges have been processed and reconciled by both syncing peers and there are no differences left.
2024-10-07 11:41:55 -04:00
2024-12-06 09:57:29 -05:00
## Transfer Protocol
**Libp2p Protocol identifier**: `/vac/waku/transfer/1.0.0`
2024-09-03 11:52:48 -04:00
Once the `reconciliation` protocol starts finding differences in `SyncID`s,
the `transfer` protocol MAY be used to exchange actual message contents between peers.
A node using `transfer` SHOULD proactively send [`14/WAKU2-MESSAGE`](https://rfc.vac.dev/waku/standards/core/14/message)s missing in the remote party.
Nodes SHOULD only accept incoming transfers from peers for which they have an active reconciliation session.
The `SyncID`s corresponding to messages received via `transfer`,
MUST be added to the corresponding `Range` tracked by the `reconciliation` protocol.
The `transfer`payload MUST follow the wire specification below.
2024-12-06 09:57:29 -05:00
### Wire specification
2024-12-06 09:57:29 -05:00
```protobuf
syntax = "proto3";
2025-01-20 10:55:11 -05:00
package waku.sync.transfer.v1;
2024-12-06 09:57:29 -05:00
import "waku/message/v1/message.proto";
message WakuMessageAndTopic {
// Full message content and associated pubsub_topic as value
optional waku.message.v1.WakuMessage message = 1;
optional string pubsub_topic = 2;
}
```
## Implementation Suggestions
2024-12-09 11:52:40 -05:00
The flexibility of the protocol implies that much is left to the implementers.
2024-12-06 09:57:29 -05:00
What will follow is NOT part of the specification.
This section was created to inform implementations.
2024-09-03 11:52:48 -04:00
### Cluster & Shards
2025-01-30 08:29:08 -05:00
To prevent nodes from synchronizing messages from shard they don't support,
cluster and shards information has been added to each payload.
On reception, if two peers don't share the same set of shards the sync is aborted.
### Parameters
2024-12-09 11:52:40 -05:00
Two useful parameters to add to your implementation are partitioning count and the item set threshold.
2024-12-06 09:57:29 -05:00
The partitioning count is the number of time a range is split.
A higher value reduces round trips at the cost of computing more fingerprints.
2024-12-06 09:57:29 -05:00
The item set threshold determines when item sets are sent instead of fingerprints.
A higher value sends more items which means higher chance of duplicates but
reduces the amount of round trips overall.
2024-12-06 09:57:29 -05:00
### Storage
2024-12-06 09:57:29 -05:00
The storage implementation should reflect the context.
2024-09-03 11:52:48 -04:00
Most messages that will be added will be recent and
2024-12-06 09:57:29 -05:00
removed messages will be older ones.
2024-09-03 11:52:48 -04:00
When differences are found some messages will have to be inserted randomly.
It is expected to be a less likely case than time based insertion and removal.
2024-12-06 09:57:29 -05:00
Last but not least it must be optimized for fingerprinting
2024-09-03 11:52:48 -04:00
as it is the most often used operation.
### Sync Interval
2024-12-05 11:34:36 -05:00
Ad-hoc syncing can be useful in some cases but continuous periodic sync
minimize the differences in messages stored across the network.
Syncing early and often is the best strategy.
2024-12-09 11:52:40 -05:00
The default used in Nwaku is 5 minutes interval between sync with a range of 1 hour.
2024-12-05 11:34:36 -05:00
### Sync Window
2024-12-09 11:52:40 -05:00
By default we offset the sync window by 20 seconds in the past.
The actual start of the sync range is T-01:00:20 and the end T-00:00:20 in most cases.
This is to handle the inherent jitters of GossipSub.
In other words, it is the amount of time needed to confirm if a message is missing or not.
2024-12-05 11:34:36 -05:00
### Peer Choice
2024-12-09 11:52:40 -05:00
Wrong peering strategies can lead to inadvertently segregating peers and
reduce sampling diversity.
Nwaku randomly select peers to sync with for simplicity and robustness.
2024-12-05 11:34:36 -05:00
2024-12-11 16:44:01 -05:00
More sophisticated strategies may be implemented in future.
2024-12-05 11:34:36 -05:00
## Security/Privacy Considerations
2024-12-05 11:34:36 -05:00
Nodes using `WAKU-SYNC` are fully trusted.
Message hashes are assumed to be of valid messages received via Waku Relay or Light push.
Further refinements to the protocol are planned
to reduce the trust level required to operate.
Notably by verifying messages RLN proof at reception.
2024-09-06 11:18:14 -04:00
## Copyright
2024-06-12 11:06:17 -04:00
Copyright and related rights waived via
[CC0](https://creativecommons.org/publicdomain/zero/1.0/).
2024-09-06 11:18:14 -04:00
## References
2024-12-06 09:57:29 -05:00
- [RBSR](https://github.com/AljoschaMeyer/rbsr_short/blob/main/main.pdf)
- [Negentropy Explainer](https://logperiodic.com/rbsr.html)
- [Master Thesis](https://github.com/AljoschaMeyer/master_thesis/blob/main/main.pdf)