Commit 8da04505 authored by Mark Tyneway's avatar Mark Tyneway

core-utils: more flexible watcher

Adds new config options to the watcher to allow it to upgrade in
a non breaking way. New config options include setting a global
`pollForPending` and `blocksToFetch`. It is also possible to
specify the number of blocks to fetch on each `Layer`.

The event ids are precomputed and held as globals instead of computed
on the fly each time.
parent 34927928
---
'@eth-optimism/core-utils': minor
---
Allow a configurable L1 and L2 blocks to fetch in the watcher
...@@ -2,9 +2,14 @@ ...@@ -2,9 +2,14 @@
import { ethers } from 'ethers' import { ethers } from 'ethers'
import { Provider, TransactionReceipt } from '@ethersproject/abstract-provider' import { Provider, TransactionReceipt } from '@ethersproject/abstract-provider'
const SENT_MESSAGE = ethers.utils.id('SentMessage(bytes)')
const RELAYED_MESSAGE = ethers.utils.id(`RelayedMessage(bytes32)`)
const FAILED_RELAYED_MESSAGE = ethers.utils.id(`FailedRelayedMessage(bytes32)`)
export interface Layer { export interface Layer {
provider: Provider provider: Provider
messengerAddress: string messengerAddress: string
blocksToFetch?: number
} }
export interface WatcherOptions { export interface WatcherOptions {
...@@ -12,6 +17,7 @@ export interface WatcherOptions { ...@@ -12,6 +17,7 @@ export interface WatcherOptions {
l2: Layer l2: Layer
pollInterval?: number pollInterval?: number
blocksToFetch?: number blocksToFetch?: number
pollForPending?: boolean
} }
export class Watcher { export class Watcher {
...@@ -19,16 +25,20 @@ export class Watcher { ...@@ -19,16 +25,20 @@ export class Watcher {
public l2: Layer public l2: Layer
public pollInterval = 3000 public pollInterval = 3000
public blocksToFetch = 1500 public blocksToFetch = 1500
public pollForPending = true
constructor(opts: WatcherOptions) { constructor(opts: WatcherOptions) {
this.l1 = opts.l1 this.l1 = opts.l1
this.l2 = opts.l2 this.l2 = opts.l2
if (opts.pollInterval) { if (typeof opts.pollInterval === 'number') {
this.pollInterval = opts.pollInterval this.pollInterval = opts.pollInterval
} }
if (opts.blocksToFetch) { if (typeof opts.blocksToFetch === 'number') {
this.blocksToFetch = opts.blocksToFetch this.blocksToFetch = opts.blocksToFetch
} }
if (typeof opts.pollForPending === 'boolean') {
this.pollForPending = opts.pollForPending
}
} }
public async getMessageHashesFromL1Tx(l1TxHash: string): Promise<string[]> { public async getMessageHashesFromL1Tx(l1TxHash: string): Promise<string[]> {
...@@ -40,14 +50,14 @@ export class Watcher { ...@@ -40,14 +50,14 @@ export class Watcher {
public async getL1TransactionReceipt( public async getL1TransactionReceipt(
l2ToL1MsgHash: string, l2ToL1MsgHash: string,
pollForPending = true pollForPending?
): Promise<TransactionReceipt> { ): Promise<TransactionReceipt> {
return this.getTransactionReceipt(this.l1, l2ToL1MsgHash, pollForPending) return this.getTransactionReceipt(this.l1, l2ToL1MsgHash, pollForPending)
} }
public async getL2TransactionReceipt( public async getL2TransactionReceipt(
l1ToL2MsgHash: string, l1ToL2MsgHash: string,
pollForPending = true pollForPending?
): Promise<TransactionReceipt> { ): Promise<TransactionReceipt> {
return this.getTransactionReceipt(this.l2, l1ToL2MsgHash, pollForPending) return this.getTransactionReceipt(this.l2, l1ToL2MsgHash, pollForPending)
} }
...@@ -65,7 +75,7 @@ export class Watcher { ...@@ -65,7 +75,7 @@ export class Watcher {
for (const log of receipt.logs) { for (const log of receipt.logs) {
if ( if (
log.address === layer.messengerAddress && log.address === layer.messengerAddress &&
log.topics[0] === ethers.utils.id('SentMessage(bytes)') log.topics[0] === SENT_MESSAGE
) { ) {
const [message] = ethers.utils.defaultAbiCoder.decode( const [message] = ethers.utils.defaultAbiCoder.decode(
['bytes'], ['bytes'],
...@@ -80,22 +90,31 @@ export class Watcher { ...@@ -80,22 +90,31 @@ export class Watcher {
public async getTransactionReceipt( public async getTransactionReceipt(
layer: Layer, layer: Layer,
msgHash: string, msgHash: string,
pollForPending = true pollForPending?
): Promise<TransactionReceipt> { ): Promise<TransactionReceipt> {
if (typeof pollForPending !== 'boolean') {
pollForPending = this.pollForPending
}
let matches: ethers.providers.Log[] = [] let matches: ethers.providers.Log[] = []
let blocksToFetch = layer.blocksToFetch
if (typeof blocksToFetch !== 'number') {
blocksToFetch = this.blocksToFetch
}
// scan for transaction with specified message // scan for transaction with specified message
while (matches.length === 0) { while (matches.length === 0) {
const blockNumber = await layer.provider.getBlockNumber() const blockNumber = await layer.provider.getBlockNumber()
const startingBlock = Math.max(blockNumber - this.blocksToFetch, 0) const startingBlock = Math.max(blockNumber - blocksToFetch, 0)
const successFilter: ethers.providers.Filter = { const successFilter: ethers.providers.Filter = {
address: layer.messengerAddress, address: layer.messengerAddress,
topics: [ethers.utils.id(`RelayedMessage(bytes32)`)], topics: [RELAYED_MESSAGE],
fromBlock: startingBlock, fromBlock: startingBlock,
} }
const failureFilter: ethers.providers.Filter = { const failureFilter: ethers.providers.Filter = {
address: layer.messengerAddress, address: layer.messengerAddress,
topics: [ethers.utils.id(`FailedRelayedMessage(bytes32)`)], topics: [FAILED_RELAYED_MESSAGE],
fromBlock: startingBlock, fromBlock: startingBlock,
} }
const successLogs = await layer.provider.getLogs(successFilter) const successLogs = await layer.provider.getLogs(successFilter)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment