diff --git a/voyager/README.md b/voyager/README.md index f5c8d1d5d94..beedd2b7ffe 100644 --- a/voyager/README.md +++ b/voyager/README.md @@ -1,67 +1,313 @@ # Voyager Architecture -Relaying is hard. There are several key properties to a reliable relayer, the -most important of which being: - -- **Speed.** IBC Relaying is a race to the bottom, with many relayers fighting - to be the first to submit a packet, often times submitting a packet that ends - up being frontrun. -- **Data Integrity.** There's no use being the first to submit a packet if the - packet is submitted incorrectly, and a good relayer will never drop packets. - The latter is especially important for ordered channels, as a channel will be - closed if a packet on it times out. -- **Quick Startup Times.** RPCs are unreliable, and it's incredibly difficult to - build around every possible failure case - especially when connecting to - multiple different chains. Even with proper error handling and retry logic, in - the event of a crash, startup time should be miniscule (see: - ) - -Voyager takes a novel approach to solving these problems. Internally, everything -is modeled as a finite state machine, ([`voyager-vm`]), which is stored in -postgres to ensure transactional integrity ([`pg-queue`]). Every chain query, -transaction submission, and even the data itself is represented as a state -within the queue. This design solves two of the properties mentioned above out -of the box: **Data Integrity** and **Quick Startup Times**. Since no state is -stored in Voyager itself, it is able to crash and restart exactly where it left -off, making startup times lightning fast; and since every message is processed -within a postgres transaction, we are guaranteed that the data we're working -with is correct (barring a bug in the business logic, of course). The final -property, **Speed**, is also solved by this design - since each message fully -encapsulates all the state it needs to operate, multiple messages can safely be -executed in parallel. This means, for instance, that while one worker is -fetching events from a block, another could be submitting a light client update, -and another could be generating a state proof, and so on. - -More information on voyager's architecture can be found [here][concepts]. +## Overview + +Relaying in IBC-based systems is intrinsically difficult. A relayer operates in a highly adversarial and failure-prone environment: multiple relayers compete to submit the same messages, RPC endpoints are unreliable, chains may experience reorgs, and incorrect submissions can cause permanent protocol-level failures. Voyager is designed from first principles to address these realities. + +A reliable relayer must satisfy three core properties: + +### Speed + +IBC relaying is a competitive, latency-sensitive process. Multiple relayers observe the same on-chain events and race to submit packets, acknowledgements, or client updates. In practice, this often leads to frontrunning, wasted transactions, and redundant work. A relayer must therefore maximize throughput while avoiding unnecessary serialization. + +### Data Integrity + +Speed alone is insufficient. Submitting incorrect data—whether malformed packets, invalid proofs, or stale client updates—results in failed transactions at best and protocol-level faults at worst. In particular, **ordered channels are unforgiving**: if a single packet times out or is skipped, the entire channel may be permanently closed. A correct relayer must never drop packets and must guarantee that submitted data is internally consistent. + +### Fast Startup and Crash Recovery + +RPCs are unreliable and heterogeneous, especially when interacting with many different chains. While defensive error handling and retries help, crashes are inevitable. A production relayer must treat crashes as a normal operating condition and be able to restart quickly, resuming exactly where it left off without expensive recovery logic or resynchronization (see the xion relayer postmortem for a concrete example). + +--- + +## Architectural Approach + +Voyager addresses these constraints by modeling the entire relaying system as a **persistent finite state machine**. + +At the core of Voyager is `voyager-vm`, an execution model in which: + +- Every chain query +- Every transaction submission +- Every proof generation step +- And even intermediate data itself + +is represented explicitly as a state transition. + +These states are persisted in PostgreSQL via `pg-queue`, providing strong transactional guarantees. + +### Transactional State Machine + +Each message processed by Voyager runs inside a database transaction: + +- State transitions are atomic +- Partial execution cannot corrupt global state +- Failed operations are safely retried + +Because all state lives in PostgreSQL rather than in-memory structures, Voyager can crash and restart without losing progress. On restart, workers simply resume processing queued states, resulting in **near-instant startup times**. + +### Parallelism by Construction + +Each message fully encapsulates the state it needs to execute. This allows Voyager to safely process multiple messages concurrently without coordination hazards. + +For example: + +- One worker may be fetching block events +- Another may be submitting a light client update +- A third may be generating a state proof + +All of these operations can proceed in parallel, dramatically improving throughput while preserving correctness. In this way, Voyager’s architecture simultaneously satisfies speed, data integrity, and fast recovery—without trade-offs. + +For a deeper dive into the execution model, see the detailed Voyager architecture documentation. ## Light Clients -Voyager implements the relaying logic for several light client protocols. Some -of these are existing specifications, such as tendermint and ethereum, but most -are custom implementations for chains Union has connected to IBC. +Voyager implements relaying logic for multiple light client protocols. + +### Supported Client Types + +- **Standard specifications**: + + - Tendermint + - Ethereum + +- **Custom client implementations**: + + - Designed for chains connected to Union + - Often extend existing Ethereum or Tendermint logic + - Add protocol-specific finality rules + +The modular architecture allows Voyager to support new light clients without rewriting core logic. + +--- + +## Ethereum L2 Clients (Conditional Clients) + +Voyager supports several Ethereum Layer 2 networks using **conditional (recursive) light clients**. + +### Key Verification Steps + +For Ethereum L2s, Voyager verifies: + +1. The L2 rollup contract’s account root on L1 +2. That the L2 state is committed in the rollup contract +3. That the IBC account root matches the rollup state root + +### Consensus Height Model + +- The consensus height of an L2 client is derived from the L1 +- For Ethereum L2s, this is typically the **Beacon Chain height** +- An L2 client can only be updated if the corresponding L1 client has a valid consensus state + +### Finality Model + +L2 finality is defined as: + +``` +L2 finality time = L2 settlement period + L1 finality time +``` + +This ensures that L2 state is only considered finalized once it is economically and cryptographically secure. + +--- + +## Core Concepts + +### IBC Specification + +An IBC specification defines the semantics of a light-client-based bridging protocol. Every specification must include: + +- A notion of a **light client update** +- A **provable store** for client and consensus states +- A host environment capable of producing cryptographic proofs (typically Merkle-based) + +Voyager supports multiple specifications simultaneously, including: + +- **ibc-union** +- **ibc-classic** (traditional IBC) + +--- + +### Chain + +A chain in Voyager is defined by: + +- Monotonically increasing block heights +- A consensus mechanism with finality +- A provable storage layer +- One or more IBC interfaces + +--- + +### Consensus + +Consensus defines: + +- Client state type +- Consensus state type +- Verification rules + +Examples: + +- Tendermint +- CometBLS +- Ethereum + +--- + +### IBC Interface + +An IBC interface defines how an IBC specification is implemented on a chain. + +A single chain may expose multiple interfaces. + +Examples: + +- ibc-go-v8 / 08-wasm +- ibc-go-v8 native +- ibc-solidity +- ibc-cosmwasm + +--- + +### Client Type + +A client type is defined by four properties: + +1. Compatible IBC specification +2. IBC interface +3. Consensus mechanism +4. Verifier implementation + +This abstraction allows the same consensus to be verified across different chains and interfaces. + +--- + +## Modules and Plugins + +Voyager functionality is entirely composed of **modules** and **plugins**. + +### Modules + +- Provide read-only functionality +- Examples: + + - Chain height queries + - Proof generation + - Finality tracking + +### Plugins + +- Interact directly with the message queue +- Perform state transitions +- Submit transactions +- Coordinate complex workflows + +Plugins may define custom internal message types and manage their own queues. + +--- + +## JSON-RPC Interface + +Voyager exposes a JSON-RPC API for querying chain and client state. + +Capabilities include: + +- Querying client state at a specific height +- Querying latest finalized state +- Decoding client state into structured JSON + +This interface significantly improves developer experience and debugging capabilities. + +--- + +## Modularity and Reuse + +Voyager’s architecture allows extensive reuse: + +- Ethereum state modules can be reused across: + + - Ethereum mainnet + - L2s + - Custom EVM chains (BSC, SEI, etc.) + +Adding support for a new chain often requires **configuration, not new code**. + +--- + +## Plugins and the Queue + +Each plugin: + +- Owns a dedicated queue topic +- Defines an interest filter +- Consumes only relevant messages + +Plugins can: + +- Spawn internal workflows +- Communicate across plugins +- Chain asynchronous operations + +This model enables complex relaying logic without tight coupling. + +--- + +## Recursive (State Lens) Clients + +Recursive clients rely on state from other chains. + +### Example: State Lens Clients + +- L2 client finalized via L1 +- L1 client finalized via L0 (host chain) + +Voyager coordinates these dependencies using structured VM messages. + +### Update Flow + +- Update L2 client on L1 +- Wait for finality +- Update L1 client on L0 +- Submit final state lens update + +Concurrency (`conc`) and sequencing (`seq`) primitives ensure correctness while maximizing parallelism. + +--- + +## Required Components for Recursive Clients + +To support state lens clients, Voyager requires: + +- Client module +- Client bootstrap module +- Client update plugin +- Transaction plugins for each involved chain +- State, proof, and finality modules + +Most components are reusable; only minimal new logic is required. + +--- + +## Extensibility + +The same architectural principles apply to: -Many of these custom light clients build off of our existing light client -infrastructure for ethereum and tendermint, with additional logic specific to -the protocol's finality. +- Ethereum rollups (Arbitrum, Optimism) +- Custom execution environments (Ethermint, SEI) +- Novel consensus mechanisms (Beacon Kit) +- Entirely new chains (Sui, Aptos) -### L2 Clients +Voyager’s design ensures that complexity scales **linearly**, not exponentially, as new chains and protocols are added. -Voyager supports several Ethereum L2s, which are implemented as conditional -light clients (TODO: link to our doc on conditional clients) +--- -The settlement condition and update logic is different for each L2, but the -basic principles are the same: +## Summary -- Verify the account root of the L2 rollup contract on the L1 -- Verify the L2 state is stored in the L2 rollup contract -- Verify the IBC account root against the rollup root +Voyager’s architecture achieves: -The consensus height of L2 clients is the consensus height of the L1 (which in -the case of Ethereum L2s is the height of the beacon chain), and L2 clients are -can only be updated to heights that the L1 client it tracks has a consensus -state for. As such, the finality time for L2s is the L2 settlement period + L1 -finality time. +- **High-speed relaying** through parallel execution +- **Strong correctness guarantees** via transactional state machines +- **Instant recovery** after crashes +- **Deep modularity and reuse** across chains and protocols -[concepts]: ./CONCEPTS.md -[`pg-queue`]: ../lib/pg-queue -[`voyager-vm`]: ../lib/voyager-vm +This makes Voyager a robust foundation for next-generation IBC relaying across heterogeneous blockchain ecosystems.