diff --git a/packages/message-relayer/.env.example b/packages/message-relayer/.env.example index 7d0bf81d89..4da183d016 100644 --- a/packages/message-relayer/.env.example +++ b/packages/message-relayer/.env.example @@ -14,3 +14,6 @@ FILTER_ENDPOINT=http://localhost:8080/boba-addr.json MAX_WAIT_TIME_S=5 MAX_WAIT_TX_TIME_S=5 FAST_RELAYER=true + +#optional +RELAYER_FILTER_WHITELIST=ADDRESS_1,ADDRESS_2,ADDRESS_3 diff --git a/packages/message-relayer/package.json b/packages/message-relayer/package.json index 30aa2dbf16..849133eec9 100644 --- a/packages/message-relayer/package.json +++ b/packages/message-relayer/package.json @@ -10,6 +10,7 @@ "scripts": { "start": "ts-node ./src/exec/run.ts", "build": "tsc -p ./tsconfig.json", + "test": "hardhat test --show-stack-traces", "clean": "rimraf dist/ ./tsconfig.tsbuildinfo", "lint": "yarn lint:fix && yarn lint:check", "pre-commit": "lint-staged", @@ -57,6 +58,8 @@ "hardhat": "^2.12.5", "lint-staged": "11.0.0", "prettier": "^2.3.1", - "typescript": "^4.3.5" + "typescript": "^4.3.5", + "ip": "^1.1.5", + "chai": "^4.3.4" } } diff --git a/packages/message-relayer/src/exec/run.ts b/packages/message-relayer/src/exec/run.ts index d068d1d854..3f1ad84375 100644 --- a/packages/message-relayer/src/exec/run.ts +++ b/packages/message-relayer/src/exec/run.ts @@ -121,6 +121,12 @@ const main = async () => { env.ENABLE_RELAYER_FILTER === 'true' ) + // add the whitelist of addresses to the filter + const RELAYER_FILTER_WHITELIST = config.str( + 'relayer-filter-whitelist', + env.RELAYER_FILTER_WHITELIST || '' + ) + if (!L1_NODE_WEB3_URL) { throw new Error('Must pass L1_NODE_WEB3_URL') } @@ -170,6 +176,7 @@ const main = async () => { resubmissionTimeout: RESUBMISSION_TIMEOUT * 1000, isFastRelayer: FAST_RELAYER, enableRelayerFilter: ENABLE_RELAYER_FILTER, + relayerFilterWhitelist: RELAYER_FILTER_WHITELIST, }) await service.start() diff --git a/packages/message-relayer/src/service.ts b/packages/message-relayer/src/service.ts index 0188620365..cde2976909 100644 --- a/packages/message-relayer/src/service.ts +++ b/packages/message-relayer/src/service.ts @@ -83,6 +83,9 @@ interface MessageRelayerOptions { isFastRelayer: boolean enableRelayerFilter: boolean + + // extra relayer filter + relayerFilterWhitelist: string } export class MessageRelayerService extends BaseService { @@ -537,6 +540,7 @@ export class MessageRelayerService extends BaseService { filter.Proxy__L1StandardBridge, filter.Proxy__L1NFTBridge, filter.Proxy__L1ERC1155Bridge, + ...this.options.relayerFilterWhitelist.split(','), ] this.state.lastFilterPollingTimestamp = new Date().getTime() diff --git a/packages/message-relayer/test/filter.spec.ts b/packages/message-relayer/test/filter.spec.ts new file mode 100644 index 0000000000..33ba90f030 --- /dev/null +++ b/packages/message-relayer/test/filter.spec.ts @@ -0,0 +1,101 @@ +import { expect } from './setup' +import { ethers } from 'hardhat' +import { MessageRelayerService } from '../src' + +describe('message relayer filter tests', () => { + const Proxy__L1StandardBridge = ethers.Wallet.createRandom().address + const Proxy__L1LiquidityPool = ethers.Wallet.createRandom().address + const Proxy__L1NFTBridge = ethers.Wallet.createRandom().address + const Proxy__L1ERC1155Bridge = ethers.Wallet.createRandom().address + const L1Message = ethers.Wallet.createRandom().address + + let messageRelayerService: any + + const apiPort = 3000 + let apiEndpoint: string + + before(async () => { + /* eslint-disable */ + const http = require('http') + const ip = require("ip") + // start local server + const server = module.exports = http.createServer(async function (req, res) { + req.on('data', () => {}) + req.on('end', async () => { + if (req.url === "/boba-addr.json") { + console.log(`[API] ${req.method} ${req.url} 200`) + res.end(JSON.stringify({ + Proxy__L1StandardBridge, + Proxy__L1LiquidityPool, + Proxy__L1NFTBridge, + Proxy__L1ERC1155Bridge, + L1Message, + })) + server.emit('success') + } + }) + }).listen(apiPort) + apiEndpoint = `http://${ip.address()}:${apiPort}` + /* eslint-enable */ + }) + + it('should filter addresses for message relayer', async () => { + const randomWallet_1 = ethers.Wallet.createRandom() + const randomWallet_2 = ethers.Wallet.createRandom() + const randomWallet_3 = ethers.Wallet.createRandom() + const relayerFilterWhitelist = `${randomWallet_1.address},${randomWallet_2.address},${randomWallet_3.address}` + messageRelayerService = new MessageRelayerService({ + l2RpcProvider: ethers.provider, + l1Wallet: ethers.Wallet.createRandom().connect(ethers.provider), + minBatchSize: 1, + maxWaitTimeS: 100, + maxWaitTxTimeS: 1, + isFastRelayer: false, + enableRelayerFilter: true, + relayerFilterWhitelist, + filterEndpoint: `${apiEndpoint}/boba-addr.json`, + }) + await messageRelayerService._init() + await messageRelayerService._getFilter() + expect(messageRelayerService.state.fastRelayerFilter).to.be.deep.equal([ + Proxy__L1LiquidityPool, + L1Message, + ]) + expect(messageRelayerService.state.relayerFilter).to.be.deep.equal([ + Proxy__L1StandardBridge, + Proxy__L1NFTBridge, + Proxy__L1ERC1155Bridge, + ...relayerFilterWhitelist.split(','), + ]) + }) + + it('should filter addresses for message relayer fast', async () => { + const randomWallet_1 = ethers.Wallet.createRandom() + const randomWallet_2 = ethers.Wallet.createRandom() + const randomWallet_3 = ethers.Wallet.createRandom() + const relayerFilterWhitelist = `${randomWallet_1.address},${randomWallet_2.address},${randomWallet_3.address}` + messageRelayerService = new MessageRelayerService({ + l2RpcProvider: ethers.provider, + l1Wallet: ethers.Wallet.createRandom().connect(ethers.provider), + minBatchSize: 1, + maxWaitTimeS: 100, + maxWaitTxTimeS: 1, + isFastRelayer: true, + enableRelayerFilter: true, + relayerFilterWhitelist, + filterEndpoint: `${apiEndpoint}/boba-addr.json`, + }) + await messageRelayerService._init() + await messageRelayerService._getFilter() + expect(messageRelayerService.state.fastRelayerFilter).to.be.deep.equal([ + Proxy__L1LiquidityPool, + L1Message, + ]) + expect(messageRelayerService.state.relayerFilter).to.be.deep.equal([ + Proxy__L1StandardBridge, + Proxy__L1NFTBridge, + Proxy__L1ERC1155Bridge, + ...relayerFilterWhitelist.split(','), + ]) + }) +}) diff --git a/packages/message-relayer/test/setup.ts b/packages/message-relayer/test/setup.ts new file mode 100644 index 0000000000..0e8f4a91f9 --- /dev/null +++ b/packages/message-relayer/test/setup.ts @@ -0,0 +1,8 @@ +/* External Imports */ +import chai = require('chai') +import { solidity } from 'ethereum-waffle' + +chai.use(solidity) +const expect = chai.expect + +export { expect }