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 '.' ...@@ -26,6 +26,7 @@ import { Range, BatchSubmitter, BLOCK_OFFSET } from '.'
export interface AutoFixBatchOptions { export interface AutoFixBatchOptions {
fixDoublePlayedDeposits: boolean fixDoublePlayedDeposits: boolean
fixMonotonicity: boolean fixMonotonicity: boolean
fixSkippedDeposits: boolean
} }
export class TransactionBatchSubmitter extends BatchSubmitter { export class TransactionBatchSubmitter extends BatchSubmitter {
...@@ -56,6 +57,7 @@ export class TransactionBatchSubmitter extends BatchSubmitter { ...@@ -56,6 +57,7 @@ export class TransactionBatchSubmitter extends BatchSubmitter {
autoFixBatchOptions: AutoFixBatchOptions = { autoFixBatchOptions: AutoFixBatchOptions = {
fixDoublePlayedDeposits: false, fixDoublePlayedDeposits: false,
fixMonotonicity: false, fixMonotonicity: false,
fixSkippedDeposits: false,
} // TODO: Remove this } // TODO: Remove this
) { ) {
super( super(
...@@ -422,7 +424,12 @@ export class TransactionBatchSubmitter extends BatchSubmitter { ...@@ -422,7 +424,12 @@ export class TransactionBatchSubmitter extends BatchSubmitter {
this.logger.warn('Fixing double played queue element.', { this.logger.warn('Fixing double played queue element.', {
nextQueueIndex, nextQueueIndex,
}) })
fixedBatch.push(await this._fixQueueElement(nextQueueIndex, ele)) fixedBatch.push(
await this._fixDoublePlayedDepositQueueElement(
nextQueueIndex,
ele
)
)
continue continue
} }
nextQueueIndex++ nextQueueIndex++
...@@ -432,6 +439,57 @@ export class TransactionBatchSubmitter extends BatchSubmitter { ...@@ -432,6 +439,57 @@ export class TransactionBatchSubmitter extends BatchSubmitter {
return fixedBatch 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. // TODO: Remove this super complex logic and rely on Geth to actually supply correct block data.
const fixMonotonicity = async (b: Batch): Promise<Batch> => { const fixMonotonicity = async (b: Batch): Promise<Batch> => {
this.logger.debug('Fixing monotonicity...') this.logger.debug('Fixing monotonicity...')
...@@ -534,12 +592,17 @@ export class TransactionBatchSubmitter extends BatchSubmitter { ...@@ -534,12 +592,17 @@ export class TransactionBatchSubmitter extends BatchSubmitter {
return fixedBatch 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) { if (this.autoFixBatchOptions.fixDoublePlayedDeposits) {
batch = await fixDoublePlayedDeposits(batch) batch = await fixDoublePlayedDeposits(batch)
} }
if (this.autoFixBatchOptions.fixMonotonicity) { if (this.autoFixBatchOptions.fixMonotonicity) {
batch = await fixMonotonicity(batch) batch = await fixMonotonicity(batch)
} }
if (this.autoFixBatchOptions.fixSkippedDeposits) {
batch = await fixSkippedDeposits(batch)
}
return batch return batch
} }
...@@ -580,7 +643,7 @@ export class TransactionBatchSubmitter extends BatchSubmitter { ...@@ -580,7 +643,7 @@ export class TransactionBatchSubmitter extends BatchSubmitter {
return { lastTimestamp, lastBlockNumber } return { lastTimestamp, lastBlockNumber }
} }
private async _fixQueueElement( private async _fixDoublePlayedDepositQueueElement(
queueIndex: number, queueIndex: number,
queueElement: BatchElement queueElement: BatchElement
): Promise<BatchElement> { ): Promise<BatchElement> {
......
...@@ -127,6 +127,9 @@ const autoFixBatchOptions: AutoFixBatchOptions = { ...@@ -127,6 +127,9 @@ const autoFixBatchOptions: AutoFixBatchOptions = {
fixMonotonicity: AUTO_FIX_BATCH_OPTIONS_CONF fixMonotonicity: AUTO_FIX_BATCH_OPTIONS_CONF
? AUTO_FIX_BATCH_OPTIONS_CONF.includes('fixMonotonicity') ? AUTO_FIX_BATCH_OPTIONS_CONF.includes('fixMonotonicity')
: false, : false,
fixSkippedDeposits: AUTO_FIX_BATCH_OPTIONS_CONF
? AUTO_FIX_BATCH_OPTIONS_CONF.includes('fixSkippedDeposits')
: false,
} }
export const run = async () => { export const run = async () => {
......
...@@ -108,16 +108,14 @@ const getOvmSolcPath = async (version: string): Promise<string> => { ...@@ -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, // 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 // TASK_COMPILE_SOLIDITY_RUN_SOLCJS. We reroute this task back to the solc task in the case
// of OVM compilation. // of OVM compilation.
subtask( subtask(TASK_COMPILE_SOLIDITY_RUN_SOLCJS, async (args, hre, runSuper) => {
TASK_COMPILE_SOLIDITY_RUN_SOLCJS,
async (args, hre, runSuper) => {
const argsAny = args as any const argsAny = args as any
if (argsAny.real || hre.network.ovm !== true) { if (argsAny.real || hre.network.ovm !== true) {
for (const file of Object.keys(argsAny.input.sources)) { for (const file of Object.keys(argsAny.input.sources)) {
// Ignore any contract that has this tag or in ignore list // Ignore any contract that has this tag or in ignore list
if ( if (
argsAny.input.sources[file].content.includes('// @unsupported: evm') argsAny.input.sources[file].content.includes('// @unsupported: evm') &&
&& hre.network.ovm !== true hre.network.ovm !== true
) { ) {
delete argsAny.input.sources[file] delete argsAny.input.sources[file]
} }
...@@ -126,11 +124,10 @@ subtask( ...@@ -126,11 +124,10 @@ subtask(
} else { } else {
return hre.run(TASK_COMPILE_SOLIDITY_RUN_SOLC, { return hre.run(TASK_COMPILE_SOLIDITY_RUN_SOLC, {
...argsAny, ...argsAny,
solcPath: argsAny.solcJsPath solcPath: argsAny.solcJsPath,
}) })
} }
} })
)
subtask( subtask(
TASK_COMPILE_SOLIDITY_RUN_SOLC, TASK_COMPILE_SOLIDITY_RUN_SOLC,
...@@ -195,7 +192,7 @@ subtask( ...@@ -195,7 +192,7 @@ subtask(
const ovmOutput = await hre.run(TASK_COMPILE_SOLIDITY_RUN_SOLCJS, { const ovmOutput = await hre.run(TASK_COMPILE_SOLIDITY_RUN_SOLCJS, {
input: ovmInput, input: ovmInput,
solcJsPath: ovmSolcPath, solcJsPath: ovmSolcPath,
real: true real: true,
}) })
// Just doing this to add some extra useful information to any errors in the OVM compiler output. // 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: ...@@ -12096,7 +12096,7 @@ source-map-support@^0.4.15:
dependencies: dependencies:
source-map "^0.5.6" 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" version "0.5.19"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61"
integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== 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