Skip to content

OkayRelay/relayer-engine

 
 

Repository files navigation

Relayer Engine

[TOC]

See bottom for quick start!

Objective

Define the relayer template / scaffold that consists of all of the boilerplate code that defines all of the base functionality of a relayer to transport a message from Chain A to Chain B and the interface to perform additional arbitrary off-chain computation.

This template / scaffold will serve as the base relayer for

  • specialized relayers that applications can run to serve a specific functionality
  • modular relayers in the form of a permissionless network to service users / applications by submitting arbitrary messages to arbitrary chains

Background

Prior to the relayer engine and relayer plugins, there is no modularized template for projects who want to spin up and run relayers to reference. This leads to home rolled solutions or ones that are modified from the spy relayer. This is undesirable as it adds more code-complexity and slows down integration efforts.

Goals

  • Define a relayer template that can be spun up and maintained out of the box with all base functionality
    • crash / error recovery
    • manage hot wallets
    • listen to Guardian gossip network
    • submit transactions on-chain
  • Define the relayer interface to enable applications to define arbitrary off-chain computation

Non-Goals

  • Design the economic incentives behind a relayer network

Overview

The relayer engine will serve as the foundation that future relayer development will be based upon, whether that is by application developers to provide dedicated relaying services for their application or by third party participants to provide general relaying service to the broader Wormhole ecosystem.

Detailed Design

There are four main components to a relayer:

  1. Non-validating guardiand node (spy) that is connected to the Guardian Gossip Network.
  2. Listener that observes filtered signed VAAs pushed from the spy and optionally creates workflow objects to process these VAAs
  3. Redis database that workflows are enqueued on by the Listener. Can also function with an in-memory store for ease of development
  4. Executor that pops off workflows from the database and processes them. This module has access to hot wallets

The relayer engine modularizes the Listener and Executor component through a Plugin Interface to enable custom filtering and off-chain processing of VAAs respectively.

The Listener portion of the Plugin component defines

  • type of connection to the Guardian Network (Spy connection or REST API)
  • VAA filter by emitterAddress and emitterChainID
  • process for consuming a VAA

The Executor portion of the Plugin component defines

  • how to handle workflow data generated by the Listener. In the simple case this is just a single serialized VAA, but could be more complicated depending on the use case.
  • can run actions that have exclusive access to a hot wallet. This is necessary since different ecosystems have different restrictions about concurrent wallet usage (e.g. nonce management for evm, 1 tx per wallet per block for cosmwasm, etc.).

The key interfaces to provide in a plug-in can be found here

Quick start

Add relayer-engine as a dependency by pointing at the github repo

    "relayer-engine": "wormhole-foundation/relayer-engine",

Define a plugin similar to AttestationPlugin or DummyPlugin, or check out the messenger example at https://github.com/wormhole-foundation/xdapp-book/blob/main/projects/messenger/src/plugin.ts

Define an entry point that calls run with something like the following:

await relayerEngine.run({
  plugins: [plugin],
  configs: {
    executorEnv: {
      // ...
    },
    listenerEnv: {
      // ...
    },
    commonEnv: {
      // ...
    },
  },
  mode: Mode.BOTH,
  envType: EnvType.LOCALHOST,
});

The relayer engine requires a spy node to be running (see below for what this is) On mainnet:

docker run \
    --platform=linux/amd64 \
    -p 7073:7073 \
    --entrypoint /guardiand \
    ghcr.io/wormhole-foundation/guardiand:latest \
spy --nodeKey /node.key --spyRPC "[::]:7073" --network /wormhole/mainnet/2 --bootstrap /dns4/wormhole-mainnet-v2-bootstrap.certus.one/udp/8999/quic/p2p/12D3KooWQp644DK27fd3d4Km3jr7gHiuJJ5ZGmy8hH4py7fP4FP7

On testnet:

docker run \
    --platform=linux/amd64 \
    -p 7073:7073 \
    --entrypoint /guardiand \
    ghcr.io/wormhole-foundation/guardiand:latest \
spy --nodeKey /node.key --spyRPC "[::]:7073" --network /wormhole/testnet/2/1 --bootstrap /dns4/wormhole-testnet-v2-bootstrap.certus.one/udp/8999/quic/p2p/12D3KooWAkB9ynDur1Jtoa97LBUp8RXdhzS5uHgAfdTquJbrbN7i

With wormhole local validator

HOST=
if [ "$(uname -m)" = "arm64" ]; then
   HOST="host.docker.internal"
else
   HOST="localhost"
fi

docker run \
    --platform=linux/amd64 \
    -p 7073:7073 \
    --entrypoint /guardiand \
    ghcr.io/wormhole-foundation/guardiand:latest \
spy --nodeKey /node.key --spyRPC "[::]:7073" --bootstrap /dns4/${HOST}/udp/8999/quic/p2p/12D3KooWL3XJ9EMCyZvmmGXL2LMiVBtrVa2BuESsJiXkSj7333Jw

Releases

No releases published

Packages

No packages published

Languages

  • TypeScript 99.2%
  • Dockerfile 0.8%