Skip to content

Commit 2b36e73

Browse files
feat: rewrite relayer with BaseServiceV2
Rewrites the message-relayer service to use BaseServiceV2. Significantly reduces the footprint of the message-relayer and enforces stronger input validation.
1 parent d57af52 commit 2b36e73

7 files changed

Lines changed: 66 additions & 152 deletions

File tree

.changeset/clean-hats-search.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@eth-optimism/message-relayer': minor
3+
---
4+
5+
Rewrites the message-relayer to use the BaseServiceV2.

ops/docker-compose.yml

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,6 @@ services:
123123
relayer:
124124
depends_on:
125125
- l1_chain
126-
- deployer
127126
- l2geth
128127
deploy:
129128
replicas: 0
@@ -133,14 +132,10 @@ services:
133132
target: relayer
134133
entrypoint: ./relayer.sh
135134
environment:
136-
L1_NODE_WEB3_URL: http://l1_chain:8545
137-
L2_NODE_WEB3_URL: http://l2geth:8545
138-
URL: http://deployer:8081/addresses.json
139-
# a funded hardhat account
140-
L1_WALLET_KEY: '0xdbda1821b80551c9d65939329250298aa3472ba22feea921c0cf5d620ea67b97'
135+
MESSAGE_RELAYER__L1RPCPROVIDER: http://l1_chain:8545
136+
MESSAGE_RELAYER__L2RPCPROVIDER: http://l2geth:8545
137+
MESSAGE_RELAYER__L1WALLET: '0xdbda1821b80551c9d65939329250298aa3472ba22feea921c0cf5d620ea67b97'
141138
RETRIES: 60
142-
POLLING_INTERVAL: 500
143-
GET_LOGS_INTERVAL: 500
144139

145140
verifier:
146141
depends_on:

ops/scripts/relayer.sh

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,6 @@ set -e
44

55
RETRIES=${RETRIES:-60}
66

7-
if [[ ! -z "$URL" ]]; then
8-
# get the addrs from the URL provided
9-
ADDRESSES=$(curl --fail --show-error --silent --retry-connrefused --retry $RETRIES --retry-delay 5 $URL)
10-
# set the env
11-
export ADDRESS_MANAGER_ADDRESS=$(echo $ADDRESSES | jq -r '.AddressManager')
12-
fi
13-
147
# waits for l2geth to be up
158
curl \
169
--fail \
@@ -20,7 +13,7 @@ curl \
2013
--retry-connrefused \
2114
--retry $RETRIES \
2215
--retry-delay 1 \
23-
$L2_NODE_WEB3_URL
16+
$MESSAGE_RELAYER__L2RPCPROVIDER
2417

2518
# go
2619
exec yarn start

packages/common-ts/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
"url": "https://github.com/ethereum-optimism/optimism.git"
3232
},
3333
"dependencies": {
34-
"@eth-optimism/core-utils": "^0.7.7",
34+
"@eth-optimism/core-utils": "0.8.1",
3535
"@sentry/node": "^6.3.1",
3636
"bcfg": "^0.1.7",
3737
"commander": "^9.0.0",

packages/message-relayer/bin/run.ts

Lines changed: 0 additions & 109 deletions
This file was deleted.

packages/message-relayer/package.json

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"dist/*"
99
],
1010
"scripts": {
11-
"start": "ts-node ./bin/run.ts",
11+
"start": "ts-node ./src/service.ts",
1212
"build": "tsc -p ./tsconfig.build.json",
1313
"clean": "rimraf dist/ ./tsconfig.build.tsbuildinfo",
1414
"lint": "yarn lint:fix && yarn lint:check",
@@ -31,13 +31,11 @@
3131
"dependencies": {
3232
"@eth-optimism/common-ts": "0.2.1",
3333
"@eth-optimism/core-utils": "0.8.1",
34-
"@eth-optimism/sdk": "^0.2.5",
35-
"@sentry/node": "^6.3.1",
36-
"bcfg": "^0.1.6",
37-
"dotenv": "^10.0.0",
34+
"@eth-optimism/sdk": "0.2.5",
3835
"ethers": "^5.5.4"
3936
},
4037
"devDependencies": {
38+
"@ethersproject/abstract-provider": "^5.5.1",
4139
"@nomiclabs/hardhat-ethers": "^2.0.2",
4240
"@nomiclabs/hardhat-waffle": "^2.0.1",
4341
"@typescript-eslint/eslint-plugin": "^4.26.0",

packages/message-relayer/src/service.ts

Lines changed: 53 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* Imports: External */
2-
import { Wallet } from 'ethers'
2+
import { Signer } from 'ethers'
33
import { sleep } from '@eth-optimism/core-utils'
44
import {
55
BaseServiceV2,
@@ -15,6 +15,7 @@ type MessageRelayerOptions = {
1515
l2RpcProvider: Provider
1616
l1Wallet: Signer
1717
fromL2TransactionIndex?: number
18+
}
1819

1920
type MessageRelayerMetrics = {
2021
highestCheckedL2Tx: Gauge
@@ -74,28 +75,22 @@ export class MessageRelayerService extends BaseServiceV2<
7475
})
7576
}
7677

77-
private state: {
78-
messenger: CrossChainMessenger
79-
highestCheckedL2Tx: number
80-
} = {} as any
81-
82-
protected async _init(): Promise<void> {
83-
this.logger.info('Initializing message relayer', {
84-
relayGasLimit: this.options.relayGasLimit,
85-
fromL2TransactionIndex: this.options.fromL2TransactionIndex,
86-
pollingInterval: this.options.pollingInterval,
87-
getLogsInterval: this.options.getLogsInterval,
88-
})
78+
protected async init(): Promise<void> {
79+
this.state.wallet = this.options.l1Wallet.connect(
80+
this.options.l1RpcProvider
81+
)
8982

90-
const l1Network = await this.options.l1Wallet.provider.getNetwork()
83+
const l1Network = await this.state.wallet.provider.getNetwork()
9184
const l1ChainId = l1Network.chainId
9285
this.state.messenger = new CrossChainMessenger({
93-
l1SignerOrProvider: this.options.l1Wallet,
86+
l1SignerOrProvider: this.state.wallet,
9487
l2SignerOrProvider: this.options.l2RpcProvider,
9588
l1ChainId,
9689
})
9790

9891
this.state.highestCheckedL2Tx = this.options.fromL2TransactionIndex || 1
92+
this.state.highestKnownL2Tx =
93+
await this.state.messenger.l2Provider.getBlockNumber()
9994
}
10095

10196
protected async main(): Promise<void> {
@@ -132,6 +127,40 @@ export class MessageRelayerService extends BaseServiceV2<
132127
block.transactions[0].hash
133128
)
134129

130+
// No messages in this transaction so we can move on to the next one.
131+
if (messages.length === 0) {
132+
this.state.highestCheckedL2Tx++
133+
return
134+
}
135+
136+
// Make sure that all messages sent within the transaction are finalized. If any messages
137+
// are not finalized, then we're going to break the loop which will trigger the sleep and
138+
// wait for a few seconds before we check again to see if this transaction is finalized.
139+
let isFinalized = true
140+
for (const message of messages) {
141+
const status = await this.state.messenger.getMessageStatus(message)
142+
if (
143+
status === MessageStatus.IN_CHALLENGE_PERIOD ||
144+
status === MessageStatus.STATE_ROOT_NOT_PUBLISHED
145+
) {
146+
isFinalized = false
147+
}
148+
}
149+
150+
if (!isFinalized) {
151+
this.logger.info(
152+
`tx not yet finalized, waiting: ${this.state.highestCheckedL2Tx}`
153+
)
154+
return
155+
} else {
156+
this.logger.info(
157+
`tx is finalized, relaying: ${this.state.highestCheckedL2Tx}`
158+
)
159+
}
160+
161+
// If we got here then all messages in the transaction are finalized. Now we can relay
162+
// each message to L1.
163+
for (const message of messages) {
135164
try {
136165
const tx = await this.state.messenger.finalizeMessage(message)
137166
this.logger.info(`relayer sent tx: ${tx.hash}`)
@@ -142,13 +171,16 @@ export class MessageRelayerService extends BaseServiceV2<
142171
} else {
143172
throw err
144173
}
145-
} catch (err) {
146-
this.logger.error('Caught an unhandled error', {
147-
message: err.toString(),
148-
stack: err.stack,
149-
code: err.code,
150-
})
151174
}
175+
await this.state.messenger.waitForMessageReceipt(message)
152176
}
177+
178+
// All messages have been relayed so we can move on to the next block.
179+
this.state.highestCheckedL2Tx++
153180
}
154181
}
182+
183+
if (require.main === module) {
184+
const service = new MessageRelayerService()
185+
service.run()
186+
}

0 commit comments

Comments
 (0)