[TOC]
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
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.
- 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
- Design the economic incentives behind a relayer network
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.
There are four main components to a relayer:
- Non-validating guardiand node (spy) that is connected to the Guardian Gossip Network.
- Listener that observes filtered signed VAAs pushed from the spy and optionally creates workflow objects to process these VAAs
- Redis database that workflows are enqueued on by the Listener. Can also function with an in-memory store for ease of development
- 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
andemitterChainID
- 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
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