helpers.ts 1.99 KB
Newer Older
1
import { Contract } from 'ethers'
2
import { Logger } from '@eth-optimism/common-ts'
3
import { BedrockOutputData } from '@eth-optimism/core-utils'
4

5
/**
6
 * Finds the BedrockOutputData that corresponds to a given output index.
7
 *
8
 * @param oracle Output oracle contract
9 10
 * @param index Output index to search for.
 * @returns BedrockOutputData corresponding to the output index.
11
 */
12
export const findOutputForIndex = async (
13
  oracle: Contract,
14 15
  index: number,
  logger?: Logger
16 17 18 19 20 21 22 23 24 25
): Promise<BedrockOutputData> => {
  try {
    const proposal = await oracle.getL2Output(index)
    return {
      outputRoot: proposal.outputRoot,
      l1Timestamp: proposal.timestamp.toNumber(),
      l2BlockNumber: proposal.l2BlockNumber.toNumber(),
      l2OutputIndex: index,
    }
  } catch (err) {
Mark Tyneway's avatar
Mark Tyneway committed
26 27 28
    logger?.fatal('error when calling L2OuputOracle.getL2Output', {
      errors: err,
    })
29
    throw new Error(`unable to find output for index ${index}`)
30 31 32 33 34 35
  }
}

/**
 * Finds the first state batch index that has not yet passed the fault proof window.
 *
36
 * @param oracle Output oracle contract.
37 38
 * @returns Starting state root batch index.
 */
39
export const findFirstUnfinalizedStateBatchIndex = async (
40
  oracle: Contract,
41 42
  fpw: number,
  logger?: Logger
43
): Promise<number> => {
44 45
  const latestBlock = await oracle.provider.getBlock('latest')
  const totalBatches = (await oracle.nextOutputIndex()).toNumber()
46 47 48 49 50 51

  // Perform a binary search to find the next batch that will pass the challenge period.
  let lo = 0
  let hi = totalBatches
  while (lo !== hi) {
    const mid = Math.floor((lo + hi) / 2)
52
    const outputData = await findOutputForIndex(oracle, mid, logger)
53

54
    if (outputData.l1Timestamp + fpw < latestBlock.timestamp) {
55 56 57 58 59 60 61 62 63 64 65 66 67 68
      lo = mid + 1
    } else {
      hi = mid
    }
  }

  // Result will be zero if the chain is less than FPW seconds old. Only returns undefined in the
  // case that no batches have been submitted for an entire challenge period.
  if (lo === totalBatches) {
    return undefined
  } else {
    return lo
  }
}