Commit 79df44e8 authored by Karl Floersch's avatar Karl Floersch Committed by GitHub

feat: add skipped deposit auto heal (#760)

* feat: add skipped deposit auto heal

* Fix weird lint errors

* Use OR instead of AND for skip check
parent 066f6c8b
---
'@eth-optimism/batch-submitter': patch
---
Add skipped deposit auto heal
......@@ -26,6 +26,7 @@ import { Range, BatchSubmitter, BLOCK_OFFSET } from '.'
export interface AutoFixBatchOptions {
fixDoublePlayedDeposits: boolean
fixMonotonicity: boolean
fixSkippedDeposits: boolean
}
export class TransactionBatchSubmitter extends BatchSubmitter {
......@@ -56,6 +57,7 @@ export class TransactionBatchSubmitter extends BatchSubmitter {
autoFixBatchOptions: AutoFixBatchOptions = {
fixDoublePlayedDeposits: false,
fixMonotonicity: false,
fixSkippedDeposits: false,
} // TODO: Remove this
) {
super(
......@@ -422,7 +424,12 @@ export class TransactionBatchSubmitter extends BatchSubmitter {
this.logger.warn('Fixing double played queue element.', {
nextQueueIndex,
})
fixedBatch.push(await this._fixQueueElement(nextQueueIndex, ele))
fixedBatch.push(
await this._fixDoublePlayedDepositQueueElement(
nextQueueIndex,
ele
)
)
continue
}
nextQueueIndex++
......@@ -432,6 +439,57 @@ export class TransactionBatchSubmitter extends BatchSubmitter {
return fixedBatch
}
const fixSkippedDeposits = async (b: Batch): Promise<Batch> => {
this.logger.debug('Fixing skipped deposits...')
let nextQueueIndex = await this.chainContract.getNextQueueIndex()
const fixedBatch: Batch = []
for (const ele of b) {
// Look for skipped deposits
while (true) {
const pendingQueueElements = await this.chainContract.getNumPendingQueueElements()
const nextRemoteQueueElements = await this.chainContract.getNextQueueIndex()
const totalQueueElements =
pendingQueueElements + nextRemoteQueueElements
// No more queue elements so we clearly haven't skipped anything
if (nextQueueIndex >= totalQueueElements) {
break
}
const [
queueEleHash,
timestamp,
blockNumber,
] = await this.chainContract.getQueueElement(nextQueueIndex)
if (timestamp < ele.timestamp || blockNumber < ele.blockNumber) {
this.logger.error('Fixing skipped deposit', {
badTimestamp: ele.timestamp,
skippedQueueTimestamp: timestamp,
badBlockNumber: ele.blockNumber,
skippedQueueBlockNumber: blockNumber,
})
// Push a dummy queue element
fixedBatch.push({
stateRoot: ele.stateRoot,
isSequencerTx: false,
rawTransaction: undefined,
timestamp,
blockNumber,
})
nextQueueIndex++
} else {
// The next queue element's timestamp is after this batch element so
// we must not have skipped anything.
break
}
}
fixedBatch.push(ele)
if (!ele.isSequencerTx) {
nextQueueIndex++
}
}
return fixedBatch
}
// TODO: Remove this super complex logic and rely on Geth to actually supply correct block data.
const fixMonotonicity = async (b: Batch): Promise<Batch> => {
this.logger.debug('Fixing monotonicity...')
......@@ -534,12 +592,17 @@ export class TransactionBatchSubmitter extends BatchSubmitter {
return fixedBatch
}
// NOTE: It is unsafe to combine multiple autoFix options.
// If you must combine them, manually verify the output before proceeding.
if (this.autoFixBatchOptions.fixDoublePlayedDeposits) {
batch = await fixDoublePlayedDeposits(batch)
}
if (this.autoFixBatchOptions.fixMonotonicity) {
batch = await fixMonotonicity(batch)
}
if (this.autoFixBatchOptions.fixSkippedDeposits) {
batch = await fixSkippedDeposits(batch)
}
return batch
}
......@@ -580,7 +643,7 @@ export class TransactionBatchSubmitter extends BatchSubmitter {
return { lastTimestamp, lastBlockNumber }
}
private async _fixQueueElement(
private async _fixDoublePlayedDepositQueueElement(
queueIndex: number,
queueElement: BatchElement
): Promise<BatchElement> {
......
......@@ -127,6 +127,9 @@ const autoFixBatchOptions: AutoFixBatchOptions = {
fixMonotonicity: AUTO_FIX_BATCH_OPTIONS_CONF
? AUTO_FIX_BATCH_OPTIONS_CONF.includes('fixMonotonicity')
: false,
fixSkippedDeposits: AUTO_FIX_BATCH_OPTIONS_CONF
? AUTO_FIX_BATCH_OPTIONS_CONF.includes('fixSkippedDeposits')
: false,
}
export const run = async () => {
......
......@@ -108,16 +108,14 @@ const getOvmSolcPath = async (version: string): Promise<string> => {
// Hardhat on M1 Macbooks does not run TASK_COMPILE_SOLIDITY_RUN_SOLC, but instead this runs one,
// TASK_COMPILE_SOLIDITY_RUN_SOLCJS. We reroute this task back to the solc task in the case
// of OVM compilation.
subtask(
TASK_COMPILE_SOLIDITY_RUN_SOLCJS,
async (args, hre, runSuper) => {
subtask(TASK_COMPILE_SOLIDITY_RUN_SOLCJS, async (args, hre, runSuper) => {
const argsAny = args as any
if (argsAny.real || hre.network.ovm !== true) {
for (const file of Object.keys(argsAny.input.sources)) {
// Ignore any contract that has this tag or in ignore list
if (
argsAny.input.sources[file].content.includes('// @unsupported: evm')
&& hre.network.ovm !== true
argsAny.input.sources[file].content.includes('// @unsupported: evm') &&
hre.network.ovm !== true
) {
delete argsAny.input.sources[file]
}
......@@ -126,11 +124,10 @@ subtask(
} else {
return hre.run(TASK_COMPILE_SOLIDITY_RUN_SOLC, {
...argsAny,
solcPath: argsAny.solcJsPath
solcPath: argsAny.solcJsPath,
})
}
}
)
})
subtask(
TASK_COMPILE_SOLIDITY_RUN_SOLC,
......@@ -195,7 +192,7 @@ subtask(
const ovmOutput = await hre.run(TASK_COMPILE_SOLIDITY_RUN_SOLCJS, {
input: ovmInput,
solcJsPath: ovmSolcPath,
real: true
real: true,
})
// Just doing this to add some extra useful information to any errors in the OVM compiler output.
......
......@@ -12096,7 +12096,7 @@ source-map-support@^0.4.15:
dependencies:
source-map "^0.5.6"
source-map-support@^0.5.13, source-map-support@^0.5.17, source-map-support@^0.5.6:
source-map-support@^0.5.13, source-map-support@^0.5.17, source-map-support@^0.5.19, source-map-support@^0.5.6:
version "0.5.19"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61"
integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==
......
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