codex-contracts-eth/test/Proofs.test.js

205 lines
6.8 KiB
JavaScript

const { expect } = require("chai")
const { ethers } = require("hardhat")
const { mineBlock, minedBlockNumber } = require("./mining")
describe("Proofs", function () {
const id = ethers.utils.randomBytes(32)
const period = 10
const timeout = 5
const duration = 50
let proofs
beforeEach(async function () {
const Proofs = await ethers.getContractFactory("TestProofs")
proofs = await Proofs.deploy()
})
it("indicates that proofs are required", async function () {
await proofs.expectProofs(id, period, timeout, duration)
expect(await proofs.period(id)).to.equal(period)
expect(await proofs.timeout(id)).to.equal(timeout)
})
it("calculates an endtime based on duration and timeout", async function () {
await proofs.expectProofs(id, period, timeout, duration)
let start = await minedBlockNumber()
let end = start + duration + 2 * timeout
expect(await proofs.end(id)).to.equal(end)
})
it("does not allow ids to be reused", async function () {
await proofs.expectProofs(id, period, timeout, duration)
await expect(
proofs.expectProofs(id, period, timeout, duration)
).to.be.revertedWith("Proof id already in use")
})
it("does not allow a proof timeout that is too large", async function () {
let invalidTimeout = 129 // max proof timeout is 128 blocks
await expect(
proofs.expectProofs(id, period, invalidTimeout, duration)
).to.be.revertedWith("Invalid proof timeout")
})
it("requires on average a proof every period", async function () {
let blocks = 600
let amount = 0
await proofs.expectProofs(id, period, timeout, blocks)
for (let i = 0; i < blocks; i++) {
await mineBlock()
if (await proofs.isProofRequired(id, await minedBlockNumber())) {
amount += 1
}
}
let average = blocks / amount
expect(average).to.be.closeTo(period, period / 2)
})
it("requires no proof before start time", async function () {
for (let i = 0; i < 4 * period; i++) {
mineBlock()
}
await proofs.expectProofs(id, period, timeout, duration)
let start = await minedBlockNumber()
for (let i = 1; i < 4 * period; i++) {
expect(await proofs.isProofRequired(id, start - i)).to.be.false
}
})
describe("when proofs are required", async function () {
beforeEach(async function () {
await proofs.expectProofs(id, period, timeout, duration)
})
async function mineUntilProofIsRequired(id) {
while (!(await proofs.isProofRequired(id, await minedBlockNumber()))) {
mineBlock()
}
}
async function mineUntilProofTimeout() {
for (let i = 0; i < timeout; i++) {
mineBlock()
}
}
async function mineUntilEnd() {
const end = await proofs.end(id)
while ((await minedBlockNumber()) < end) {
mineBlock()
}
}
it("requires no proof for blocks that are unavailable", async function () {
await mineUntilProofIsRequired(id)
let blocknumber = await minedBlockNumber()
for (let i = 0; i < 256; i++) {
// only last 256 blocks available in solidity
mineBlock()
}
expect(await proofs.isProofRequired(id, blocknumber)).to.be.false
})
it("requires no proof after end time", async function () {
await mineUntilEnd()
for (let i = 0; i < 4 * period; i++) {
const blocknumber = await minedBlockNumber()
expect(await proofs.isProofRequired(id, blocknumber)).to.be.false
mineBlock()
}
})
it("submits a correct proof", async function () {
await mineUntilProofIsRequired(id)
let blocknumber = await minedBlockNumber()
await proofs.submitProof(id, blocknumber, true)
})
it("fails proof submission when proof is incorrect", async function () {
await mineUntilProofIsRequired(id)
let blocknumber = await minedBlockNumber()
await expect(
proofs.submitProof(id, blocknumber, false)
).to.be.revertedWith("Invalid proof")
})
it("fails proof submission when proof was not required", async function () {
while (await proofs.isProofRequired(id, await minedBlockNumber())) {
await mineBlock()
}
let blocknumber = await minedBlockNumber()
await expect(
proofs.submitProof(id, blocknumber, true)
).to.be.revertedWith("No proof required")
})
it("fails proof submission when proof is too late", async function () {
await mineUntilProofIsRequired(id)
let blocknumber = await minedBlockNumber()
await mineUntilProofTimeout()
await expect(
proofs.submitProof(id, blocknumber, true)
).to.be.revertedWith("Proof not allowed after timeout")
})
it("fails proof submission when already submitted", async function () {
await mineUntilProofIsRequired(id)
let blocknumber = await minedBlockNumber()
await proofs.submitProof(id, blocknumber, true)
await expect(
proofs.submitProof(id, blocknumber, true)
).to.be.revertedWith("Proof already submitted")
})
it("marks a proof as missing", async function () {
expect(await proofs.missed(id)).to.equal(0)
await mineUntilProofIsRequired(id)
let blocknumber = await minedBlockNumber()
await mineUntilProofTimeout()
await proofs.markProofAsMissing(id, blocknumber)
expect(await proofs.missed(id)).to.equal(1)
})
it("does not mark a proof as missing before timeout", async function () {
await mineUntilProofIsRequired(id)
let blocknumber = await minedBlockNumber()
await mineBlock()
await expect(
proofs.markProofAsMissing(id, blocknumber)
).to.be.revertedWith("Proof has not timed out yet")
})
it("does not mark a submitted proof as missing", async function () {
await mineUntilProofIsRequired(id)
let blocknumber = await minedBlockNumber()
await proofs.submitProof(id, blocknumber, true)
await mineUntilProofTimeout()
await expect(
proofs.markProofAsMissing(id, blocknumber)
).to.be.revertedWith("Proof was submitted, not missing")
})
it("does not mark proof as missing when not required", async function () {
while (await proofs.isProofRequired(id, await minedBlockNumber())) {
mineBlock()
}
let blocknumber = await minedBlockNumber()
await mineUntilProofTimeout()
await expect(
proofs.markProofAsMissing(id, blocknumber)
).to.be.revertedWith("Proof was not required")
})
it("does not mark proof as missing twice", async function () {
await mineUntilProofIsRequired(id)
let blocknumber = await minedBlockNumber()
await mineUntilProofTimeout()
await proofs.markProofAsMissing(id, blocknumber)
await expect(
proofs.markProofAsMissing(id, blocknumber)
).to.be.revertedWith("Proof already marked as missing")
})
})
})