Skip to content

Commit

Permalink
Add bulk sync documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
Jamie Bertram committed Dec 8, 2023
1 parent d589086 commit 27b5df4
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 23 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
---
title: MarloweBulkSync sub-protocol
sidebar_position: 3
---

The MarloweBulkSync sub-protocol is defined here:

- **[https://github.com/input-output-hk/marlowe-cardano/blob/main/marlowe-runtime/sync-api/Language/Marlowe/Protocol/BulkSync/Types.hs](https://github.com/input-output-hk/marlowe-cardano/blob/main/marlowe-runtime/sync-api/Language/Marlowe/Protocol/BulkSync/Types.hs)**

The MarloweBulkSync sub-protocol is used to synchronize all marlowe contract transactions.
The client receives a stream of blocks, each of which contains collections of create, apply inputs, and withdraw transactions.

This is a firehose protocol. It gives far more information than the header sync
or regular sync protocols, but for following a small set of contracts may be an
inefficient choice.

### Sub-protocol states

| Protocol state | Agency | Description |
| --- | --- | --- |
| 1. `Idle` | `Client` | The initial state. |
| 2. `Intersect` | `Server` | When the client asks the server to fast forward to a known chain point. |
| 3. `Next` | `Server` | When the client asks the server to provide the next block of marlowe transactions. |
| 4. `Poll` | `Client` | When the server has no more blocks to send (i.e., the client has reached the tip of the chain). |
| 5. `Done` | `Nobody` | The terminal state. |

### The Intersect state

The Intersect is when the client asks the server to fast forward to a known chain point.
For example, in a situation where the client has already done a fair amount of synchronization, and then quits, when it starts up again, rather than starting over from Genesis, it can instead start from the point where it last left off.
The Intersect is the server recognizing a point that both it and the client know about, then starting from there.
On the other hand, if the server does not or cannot recognize what the client is referencing, it will start from the beginning of the chain (from Genesis).

### MarloweHeaderSync sub-protocol messages

| Message | Begin state | End state | Parameter | Description |
| --- | --- | --- | --- | --- |
| 1. `RequestNext` | `Idle` | `Next` | | The client requests the next block of headers from the server. |
| | | | `extraCount` | a number in the range [0, 255] that represents the number of *extra* blocks to fetch (0 = 1 block will be fetched). |
| 2. `RollForward blks blockHeader` | `Next` | `Idle` | | The server sends the next n blocks of transactions to the client. |
| | | | `blks` | The next extraCount + 1 blocks in the chain. |
| | | | `tip` | The tip of the chain. |
| 3. `RollBackward point tip` | `Next` | `Idle` | | The client's current position was rolled back, the server tells the client of the point to which it was rolled back. |
| | | | `point` | Chain point (either a block header or Genesis if the chain has rolled all the way back to Genesis). |
| | | | `tip` | The tip of the chain. (either a block header or Genesis). |
| 4. `Wait` | `Next` | `Poll` | | The client is at the chain tip. There are no more Marlowe contract transactions to send. The client may choose to wait and poll until more are available. |
| 5. `Poll` | `Poll` | `Next` | | The client is checking with the server to find out if there are new blocks available. |
| 6. `Cancel` | `Poll` | `Idle` | | The client doesn't wish to wait, and returns to the idle state. Usually, when you send a `cancel`, in nearly all cases, it is followed by a `done` message. This is the case for clients that are only concerned about getting everything that is currently on the chain. Once that point is reached, when it reaches the tip, it communicates `done`. |
| 7. `Done` | `Idle` | `Done` | | Terminates the session. |
| 8. `Intersect blks` | `Idle` | `Intersect` | | The client tells the server which blocks it has already seen so that the server can start syncing from an appropriate point in the chain. |
| | | | `blks` | A contiguous list of block headers in ascending order. These block headers represent the most recent blocks from the client's chain. |
| 9. `IntersectFound blk` | `Intersect` | `Idle` | | The server has found an intersection point with the client and will start syncing *after* this point (i.e., the next `RollForward` message will be after this block). |
| | | | `blk` | The most recent block contained in both the client's chain and the server's chain. |
| 10. `IntersectNotFound` | `Intersect` | `Idle` | |The server was unable to find an intersection point with the client and will start syncing from Genesis. |

Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ stateDiagram-v2
state "Init" as init
state "MarloweSync" as ms
state "MarloweHeaderSync" as mhs
state "MarloweBulkSync" as mbs
state "MarloweQuery" as mq
state "TxJob" as tj
state "MarloweLoad" as ml
Expand All @@ -58,20 +59,23 @@ stateDiagram-v2
[*] --> init
init --> ms: RunMarloweSync
init --> mhs: RunMarloweHeaderSync
init --> mbs: RunMarloweBulkSync
init --> mq: RunMarloweQuery
init --> tj: RunTxJob
init --> ml: RunMarloweLoad
init --> cq: RunContractQuery
init --> mt: RunMarloweTransfer
ms --> ms: MarloweSync
mhs --> mhs: MarloweHeaderSync
mbs --> mbs: MarloweBulkSync
mq --> mq: MarloweQuery
tj --> tj: TxJob
ml --> ml: MarloweLoad
cq --> cq: ContractQuery
mt --> mt: MarloweTransfer
ms --> [*]
mhs --> [*]
mbs --> [*]
mq --> [*]
tj --> [*]
ml --> [*]
Expand All @@ -95,6 +99,7 @@ The Marlowe Runtime protocol consists of four sub-protocols:

1. **[Marlowe Sync](marlowesync-subprotocol.md)**
2. **[Marlowe Header Sync](marloweheadersync-subprotocol.md)**
2. **[Marlowe Bulk Sync](marlowebulksync-subprotocol.md)**
3. **[Marlowe Query](marlowequery-subprotocol.md)**
4. **[Tx Job](txjob-subprotocol.md)**
5. **[Marlowe Load](marloweload-subprotocol.md)**
Expand All @@ -112,11 +117,12 @@ At any given time, the Marlowe Runtime protocol can be in one of five states:
1. `Init`
2. `MarloweSync`
3. `MarloweHeaderSync`
4. `MarloweQuery`
5. `TxJob`
6. `MarloweLoad`
7. `ConractQuery`
8. `MarloweTransfer`
4. `MarloweBulkSync`
5. `MarloweQuery`
6. `TxJob`
7. `MarloweLoad`
8. `ConractQuery`
9. `MarloweTransfer`

There is an `init` state, then there is one protocol state per sub-protocol.
These states transition in a fairly straightforward manner.
Expand All @@ -134,15 +140,17 @@ Once in that protocol state, the protocol stays there for the rest of the sessio
| | | `st` | A protocol state from **[MarloweSync](#1-marlowe-sync-sub-protocol)** |
| 3. `MarloweHeaderSync st` | Determined by `st` | | The peers are communicating via the `MarloweHeaderSync` sub-protocol. |
| | | `st` | A protocol state from **[MarloweHeaderSync](#1-marlowe-header-sync-sub-protocol)** |
| 4. `MarloweQuery st` | Determined by `st` | | The peers are communicating via the `Query MarloweSyncRequest` sub-protocol. |
| 4. `MarloweBulkSync st` | Determined by `st` | | The peers are communicating via the `MarloweBulkSync` sub-protocol. |
| | | `st` | A protocol state from **[MarloweBulkSync](#1-marlowe-bulk-sync-sub-protocol)** |
| 5. `MarloweQuery st` | Determined by `st` | | The peers are communicating via the `Query MarloweSyncRequest` sub-protocol. |
| | | `st` | A protocol state from **[Query MarloweSyncRequest](#1-marlowe-query-sub-protocol)** |
| 5. `TxJob st` | Determined by `st` | | The peers are communicating via the `Job MarloweTxCommand` sub-protocol. |
| 6. `TxJob st` | Determined by `st` | | The peers are communicating via the `Job MarloweTxCommand` sub-protocol. |
| | | `st` | A protocol state from **[Job MarloweTxCommand](#1-tx-job-sub-protocol)** |
| 6. `MarloweLoad st` | Determined by `st` | | The peers are communicating via the `MarloweLoad` sub-protocol. |
| 7. `MarloweLoad st` | Determined by `st` | | The peers are communicating via the `MarloweLoad` sub-protocol. |
| | | `st` | A protocol state from **[MarloweLoad](#1-marlowe-load-sub-protocol)** |
| 7. `ContractQuery st` | Determined by `st` | | The peers are communicating via the `Query ContractRequest` sub-protocol. |
| 8. `ContractQuery st` | Determined by `st` | | The peers are communicating via the `Query ContractRequest` sub-protocol. |
| | | `st` | A protocol state from **[Query ContractRequest](#1-contract-query-sub-protocol)** |
| 8. `MarloweTransfer st` | Determined by `st` | | The peers are communicating via the `MarloweTransfer` sub-protocol. |
| 9. `MarloweTransfer st` | Determined by `st` | | The peers are communicating via the `MarloweTransfer` sub-protocol. |
| | | `st` | A protocol state from **[MarloweTransfer](#1-marlowe-transfer-sub-protocol)** |


Expand All @@ -156,24 +164,27 @@ For example, the `MarloweSync` message type embeds a message from the sub-protoc
| --- | --- | --- | --- | --- |
| 1. `RunMarloweSync` | `Init` | `MarloweSync Init` | | Start a `MarloweSync` session. |
| 2. `RunMarloweHeaderSync` | `Init` | `MarloweHeaderSync Idle` | | Start a `MarloweHeaderSync` session. |
| 3. `RunMarloweQuery` | `Init` | `MarloweQuery Req` | | Start a `MarloweQuery` session. |
| 4. `RunTxJob` | `Init` | `TxJob Init` | | Start a `TxJob` session. |
| 5. `RunMarloweLoad` | `Init` | `MarloweLoad (Processing RootNode)` | | Start a `MarloweLoad` session. |
| 6. `RunContractQuery` | `Init` | `ContractQuery Req` | | Start a `ContractQuery` session. |
| 7. `RunMarloweTransfer` | `Init` | `MarloweTransfer Idle` | | Start a `MarloweTransfer` session. |
| 8. `MarloweSync msg` | `MarloweSync st` | `MarloweSync st'` | | Wrap a `MarloweSync` message. |
| 3. `RunMarloweBulkSync` | `Init` | `MarloweBulkSync Idle` | | Start a `MarloweBulkSync` session. |
| 4. `RunMarloweQuery` | `Init` | `MarloweQuery Req` | | Start a `MarloweQuery` session. |
| 5. `RunTxJob` | `Init` | `TxJob Init` | | Start a `TxJob` session. |
| 6. `RunMarloweLoad` | `Init` | `MarloweLoad (Processing RootNode)` | | Start a `MarloweLoad` session. |
| 7. `RunContractQuery` | `Init` | `ContractQuery Req` | | Start a `ContractQuery` session. |
| 8. `RunMarloweTransfer` | `Init` | `MarloweTransfer Idle` | | Start a `MarloweTransfer` session. |
| 9. `MarloweSync msg` | `MarloweSync st` | `MarloweSync st'` | | Wrap a `MarloweSync` message. |
| | | | `msg` | A `MarloweSync` message with begin state `st` and end state `st'` |
| 9. `MarloweHeaderSync msg` | `MarloweHeaderSync st` | `MarloweHeaderSync st'` | | Wrap a `MarloweHeaderSync` message. |
| 10. `MarloweHeaderSync msg` | `MarloweHeaderSync st` | `MarloweHeaderSync st'` | | Wrap a `MarloweHeaderSync` message. |
| | | | `msg` | A `MarloweHeaderSync` message with begin state `st` and end state `st'` |
| 10. `MarloweQuery msg` | `MarloweQuery st` | `MarloweQuery st'` | | Wrap a `MarloweQuery` message. |
| 11. `MarloweBulkSync msg` | `MarloweBulkSync st` | `MarloweBulkSync st'` | | Wrap a `MarloweBulkSync` message. |
| | | | `msg` | A `MarloweBulkSync` message with begin state `st` and end state `st'` |
| 12. `MarloweQuery msg` | `MarloweQuery st` | `MarloweQuery st'` | | Wrap a `MarloweQuery` message. |
| | | | `msg` | A `MarloweQuery` message with begin state `st` and end state `st'` |
| 11. `TxJob msg` | `TxJob st` | `TxJob st'` | | Wrap a `Job MarloweTxCommand` message. |
| 13. `TxJob msg` | `TxJob st` | `TxJob st'` | | Wrap a `Job MarloweTxCommand` message. |
| | | | `msg` | A `TxJob` message with begin state `st` and end state `st'` |
| 12. `MarloweLoad msg` | `MarloweLoad st` | `MarloweLoad st'` | | Wrap a `Job MarloweTxCommand` message. |
| 14. `MarloweLoad msg` | `MarloweLoad st` | `MarloweLoad st'` | | Wrap a `Job MarloweTxCommand` message. |
| | | | `msg` | A `MarloweLoad` message with begin state `st` and end state `st'` |
| 13. `ContractQuery msg` | `ContractQuery st` | `ContractQuery st'` | | Wrap a `Job MarloweTxCommand` message. |
| 15. `ContractQuery msg` | `ContractQuery st` | `ContractQuery st'` | | Wrap a `Job MarloweTxCommand` message. |
| | | | `msg` | A `ContractQuery` message with begin state `st` and end state `st'` |
| 14. `MarloweTransfer msg` | `MarloweTransfer st` | `MarloweTransfer st'` | | Wrap a `Job MarloweTxCommand` message. |
| 16. `MarloweTransfer msg` | `MarloweTransfer st` | `MarloweTransfer st'` | | Wrap a `Job MarloweTxCommand` message. |
| | | | `msg` | A `MarloweTransfer` message with begin state `st` and end state `st'` |

### Binary format for sending messages over TCP
Expand All @@ -188,7 +199,7 @@ If you are using Haskell, use the **[Marlowe client library](https://github.com/
## Messaging behavior

On a functional level, the Marlowe Runtime protocol multiplexes the four sub-protocols into one.
The client always sends one of these seven message types (`RunMarloweSync`, `RunMarloweHeaderSync`, `RunMarloweQuery`, `RunTxJob`, `RunMarloweLoad`, `RunContractQuery`, `RunMarloweTransfer`) to start.
The client always sends one of these seven message types (`RunMarloweSync`, `RunMarloweHeaderSync`, `RunMarloweBulkSync`, `RunMarloweQuery`, `RunTxJob`, `RunMarloweLoad`, `RunContractQuery`, `RunMarloweTransfer`) to start.
Depending on which one it started the session with, it will then continuously send that message type between client and server.
If it starts with `RunMarloweSync`, the client and server will then just exchange `MarloweSync` messages back and forth.
Inside each of those is a message from the underlying `MarloweSync` protocol.
Expand Down

0 comments on commit 27b5df4

Please sign in to comment.