Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve Watcher ability to find transactions #1107

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/tall-plums-behave.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@eth-optimism/core-utils': patch
---

improved watcher ability to find transactions during periods of high load
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"lint:check": "yarn lerna run lint:check",
"lint:fix": "yarn lerna run lint:fix",
"postinstall": "patch-package",
"ready": "yarn lint && yarn test",
"release": "yarn build && yarn changeset publish"
},
"dependencies": {
Expand Down
63 changes: 25 additions & 38 deletions packages/core-utils/src/watcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,22 +73,31 @@ export class Watcher {
msgHash: string,
pollForPending: boolean = true
): Promise<TransactionReceipt> {
const blockNumber = await layer.provider.getBlockNumber()
const startingBlock = Math.max(blockNumber - this.NUM_BLOCKS_TO_FETCH, 0)
const successFilter = {
address: layer.messengerAddress,
topics: [ethers.utils.id(`RelayedMessage(bytes32)`)],
fromBlock: startingBlock,
}
const failureFilter = {
address: layer.messengerAddress,
topics: [ethers.utils.id(`FailedRelayedMessage(bytes32)`)],
fromBlock: startingBlock,
let matches: ethers.providers.Log[] = []

// scan for transaction with specified message
while (matches.length === 0) {
const blockNumber = await layer.provider.getBlockNumber()
const startingBlock = Math.max(blockNumber - this.NUM_BLOCKS_TO_FETCH, 0)
const successFilter: ethers.providers.Filter = {
address: layer.messengerAddress,
topics: [ethers.utils.id(`RelayedMessage(bytes32)`)],
fromBlock: startingBlock
}
const failureFilter: ethers.providers.Filter = {
address: layer.messengerAddress,
topics: [ethers.utils.id(`FailedRelayedMessage(bytes32)`)],
fromBlock: startingBlock
}
const successLogs = await layer.provider.getLogs(successFilter)
const failureLogs = await layer.provider.getLogs(failureFilter)
const logs = successLogs.concat(failureLogs)
matches = logs.filter((log: ethers.providers.Log) => log.data === msgHash)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes me realize that we should emit the msg hash as an indexed event param.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would this be something we should attempt to implement in this PR?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the sake of keeping this PR simple I'd leave it out. But could definitely be worth doing in a separate PR.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change would have to target regenesis/0.5.0

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is an important change as to prevent a massive JSON response that blocks the event loop and causes a memory spike.

// exit loop after first iteration if not polling
if (!pollForPending) {
break
}
}
const successLogs = await layer.provider.getLogs(successFilter)
const failureLogs = await layer.provider.getLogs(failureFilter)
const logs = successLogs.concat(failureLogs)
const matches = logs.filter((log: any) => log.data === msgHash)

// Message was relayed in the past
if (matches.length > 0) {
Expand All @@ -98,30 +107,8 @@ export class Watcher {
)
}
return layer.provider.getTransactionReceipt(matches[0].transactionHash)
}
if (!pollForPending) {
} else {
return Promise.resolve(undefined)
}

// Message has yet to be relayed, poll until it is found
return new Promise(async (resolve, reject) => {
const handleEvent = async (log: any) => {
if (log.data === msgHash) {
try {
const txReceipt = await layer.provider.getTransactionReceipt(
log.transactionHash
)
layer.provider.off(successFilter)
layer.provider.off(failureFilter)
resolve(txReceipt)
} catch (e) {
reject(e)
}
}
}

layer.provider.on(successFilter, handleEvent)
layer.provider.on(failureFilter, handleEvent)
})
}
}