mirror of
https://github.com/status-im/dagger-contracts.git
synced 2025-01-28 07:15:50 +00:00
fd74268a8a
1. Remove proof extension as it is not needed. Host are required to provide proofs from the moment they fill a slot, for the duration specified by the contract. This means that the ending of their requirements will be staggered at the end, as they were at the start, but this is more predicable for determining the cost of a request. 2. The proof end time was modified so that if the request state is not accepting proofs, it takes the min of the slot proof end time, the request end time, or block.timestamp - 1, which ensures that it returns a time in the past. If the slot is accepting proofs, it returns the slot end time. 3. Modify marketplace tests so that `waitUntilFinished` advances time to the proof ending of the last slot filled.
274 lines
9.2 KiB
JavaScript
274 lines
9.2 KiB
JavaScript
const { expect } = require("chai")
|
|
const { ethers } = require("hardhat")
|
|
const { hexlify, randomBytes } = ethers.utils
|
|
const {
|
|
snapshot,
|
|
revert,
|
|
mine,
|
|
ensureMinimumBlockHeight,
|
|
currentTime,
|
|
advanceTime,
|
|
advanceTimeTo,
|
|
} = require("./evm")
|
|
const { periodic, hours, minutes } = require("./time")
|
|
|
|
describe("Proofs", function () {
|
|
const id = hexlify(randomBytes(32))
|
|
const period = 30 * 60
|
|
const timeout = 5
|
|
const downtime = 64
|
|
const duration = 1000 * period
|
|
const probability = 4 // require a proof roughly once every 4 periods
|
|
const { periodOf, periodEnd } = periodic(period)
|
|
|
|
let proofs
|
|
|
|
beforeEach(async function () {
|
|
await snapshot()
|
|
await ensureMinimumBlockHeight(256)
|
|
const Proofs = await ethers.getContractFactory("TestProofs")
|
|
proofs = await Proofs.deploy(period, timeout, downtime)
|
|
})
|
|
|
|
afterEach(async function () {
|
|
await revert()
|
|
})
|
|
|
|
it("calculates an end time based on duration", async function () {
|
|
await proofs.expectProofs(id, probability, duration)
|
|
let end = (await currentTime()) + duration
|
|
expect((await proofs.end(id)).toNumber()).to.be.closeTo(end, 1)
|
|
})
|
|
|
|
it("does not allow ids to be reused", async function () {
|
|
await proofs.expectProofs(id, probability, duration)
|
|
await expect(
|
|
proofs.expectProofs(id, probability, duration)
|
|
).to.be.revertedWith("Proof id already in use")
|
|
})
|
|
|
|
it("requires proofs with an agreed upon probability", async function () {
|
|
await proofs.expectProofs(id, probability, duration)
|
|
let amount = 0
|
|
for (let i = 0; i < 100; i++) {
|
|
if (await proofs.isProofRequired(id)) {
|
|
amount += 1
|
|
}
|
|
await advanceTime(period)
|
|
}
|
|
let expected = 100 / probability
|
|
expect(amount).to.be.closeTo(expected, expected / 2)
|
|
})
|
|
|
|
it("requires no proofs in the start period", async function () {
|
|
const startPeriod = Math.floor((await currentTime()) / period)
|
|
const probability = 1
|
|
await proofs.expectProofs(id, probability, duration)
|
|
while (Math.floor((await currentTime()) / period) == startPeriod) {
|
|
expect(await proofs.isProofRequired(id)).to.be.false
|
|
await advanceTime(Math.floor(period / 10))
|
|
}
|
|
})
|
|
|
|
it("requires no proofs in the end period", async function () {
|
|
const probability = 1
|
|
await proofs.expectProofs(id, probability, duration)
|
|
await advanceTime(duration)
|
|
expect(await proofs.isProofRequired(id)).to.be.false
|
|
})
|
|
|
|
it("requires no proofs after the end time", async function () {
|
|
const probability = 1
|
|
await proofs.expectProofs(id, probability, duration)
|
|
await advanceTime(duration + timeout)
|
|
expect(await proofs.isProofRequired(id)).to.be.false
|
|
})
|
|
|
|
it("requires proofs for different ids at different times", async function () {
|
|
let id1 = hexlify(randomBytes(32))
|
|
let id2 = hexlify(randomBytes(32))
|
|
let id3 = hexlify(randomBytes(32))
|
|
for (let id of [id1, id2, id3]) {
|
|
await proofs.expectProofs(id, probability, duration)
|
|
}
|
|
let req1, req2, req3
|
|
while (req1 === req2 && req2 === req3) {
|
|
req1 = await proofs.isProofRequired(id1)
|
|
req2 = await proofs.isProofRequired(id2)
|
|
req3 = await proofs.isProofRequired(id3)
|
|
await advanceTime(period)
|
|
}
|
|
})
|
|
|
|
it("moves pointer one block at a time", async function () {
|
|
await advanceTimeTo(periodEnd(periodOf(await currentTime())))
|
|
for (let i = 0; i < 256; i++) {
|
|
let previous = await proofs.getPointer(id)
|
|
await mine()
|
|
let current = await proofs.getPointer(id)
|
|
expect(current).to.equal((previous + 1) % 256)
|
|
}
|
|
})
|
|
|
|
describe("when proof requirement is upcoming", function () {
|
|
async function waitUntilProofWillBeRequired() {
|
|
while (!(await proofs.willProofBeRequired(id))) {
|
|
await mine()
|
|
}
|
|
}
|
|
|
|
beforeEach(async function () {
|
|
await proofs.expectProofs(id, probability, duration)
|
|
await advanceTimeTo(periodEnd(periodOf(await currentTime())))
|
|
await waitUntilProofWillBeRequired()
|
|
})
|
|
|
|
it("means the pointer is in downtime", async function () {
|
|
expect(await proofs.getPointer(id)).to.be.lt(downtime)
|
|
while ((await proofs.getPointer(id)) < downtime) {
|
|
expect(await proofs.willProofBeRequired(id)).to.be.true
|
|
await mine()
|
|
}
|
|
})
|
|
|
|
it("means that a proof is required after downtime", async function () {
|
|
while ((await proofs.getPointer(id)) < downtime) {
|
|
await mine()
|
|
}
|
|
expect(await proofs.willProofBeRequired(id)).to.be.false
|
|
expect(await proofs.isProofRequired(id)).to.be.true
|
|
})
|
|
|
|
it("will not require proofs when no longer expected", async function () {
|
|
expect(await proofs.getPointer(id)).to.be.lt(downtime)
|
|
expect(await proofs.willProofBeRequired(id)).to.be.true
|
|
await proofs.unexpectProofs(id)
|
|
expect(await proofs.willProofBeRequired(id)).to.be.false
|
|
})
|
|
})
|
|
|
|
describe("when proofs are required", function () {
|
|
const proof = hexlify(randomBytes(42))
|
|
|
|
beforeEach(async function () {
|
|
await proofs.expectProofs(id, probability, duration)
|
|
})
|
|
|
|
async function waitUntilProofIsRequired(id) {
|
|
await advanceTimeTo(periodEnd(periodOf(await currentTime())))
|
|
while (
|
|
!(
|
|
(await proofs.isProofRequired(id)) &&
|
|
(await proofs.getPointer(id)) < 250
|
|
)
|
|
) {
|
|
await advanceTime(period)
|
|
}
|
|
}
|
|
|
|
it("provides different challenges per period", async function () {
|
|
await waitUntilProofIsRequired(id)
|
|
const challenge1 = await proofs.getChallenge(id)
|
|
await waitUntilProofIsRequired(id)
|
|
const challenge2 = await proofs.getChallenge(id)
|
|
expect(challenge2).not.to.equal(challenge1)
|
|
})
|
|
|
|
it("provides different challenges per id", async function () {
|
|
const id2 = hexlify(randomBytes(32))
|
|
const id3 = hexlify(randomBytes(32))
|
|
const challenge1 = await proofs.getChallenge(id)
|
|
const challenge2 = await proofs.getChallenge(id2)
|
|
const challenge3 = await proofs.getChallenge(id3)
|
|
expect(challenge1 === challenge2 && challenge2 === challenge3).to.be.false
|
|
})
|
|
|
|
it("submits a correct proof", async function () {
|
|
await proofs.submitProof(id, proof)
|
|
})
|
|
|
|
it("fails proof submission when proof is incorrect", async function () {
|
|
await expect(proofs.submitProof(id, [])).to.be.revertedWith(
|
|
"Invalid proof"
|
|
)
|
|
})
|
|
|
|
it("emits an event when proof was submitted", async function () {
|
|
await expect(proofs.submitProof(id, proof))
|
|
.to.emit(proofs, "ProofSubmitted")
|
|
.withArgs(id, proof)
|
|
})
|
|
|
|
it("fails proof submission when already submitted", async function () {
|
|
await advanceTimeTo(periodEnd(periodOf(await currentTime())))
|
|
await proofs.submitProof(id, proof)
|
|
await expect(proofs.submitProof(id, proof)).to.be.revertedWith(
|
|
"Proof already submitted"
|
|
)
|
|
})
|
|
|
|
it("marks a proof as missing", async function () {
|
|
expect(await proofs.missed(id)).to.equal(0)
|
|
await waitUntilProofIsRequired(id)
|
|
let missedPeriod = periodOf(await currentTime())
|
|
await advanceTimeTo(periodEnd(missedPeriod))
|
|
await proofs.markProofAsMissing(id, missedPeriod)
|
|
expect(await proofs.missed(id)).to.equal(1)
|
|
})
|
|
|
|
it("does not mark a proof as missing before period end", async function () {
|
|
await waitUntilProofIsRequired(id)
|
|
let currentPeriod = periodOf(await currentTime())
|
|
await expect(
|
|
proofs.markProofAsMissing(id, currentPeriod)
|
|
).to.be.revertedWith("Period has not ended yet")
|
|
})
|
|
|
|
it("does not mark a proof as missing after timeout", async function () {
|
|
await waitUntilProofIsRequired(id)
|
|
let currentPeriod = periodOf(await currentTime())
|
|
await advanceTimeTo(periodEnd(currentPeriod) + timeout)
|
|
await expect(
|
|
proofs.markProofAsMissing(id, currentPeriod)
|
|
).to.be.revertedWith("Validation timed out")
|
|
})
|
|
|
|
it("does not mark a submitted proof as missing", async function () {
|
|
await waitUntilProofIsRequired(id)
|
|
let submittedPeriod = periodOf(await currentTime())
|
|
await proofs.submitProof(id, proof)
|
|
await advanceTimeTo(periodEnd(submittedPeriod))
|
|
await expect(
|
|
proofs.markProofAsMissing(id, submittedPeriod)
|
|
).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 advanceTime(period)
|
|
}
|
|
let currentPeriod = periodOf(await currentTime())
|
|
await advanceTimeTo(periodEnd(currentPeriod))
|
|
await expect(
|
|
proofs.markProofAsMissing(id, currentPeriod)
|
|
).to.be.revertedWith("Proof was not required")
|
|
})
|
|
|
|
it("does not mark proof as missing twice", async function () {
|
|
await waitUntilProofIsRequired(id)
|
|
let missedPeriod = periodOf(await currentTime())
|
|
await advanceTimeTo(periodEnd(missedPeriod))
|
|
await proofs.markProofAsMissing(id, missedPeriod)
|
|
await expect(
|
|
proofs.markProofAsMissing(id, missedPeriod)
|
|
).to.be.revertedWith("Proof already marked as missing")
|
|
})
|
|
|
|
it("requires no proofs when no longer expected", async function () {
|
|
await waitUntilProofIsRequired(id)
|
|
await proofs.unexpectProofs(id)
|
|
await expect(await proofs.isProofRequired(id)).to.be.false
|
|
})
|
|
})
|
|
})
|