You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
All functionality in voyager is provided by modules and plugins. Modules provide various forms of read-only data, such as the latest height of a chain or a state proof. Plugins, on the other hand, directly interact with the queue - every plugin has their own [topic queue](https://github.com/unionlabs/union/blob/main/lib/voyager-vm/README.md) with it's plugin name as the topic, along with an interest filter that can pull messages into this queue. Plugins also define their own internal message types that they can use to pass data around between calls to their internal queue (or even between other plugins).
9
+
All functionality in voyager is provided by modules and plugins. Modules provide various forms of read-only data, such as the latest height of a chain or a state proof. Plugins, on the other hand, directly interact with the queue (see [*Plugins and the queue*](#plugins-and-the-queue) for more information).
10
10
11
11
## Types
12
12
13
13
### IBC Specification
14
14
15
15
An IBC specification defines the semantics of a light client based bridging protocol. A specification must have the following properties:
16
16
17
-
-some notion of a "light client update"
18
-
-a store specification, where client and consensus states are stored (among any other states required by the IBC specification)
19
-
-this store is required to be provable (i.e. the host environment must have some form of "proof" for it's storage, most likely merkleized)
17
+
-Some notion of a "light client update"
18
+
-A store specification, where client and consensus states are stored (among any other states required by the IBC specification)
19
+
-This store is required to be provable, i.e. the host environment must have some form of "proof" for it's storage. This is most likely achieved via a merkleized state trie, although this is not strictly required.
20
20
21
-
Everything else is an implementation detail of the ibc specification.
21
+
Everything else is an implementation detail of the IBC specification. This flexibility allows voyager to trivially support other IBC-like protocols, such as traditional IBC (referred to as `ibc-classic` throughout these docs) alongside `ibc-union`.
22
22
23
23
### Chain
24
24
25
25
A chain is defined by a few basic properties:
26
26
27
-
-produces blocks with an incrementing height (sometimes also referred to as "block number" or "slot")
28
-
-a consensus with some notion of finality, where blocks older than the latest finalized height will never reorg and are considered finalized
29
-
-a storage layer with provable state
30
-
-one or more IBC interfaces
27
+
-Produces blocks with an incrementing height (sometimes also referred to as "block number" or "slot")
28
+
-A consensus with some notion of finality, where blocks older than the latest finalized height will never reorg and are considered finalized
29
+
-A storage layer with provable state
30
+
-One or more IBC interfaces
31
31
32
32
### Consensus
33
33
34
-
A chain's consensus defines the client and consensus state types stored in the clients that verify this consensus.
34
+
A chain's consensus defines the client and consensus state types stored in the clients that verify said consensus mechanism.
35
35
36
36
#### Examples
37
37
38
-
- cometbls
39
-
- tendermint
40
-
- ethereum
38
+
-`cometbls`
39
+
-`tendermint`
40
+
-`ethereum`
41
41
42
42
### IBC Interface
43
43
44
44
An IBC interface defines the entrypoints of an IBC specification implementation on a chain. A chain can potentially have many different IBC interfaces (for example, `ibc-go` native clients vs. `08-wasm` clients), and a consensus can be verified by the same client specification on different IBC interfaces.
45
45
46
46
#### Examples
47
47
48
-
- ibc-go-v8/08-wasm
49
-
- ibc-solidity
50
-
- ibc-cosmwasm
48
+
-`ibc-go-v8/08-wasm`
49
+
-`ibc-solidity`
50
+
-`ibc-cosmwasm`
51
51
52
-
### Client
52
+
### Client Type
53
53
54
54
Clients are the mechanism used to verify a counterparty consensus. Clients are defined by 4 properties:
55
55
56
-
-compatible with an IBC specification
57
-
-on an IBC interface
58
-
-for a specific consensus mechanism
59
-
-which is verified via a consensus verification specification
The voyager binary exposes a JSON-RPC interface to allow for querying any configured chain. For example, you can query the state of any client on any chain, as long as the state module for the host chain is configured (using the voyager binary's cli):
And finally, if the client module is configured for whatever type of client this is (in this case, it happens to be `ethereum` on `ibc-cosmwasm`), `--decode` can be passed as well to receive the client state as a JSON value instead of the raw bytes:
This general concept of modularity is present in all areas of voyager. As another example, many EVM chains (various EVM L2s, custom geth fork L1s such as BSC, or fully custom EVM-compatible chains such as SEI), many of the interfaces are the exact same as ethereum mainnet. In these cases, the ethereum state module can be completely reused for these chains, just configured with a different chain ID and RPC url. The same applies to all modules, meaning that when adding support to voyager for a new chain, often times a vast majority of the work required can be fully reused from existing plugins and modules.
129
+
130
+
## Plugins and the queue
131
+
132
+
Plugins are a special type of module that also have access to the message queue. Every plugin has their own [topic queue](https://github.com/unionlabs/union/blob/main/lib/voyager-vm/README.md) with it's plugin name as the topic, along with an interest filter that can pull messages into this queue. Plugins also define their own internal message types that they can use to pass data around between calls to their internal queue (or even between other plugins).
133
+
134
+
For more information about plugin lifecycle and management, see the [`voyager-plugin-protocol`](https://github.com/unionlabs/union/blob/main/lib/voyager-plugin-protocol) crate.
135
+
136
+
## Putting it all together
137
+
138
+
The ability to query any chain in an abstract manner also drastically improves the DX and reliability of writing new plugins and modules. One area in particular where this architecture shines is when dealing with [recursive clients] (sometimes also referred to as conditional clients). Recursive clients inherently rely on state from other chains, such as L2 settlement in relation to L1 finality for the L2 finality, or requiring potentially multiple clients to be updated before the recursive client itself can be updated.
139
+
140
+
A good example of this is our [state lens client architecture][state-lens], where many modules are fully reused from existing modules. The finality of a state lens client is the finality of the "L2" client being tracked through the hop chain - this means that no additional module is required for finality, as the target chain's finality module will be used directly. Additionally, no *new* state or proof modules are required to be loaded when dealing with state lens clients, since these modules will need to be loaded for the host chain where the state lens client is on anyways. There are, however, several new plugins and modules that are required for this architecture to work:
141
+
142
+
-**Client Module**: This is standard for all new client types. The client module provides the coded for encoding and decoding various states for this client.
143
+
144
+
-**Client Bootstrap Module**: Similar to the client module, this is also standard for all new client types, however this is only required for creating new clients.
145
+
146
+
-**Client Update Plugin**: This is the most complex part of the state lens architecture. Up to two individual client updates are required to update a state lens client: the L2 client on the L1 and the L1 client on the L0 (the host chain).
147
+
148
+
This is trivially achieved by leveraging the voyager-vm messages:
149
+
150
+
```rs
151
+
// do all contained operations concurrently
152
+
conc([
153
+
// update the l2 client on the l1
154
+
promise(
155
+
[
156
+
// fetch the update headers of the l2 client
157
+
call(FetchUpdateHeaders { /* snip */ })
158
+
],
159
+
// this is the data queue of the promise callback, this allows for configuring data on creation of the promise
160
+
// in this case, there is no extra data, so it can be left empty
161
+
[],
162
+
// this is the callback that will process the data once all messages in the internal queue are processed
// do all contained operations in sequence, waiting until the head message fully resolves (i.e. returns no additional non-data messages) before processing the next message
166
+
seq([
167
+
// wait for the trusted height of the client we just updated to be finalized on the hop chain
168
+
// without this, weird things can happen with transaction ordering and reorgs
169
+
call(WaitForTrustedHeight { /* snip */ }),
170
+
// call back into this plugin to update the other clients
// wait for 1 extra block to ensure that the L1 update is in state, and this update will not end up in the same block (and potentially get reordered)
192
+
call(WaitForHeightRelative { /* snip */ }),
193
+
// this contains the actual headers for *this* client update.
194
+
data(OrderedHeaders { /* snip */ }),
195
+
]),
196
+
])
197
+
```
198
+
199
+
In building these messages, several additional modules and plugins are also needed. To update the L2 on the L1, the L2 client update plugin is required (as well as all of it's transitive requirements), and the same goes for the L1 on the L0. Additionally, in order to actually *submit* these intermediate client updates on chain, transactiopn plugins for both the L1 and L0 are required to be loaded. All of state, proof, and finality modules are also required to be loaded for the L1 as well (recall that the client update of the state lens client contains a state proof of the L2 state in the L1).
200
+
201
+
This may seem like a lot of requirements, however remember that all of the dependencies listed above were in this case already written - all that needed to be done was to configure them for the chains we need to use here, and to build the state lens client logic only 1 plugin (client update) and 2 modules (client and client bootstrap) needed to be written from scratch. The same concepts, with differing degrees of reusability, apply to L2s (arbitrum, optimism, various types of rollups), customized execution environments (SEI/ethermint), novel consensus mechanisms (beacon-kit), and even entirely new chains (sui, aptos).
202
+
203
+
The full non-abridged implementation of the state lens client update plugin can be found [here](https://github.com/unionlabs/union/blob/main/voyager/plugins/client-update/state-lens).
Voyager takes a novel approach to solving these problems. Internally, everything is modeled as a
22
-
finite state machine, ([`voyager-vm`](https://github.com/unionlabs/union/tree/ab76fd72e114a2b8db8ad469dc587aec865e2095/lib/voyager-vm)), which is stored in postgres to ensure transactional integrity ([`pg-queue`](https://github.com/unionlabs/union/tree/main/lib/pg-queue)). Every chain
19
+
finite state machine, ([`voyager-vm`](https://github.com/unionlabs/union/blob/main/lib/voyager-vm/README.md)), which is stored in postgres to ensure transactional integrity ([`pg-queue`](https://github.com/unionlabs/union/blob/main/lib/pg-queue/README.md)). Every chain
23
20
query, transaction submission, and even the data itself is represented as a state within the queue.
24
21
This design solves two of the properties mentioned above out of the box: **Data Integrity** and
25
22
**Quick Startup Times**. Since no state is stored in Voyager itself, it is able to crash and restart
@@ -31,7 +28,7 @@ messages can safely be executed in parallel. This means, for instance, that whil
31
28
fetching events from a block, another could be submitting a light client update, and another could
32
29
be generating a state proof, and so on.
33
30
34
-
For more information on voyager's architecture, see [CONCEPTS.md](https://github.com/unionlabs/union/blob/ab76fd72e114a2b8db8ad469dc587aec865e2095/voyager/CONCEPTS.md)
31
+
For more information on voyager's architecture, see [Concepts](/architecture/voyager/concepts).
0 commit comments