helpers.spec.ts 5.71 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
import hre from 'hardhat'
import { Contract } from 'ethers'
import { toRpcHexString } from '@eth-optimism/core-utils'
import {
  getContractFactory,
  getContractInterface,
} from '@eth-optimism/contracts'
import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'
import { smock, FakeContract } from '@defi-wonderland/smock'

import { expect } from './setup'
import {
  findEventForStateBatch,
  findFirstUnfinalizedStateBatchIndex,
15
  OutputOracle,
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
} from '../src'

describe('helpers', () => {
  // Can be any non-zero value, 1000 is fine.
  const challengeWindowSeconds = 1000

  let signer: SignerWithAddress
  before(async () => {
    ;[signer] = await hre.ethers.getSigners()
  })

  let FakeBondManager: FakeContract<Contract>
  let FakeCanonicalTransactionChain: FakeContract<Contract>
  let AddressManager: Contract
  let ChainStorageContainer: Contract
  let StateCommitmentChain: Contract
32
  let oracle: OutputOracle<any>
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
  beforeEach(async () => {
    // Set up fakes
    FakeBondManager = await smock.fake(getContractInterface('BondManager'))
    FakeCanonicalTransactionChain = await smock.fake(
      getContractInterface('CanonicalTransactionChain')
    )

    // Set up contracts
    AddressManager = await getContractFactory(
      'Lib_AddressManager',
      signer
    ).deploy()
    ChainStorageContainer = await getContractFactory(
      'ChainStorageContainer',
      signer
    ).deploy(AddressManager.address, 'StateCommitmentChain')
    StateCommitmentChain = await getContractFactory(
      'StateCommitmentChain',
      signer
    ).deploy(AddressManager.address, challengeWindowSeconds, 10000000)

    // Set addresses in manager
    await AddressManager.setAddress(
      'ChainStorageContainer-SCC-batches',
      ChainStorageContainer.address
    )
    await AddressManager.setAddress(
      'StateCommitmentChain',
      StateCommitmentChain.address
    )
    await AddressManager.setAddress(
      'CanonicalTransactionChain',
      FakeCanonicalTransactionChain.address
    )
    await AddressManager.setAddress('BondManager', FakeBondManager.address)

    // Set up mock returns
    FakeCanonicalTransactionChain.getTotalElements.returns(1000000000) // just needs to be large
    FakeBondManager.isCollateralized.returns(true)
72 73 74 75 76 77 78

    oracle = {
      contract: StateCommitmentChain,
      filter: StateCommitmentChain.filters.StateBatchAppended(),
      getTotalElements: async () => StateCommitmentChain.getTotalBatches(),
      getEventIndex: (args: any) => args._batchIndex,
    }
79 80 81 82 83 84 85 86 87 88 89 90
  })

  describe('findEventForStateBatch', () => {
    describe('when the event exists once', () => {
      beforeEach(async () => {
        await StateCommitmentChain.appendStateBatch(
          [hre.ethers.constants.HashZero],
          0
        )
      })

      it('should return the event', async () => {
91
        const event = await findEventForStateBatch(oracle, 0)
92 93 94 95 96 97 98 99

        expect(event.args._batchIndex).to.equal(0)
      })
    })

    describe('when the event does not exist', () => {
      it('should throw an error', async () => {
        await expect(
100
          findEventForStateBatch(oracle, 0)
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
        ).to.eventually.be.rejectedWith('unable to find event for batch')
      })
    })
  })

  describe('findFirstUnfinalizedIndex', () => {
    describe('when the chain is more then FPW seconds old', () => {
      beforeEach(async () => {
        await StateCommitmentChain.appendStateBatch(
          [hre.ethers.constants.HashZero],
          0
        )

        // Simulate FPW passing
        await hre.ethers.provider.send('evm_increaseTime', [
          toRpcHexString(challengeWindowSeconds * 2),
        ])

        await StateCommitmentChain.appendStateBatch(
          [hre.ethers.constants.HashZero],
          1
        )
        await StateCommitmentChain.appendStateBatch(
          [hre.ethers.constants.HashZero],
          2
        )
      })

      it('should find the first batch older than the FPW', async () => {
        const first = await findFirstUnfinalizedStateBatchIndex(
131 132
          oracle,
          challengeWindowSeconds
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
        )

        expect(first).to.equal(1)
      })
    })

    describe('when the chain is less than FPW seconds old', () => {
      beforeEach(async () => {
        await StateCommitmentChain.appendStateBatch(
          [hre.ethers.constants.HashZero],
          0
        )
        await StateCommitmentChain.appendStateBatch(
          [hre.ethers.constants.HashZero],
          1
        )
        await StateCommitmentChain.appendStateBatch(
          [hre.ethers.constants.HashZero],
          2
        )
      })

      it('should return zero', async () => {
        const first = await findFirstUnfinalizedStateBatchIndex(
157 158
          oracle,
          challengeWindowSeconds
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
        )

        expect(first).to.equal(0)
      })
    })

    describe('when no batches submitted for the entire FPW', () => {
      beforeEach(async () => {
        await StateCommitmentChain.appendStateBatch(
          [hre.ethers.constants.HashZero],
          0
        )
        await StateCommitmentChain.appendStateBatch(
          [hre.ethers.constants.HashZero],
          1
        )
        await StateCommitmentChain.appendStateBatch(
          [hre.ethers.constants.HashZero],
          2
        )

        // Simulate FPW passing and no new batches
        await hre.ethers.provider.send('evm_increaseTime', [
          toRpcHexString(challengeWindowSeconds * 2),
        ])

        // Mine a block to force timestamp to update
        await hre.ethers.provider.send('hardhat_mine', ['0x1'])
      })

      it('should return undefined', async () => {
        const first = await findFirstUnfinalizedStateBatchIndex(
191 192
          oracle,
          challengeWindowSeconds
193 194 195 196 197 198 199
        )

        expect(first).to.equal(undefined)
      })
    })
  })
})