# DWN Sync Proposal Synchronizing a tenant's data across more than 1 DWN can be achieved by introducing three mechanisms: * An append-only event log * The ability to get events from event log * the ability to get a message by CID using the above mechanisms in addition to existing ones we can break sync into 2 phases: * **Push**: here are all the messages i have for you * **Pull**: give me all the messages i haven't already gotten from you ## Event Log Within the context of a DWN, An append-only event log is simply a ordered K/V store where the key is an ordinal number and the value is the CID of a message. Each DWN would maintain it's own individual event log. There's no requirement for an individual DWN's event log to be in the same order as another DWN Whenever a message is stored by a DWN, the CID of that message is added to its event log. ## `EventsGet` message type used to get events from a DWN ### Message Contents | property name | type | required (y/n) | description | | --------------- | ----------------- | -------------- | ------------------------------------------------------------------ | | `method` | const `EventsGet` | Y | | | `watermark` | string | N | providing no watermark returns all events for a given tenant | | `authorization` | GeneralJws | Y | same expected authorization format required by other DWN messages. | ### Response all events that occurred between the watermark and the time at which the message is processed [`MessageReply`](https://github.com/TBD54566975/dwn-sdk-js/blob/main/src/core/message-reply.ts#L13) where `entries` is an array of event objects ### Notes * Should not be usable in protocol definitions ## `MessagesGet` message typed used to get a message by CID from a DWN ### Message Contents | property name | type | required (y/n) | description | | --------------- | ------------------- | -------------- | ------------------------------------------------------------------ | | `method` | const `MessagesGet` | Y | | | `cid` | string | Y | the CID of the message you want | | `authorization` | GeneralJws | Y | same expected authorization format required by other DWN messages. | ## Pull Introducing `EventsGet` and `MessagesGet` makes it possible to pull all messages from a given DWN ```mermaid sequenceDiagram autonumber participant A as DWN A participant B as DWN B A->>A: grab pull-specific watermark for DWN B A->>B: EventsGet{ watermark, tenant_sig } B->>B: fetch all events between watermark and now B->>A: [event_id:cid, event_id:cid, ...] loop each event A->>A: message = MessagesGet{ cid, tenant_sig } alt if message else else A->>B: MessagesGet{ cid, tenant_sig } B->>B: inflate message B->>A: message A->>A: store message end A->>A: update watermark end ``` ## Push introducing `EventsGet` and `MessagesGet` allows a DWN to _push_ messages to another DWN ```mermaid sequenceDiagram autonumber participant A as DWN A participant B as DWN B A->>A: grab push-specific watermark for DWN B A->>A: EventsGet{watermark, tenant_sig} loop each event A->>A: MessagesGet{ cid, tenant_sig } A->>B: message B->>B: process message A->>A: update watermark end ``` ## Considerations * the only DWNs that can be synced (aka _pushed to_ and _pulled from_) are DWNs listed in a DID Doc. * This approach requires that a syncing DWN maintain a push-watermark and pull-watermark for each DWN it wants to push to and pull from * There's a "sync echo" that inevitably occurs with the above approach. Imagine a scenario where there's DWN A and DWN B. They've never synced before. DWN B is empty. DWN A has 1 message in it. * DWN A _pushes_ the message it has to DWN B * DWN B receives the message. stores it. event is added to event log * DWN A _pulls_ from DWN B. DWN B only has 1 message and it happens to be the message that was sent by DWN A. * introducing 2 additional message types: `SyncPush` and `SyncPull` as convenience messages that facilitate pushing and pulling introduces challenges: * both Push and Pull necessitate `EventsGet` and `MessagesGet` messages, both of which need to be signed which implies that keys need to be present * _Counter Argument_: I suppose the `authorization` JWS of `SyncPush` and `SyncPull` could could have a wrapped signature that could be used for any resulting `EventsGet` and `MessagesGet` messages. haven't fully thought this through yet * probably not much benefit of _sending_ `SyncPush` and `SyncPull` messages to your other DWNs. I guess it'd be a way to manually trigger your addressable DWNs to _push_ or _pull_ * would have to decide whether the SDK wants to take on the responsibility of storing watermarks * or make `watermark` a required property * If `SyncPush` and `SyncPull` don't make sense as new message types, we could always implement them as methods that are surfaced for consumption by `dwn-sdk-js` ## PoC the chat-app demo in web5-labs is driven by a PoC of this proposed approach. * [message-store-level-v2](https://github.com/tbdeng/web5-labs/tree/main/message-store-level-v2) implements an event log. This message-store is used in [web5-wallet](https://github.com/tbdeng/web5-labs/blob/main/web5-wallet/background/dwn.js) and [addressable-dwn](https://github.com/tbdeng/web5-labs/blob/main/addressable-dwn/src/dwn.js#L2) * this would get implemented into [`MessageStoreLevel`](https://github.com/TBD54566975/dwn-sdk-js/blob/main/src/store/message-store-level.ts) in dwn-sdk-js * [addressable-dwn](https://github.com/tbdeng/web5-labs/blob/main/addressable-dwn/src/app.js#L19-L34) exposes an HTTP endpoint `/dwn/event-log` as a workaround for `EventsGet` not existing. * * this PoC endpoint **does not** have any authn/authz verification as it's just a PoC * [addressable-dwn](https://github.com/tbdeng/web5-labs/blob/main/addressable-dwn/src/app.js#L36-L60) exposes an HTTP endpoint `/dwn/messages/:cid` as a workarond for `MessagesGet` not existing * this PoC endpoint **does not** have any authn/authz verification as it's just a PoC * [`push`](https://github.com/tbdeng/web5-labs/blob/main/web5-wallet/background/alarm-handlers/push-dwn-messages.js) and [`pull`](https://github.com/tbdeng/web5-labs/blob/main/web5-wallet/background/alarm-handlers/pull-dwn-messages.js) are implemented in `web5-wallet`. they run once every minute (frequency is limited by browser extension constraints)