From fd74268a8ab5ce5ff97b1860dae3d60cb26c3a35 Mon Sep 17 00:00:00 2001 From: Eric Mastro Date: Fri, 23 Sep 2022 12:33:39 +1000 Subject: [PATCH] Remove proof extension, test clean up 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. --- contracts/Marketplace.sol | 21 ++-- contracts/Proofs.sol | 40 +------- contracts/TestProofs.sol | 7 +- test/AccountLocks.test.js | 3 +- test/Marketplace.test.js | 200 ++++++++++++++++++-------------------- test/Proofs.test.js | 106 +++----------------- test/Storage.test.js | 6 +- test/marketplace.js | 22 +++-- 8 files changed, 140 insertions(+), 265 deletions(-) diff --git a/contracts/Marketplace.sol b/contracts/Marketplace.sol index 37e7bdb..bc2b03e 100644 --- a/contracts/Marketplace.sol +++ b/contracts/Marketplace.sol @@ -2,6 +2,7 @@ pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/utils/math/Math.sol"; import "./Collateral.sol"; import "./Proofs.sol"; @@ -62,20 +63,19 @@ contract Marketplace is Collateral, Proofs { require(balanceOf(msg.sender) >= collateral, "Insufficient collateral"); _lock(msg.sender, requestId); - _expectProofs(slotId, requestId, request.ask.proofProbability, request.ask.duration); + _expectProofs(slotId, request.ask.proofProbability, request.ask.duration); _submitProof(slotId, proof); slot.host = msg.sender; slot.requestId = requestId; RequestContext storage context = _context(requestId); context.slotsFilled += 1; + context.endsAt = block.timestamp + request.ask.duration; emit SlotFilled(requestId, slotIndex, slotId); if (context.slotsFilled == request.ask.slots) { context.state = RequestState.Started; context.startedAt = block.timestamp; - context.endsAt = block.timestamp + request.ask.duration; _extendLockExpiryTo(requestId, context.endsAt); - _extendProofEndTo(slotId, context.endsAt); emit RequestFulfilled(requestId); } } @@ -105,6 +105,7 @@ contract Marketplace is Collateral, Proofs { context.state == RequestState.Started) { context.state = RequestState.Failed; + context.endsAt = block.timestamp - 1; emit RequestFailed(requestId); // TODO: burn all remaining slot collateral (note: slot collateral not @@ -232,11 +233,16 @@ contract Marketplace is Collateral, Proofs { function proofEnd(bytes32 slotId) public view returns (uint256) { Slot memory slot = _slot(slotId); - uint256 end = _end(slot.requestId); - if (!_slotAcceptsProofs(slotId)) { - return end < block.timestamp ? end : block.timestamp - 1; + uint256 end = _end(slotId); + RequestContext storage context = _context(slot.requestId); + if (_slotAcceptsProofs(slotId)) { + return end; + } else { + // Calculate the earliest ending between a slot and a request. + // Request endings are set, for eg, when a request fails. + uint256 earliestEnd = Math.min(end, context.endsAt); + return Math.min(earliestEnd, block.timestamp - 1); } - return end; } function _price( @@ -260,7 +266,6 @@ contract Marketplace is Collateral, Proofs { } function state(bytes32 requestId) public view returns (RequestState) { - // TODO: add check for _isFinished if (_isCancelled(requestId)) { return RequestState.Cancelled; } else if (_isFinished(requestId)) { diff --git a/contracts/Proofs.sol b/contracts/Proofs.sol index 3ffa3e1..a6a20dd 100644 --- a/contracts/Proofs.sol +++ b/contracts/Proofs.sol @@ -20,7 +20,6 @@ contract Proofs { mapping(bytes32 => bool) private ids; mapping(bytes32 => uint256) private starts; mapping(bytes32 => uint256) private ends; - mapping(bytes32 => bytes32) private idEnds; mapping(bytes32 => uint256) private probabilities; mapping(bytes32 => uint256) private markers; mapping(bytes32 => uint256) private missed; @@ -35,21 +34,10 @@ contract Proofs { return timeout; } - function _end(bytes32 endId) internal view returns (uint256) { - uint256 end = ends[endId]; + function _end(bytes32 id) internal view returns (uint256) { + uint256 end = ends[id]; require(end > 0, "Proof ending doesn't exist"); - return ends[endId]; - } - - function _endId(bytes32 id) internal view returns (bytes32) { - bytes32 endId = idEnds[id]; - require(endId > 0, "endId for given id doesn't exist"); - return endId; - } - - function _endFromId(bytes32 id) internal view returns (uint256) { - bytes32 endId = _endId(id); - return _end(endId); + return ends[id]; } function _missed(bytes32 id) internal view returns (uint256) { @@ -67,22 +55,19 @@ contract Proofs { /// @notice Informs the contract that proofs should be expected for id /// @dev Requires that the id is not already in use /// @param id identifies the proof expectation, typically a slot id - /// @param endId Identifies the id of the proof expectation ending. Typically a request id. Different from id because the proof ending is shared amongst many ids. /// @param probability The probability that a proof should be expected /// @param duration Duration, from now, for which proofs should be expected function _expectProofs( bytes32 id, // typically slot id - bytes32 endId, // typically request id, used so that the ending is global for all slots uint256 probability, uint256 duration ) internal { require(!ids[id], "Proof id already in use"); ids[id] = true; starts[id] = block.timestamp; - ends[endId] = block.timestamp + duration; + ends[id] = block.timestamp + duration; probabilities[id] = probability; markers[id] = uint256(blockhash(block.number - 1)) % period; - idEnds[id] = endId; } function _unexpectProofs( @@ -134,14 +119,13 @@ contract Proofs { if (proofPeriod <= periodOf(starts[id])) { return (false, 0); } - uint256 end = _endFromId(id); + uint256 end = _end(id); if (proofPeriod >= periodOf(end)) { return (false, 0); } pointer = _getPointer(id, proofPeriod); bytes32 challenge = _getChallenge(pointer); uint256 probability = (probabilities[id] * (256 - downtime)) / 256; - // TODO: add test for below change isRequired = ids[id] && uint256(challenge) % probability == 0; } @@ -185,19 +169,5 @@ contract Proofs { missed[id] += 1; } - /// @notice Extends the proof end time - /// @dev The id must have a mapping to an end id, the end must exist, and the end must not have elapsed yet - /// @param id the id of the proofs to extend. Typically a slot id, the id is mapped to an endId. - /// @param ending the new end time (in seconds) - function _extendProofEndTo(bytes32 id, uint256 ending) internal { - bytes32 endId = _endId(id); - uint256 end = ends[endId]; - // TODO: create type aliases for id and endId so that _end() can return - // EndId storage and we don't need to replicate the below require here - require (end > 0, "Proof ending doesn't exist"); - require (block.timestamp <= end, "Proof already ended"); - ends[endId] = ending; - } - event ProofSubmitted(bytes32 id, bytes proof); } diff --git a/contracts/TestProofs.sol b/contracts/TestProofs.sol index aa6a37f..9cdb8fb 100644 --- a/contracts/TestProofs.sol +++ b/contracts/TestProofs.sol @@ -34,11 +34,10 @@ contract TestProofs is Proofs { function expectProofs( bytes32 id, - bytes32 endId, uint256 _probability, uint256 _duration ) public { - _expectProofs(id, endId, _probability, _duration); + _expectProofs(id, _probability, _duration); } function unexpectProofs(bytes32 id) public { @@ -68,8 +67,4 @@ contract TestProofs is Proofs { function markProofAsMissing(bytes32 id, uint256 _period) public { _markProofAsMissing(id, _period); } - - function extendProofEndTo(bytes32 id, uint256 ending) public { - _extendProofEndTo(id, ending); - } } diff --git a/test/AccountLocks.test.js b/test/AccountLocks.test.js index 42aad2e..96f4432 100644 --- a/test/AccountLocks.test.js +++ b/test/AccountLocks.test.js @@ -10,7 +10,6 @@ const { } = require("./evm") const { exampleLock } = require("./examples") const { hours } = require("./time") -const { waitUntilCancelled } = require("./marketplace") describe("Account Locks", function () { let locks @@ -202,7 +201,7 @@ describe("Account Locks", function () { }) it("fails when lock is already expired", async function () { - await waitUntilCancelled(expiry) + await advanceTimeTo(expiry) await expect(locks.extendLockExpiryTo(id, newExpiry)).to.be.revertedWith( "Lock already expired" ) diff --git a/test/Marketplace.test.js b/test/Marketplace.test.js index 6b4ee82..ee30bf8 100644 --- a/test/Marketplace.test.js +++ b/test/Marketplace.test.js @@ -178,26 +178,16 @@ describe("Marketplace", function () { }) it("is rejected when request is finished", async function () { - await waitUntilStarted( - marketplace, - request.ask.slots, - slot.request, - proof - ) - await waitUntilFinished(marketplace, slotId(slot)) + const lastSlot = await waitUntilStarted(marketplace, request, slot, proof) + await waitUntilFinished(marketplace, lastSlot) await expect( marketplace.fillSlot(slot.request, slot.index, proof) ).to.be.revertedWith("Request not accepting proofs") }) it("is rejected when request is failed", async function () { - await waitUntilStarted( - marketplace, - request.ask.slots, - slot.request, - proof - ) - await waitUntilFailed(marketplace, slot, request.ask.maxSlotLoss) + await waitUntilStarted(marketplace, request, slot, proof) + await waitUntilFailed(marketplace, request, slot) await expect( marketplace.fillSlot(slot.request, slot.index, proof) ).to.be.revertedWith("Request not accepting proofs") @@ -219,6 +209,18 @@ describe("Marketplace", function () { marketplace.fillSlot(slot.request, lastSlot, proof) ).to.be.revertedWith("Slot already filled") }) + }) + + describe("proof end", function () { + beforeEach(async function () { + switchAccount(client) + await token.approve(marketplace.address, price(request)) + await marketplace.requestStorage(request) + switchAccount(host) + await token.approve(marketplace.address, collateral) + await marketplace.deposit(collateral) + }) + it("shares proof end time for all slots in request", async function () { const lastSlot = request.ask.slots - 1 for (let i = 0; i < lastSlot; i++) { @@ -233,6 +235,39 @@ describe("Marketplace", function () { await expect((await marketplace.proofEnd(slotId(sloti))) === end) } }) + + it("sets proof end time to the request duration once filled", async function () { + await marketplace.fillSlot(slot.request, slot.index, proof) + await expect(await marketplace.proofEnd(slotId(slot))).to.be.eq( + (await currentTime()) + request.ask.duration + ) + }) + + it("sets proof end time to the past once failed", async function () { + await waitUntilStarted(marketplace, request, slot, proof) + await waitUntilFailed(marketplace, request, slot) + let slot0 = { ...slot, index: request.ask.maxSlotLoss + 1 } + const now = await currentTime() + await expect(await marketplace.proofEnd(slotId(slot0))).to.be.eq(now - 1) + }) + + it("sets proof end time to the past once cancelled", async function () { + await marketplace.fillSlot(slot.request, slot.index, proof) + await waitUntilCancelled(request) + const now = await currentTime() + await expect(await marketplace.proofEnd(slotId(slot))).to.be.eq(now - 1) + }) + + it("sets proof end time to the past once finished", async function () { + const lastSlot = await waitUntilStarted(marketplace, request, slot, proof) + await waitUntilFinished(marketplace, lastSlot) // sets proofEnd to block.timestamp - 1 + const now = await currentTime() + // the proof end time is set to block.timestamp - 1 when the contract is + // finished. in the process of calling currentTime and proofEnd, + // block.timestamp has advanced by 1, so the expected proof end time will + // be block.timestamp - 2. + await expect(await marketplace.proofEnd(slotId(slot))).to.be.eq(now - 2) + }) }) describe("freeing a slot", function () { @@ -257,48 +292,36 @@ describe("Marketplace", function () { ) }) - it("fails to free slot when finished", async function () { - await waitUntilStarted( - marketplace, - request.ask.slots, - slot.request, - proof + it("fails to free slot when cancelled", async function () { + await marketplace.fillSlot(slot.request, slot.index, proof) + await waitUntilCancelled(request) + await expect(marketplace.freeSlot(slotId(slot))).to.be.revertedWith( + "Slot not accepting proofs" ) - await waitUntilFinished(marketplace, slotId(slot)) - await expect(marketplace.freeSlot(id)).to.be.revertedWith( + }) + + it("fails to free slot when finished", async function () { + const lastSlot = await waitUntilStarted(marketplace, request, slot, proof) + await waitUntilFinished(marketplace, lastSlot) + await expect(marketplace.freeSlot(slotId(slot))).to.be.revertedWith( "Slot not accepting proofs" ) }) it("successfully frees slot", async function () { - await waitUntilStarted( - marketplace, - request.ask.slots, - slot.request, - proof - ) + await waitUntilStarted(marketplace, request, slot, proof) await expect(marketplace.freeSlot(id)).not.to.be.reverted }) it("emits event once slot is freed", async function () { - await waitUntilStarted( - marketplace, - request.ask.slots, - slot.request, - proof - ) + await waitUntilStarted(marketplace, request, slot, proof) await expect(await marketplace.freeSlot(id)) .to.emit(marketplace, "SlotFreed") .withArgs(slot.request, id) }) it("cannot get slot once freed", async function () { - await waitUntilStarted( - marketplace, - request.ask.slots, - slot.request, - proof - ) + await waitUntilStarted(marketplace, request, slot, proof) await marketplace.freeSlot(id) await expect(marketplace.slot(id)).to.be.revertedWith("Slot empty") }) @@ -315,13 +338,8 @@ describe("Marketplace", function () { }) it("pays the host", async function () { - await waitUntilStarted( - marketplace, - request.ask.slots, - slot.request, - proof - ) - await waitUntilFinished(marketplace, slotId(slot)) + const lastSlot = await waitUntilStarted(marketplace, request, slot, proof) + await waitUntilFinished(marketplace, lastSlot) const startBalance = await token.balanceOf(host.address) await marketplace.payoutSlot(slot.request, slot.index) const endBalance = await token.balanceOf(host.address) @@ -336,13 +354,8 @@ describe("Marketplace", function () { }) it("can only be done once", async function () { - await waitUntilStarted( - marketplace, - request.ask.slots, - slot.request, - proof - ) - await waitUntilFinished(marketplace, slotId(slot)) + const lastSlot = await waitUntilStarted(marketplace, request, slot, proof) + await waitUntilFinished(marketplace, lastSlot) await marketplace.payoutSlot(slot.request, slot.index) await expect( marketplace.payoutSlot(slot.request, slot.index) @@ -350,13 +363,8 @@ describe("Marketplace", function () { }) it("cannot be filled again", async function () { - await waitUntilStarted( - marketplace, - request.ask.slots, - slot.request, - proof - ) - await waitUntilFinished(marketplace, slotId(slot)) + const lastSlot = await waitUntilStarted(marketplace, request, slot, proof) + await waitUntilFinished(marketplace, lastSlot) await marketplace.payoutSlot(slot.request, slot.index) await expect(marketplace.fillSlot(slot.request, slot.index, proof)).to.be .reverted @@ -420,7 +428,7 @@ describe("Marketplace", function () { }) it("rejects withdraw when wrong account used", async function () { - await waitUntilCancelled(request.expiry) + await waitUntilCancelled(request) await expect(marketplace.withdrawFunds(slot.request)).to.be.revertedWith( "Invalid client address" ) @@ -432,7 +440,7 @@ describe("Marketplace", function () { for (let i = 0; i <= lastSlot; i++) { await marketplace.fillSlot(slot.request, i, proof) } - await waitUntilCancelled(request.expiry) + await waitUntilCancelled(request) switchAccount(client) await expect(marketplace.withdrawFunds(slot.request)).to.be.revertedWith( "Invalid state" @@ -440,7 +448,7 @@ describe("Marketplace", function () { }) it("emits event once request is cancelled", async function () { - await waitUntilCancelled(request.expiry) + await waitUntilCancelled(request) switchAccount(client) await expect(marketplace.withdrawFunds(slot.request)) .to.emit(marketplace, "RequestCancelled") @@ -448,7 +456,7 @@ describe("Marketplace", function () { }) it("withdraws to the client", async function () { - await waitUntilCancelled(request.expiry) + await waitUntilCancelled(request) switchAccount(client) const startBalance = await token.balanceOf(client.address) await marketplace.withdrawFunds(slot.request) @@ -474,7 +482,7 @@ describe("Marketplace", function () { }) it("state is Cancelled when client withdraws funds", async function () { - await waitUntilCancelled(request.expiry) + await waitUntilCancelled(request) switchAccount(client) await marketplace.withdrawFunds(slot.request) await expect(await marketplace.state(slot.request)).to.equal( @@ -483,38 +491,23 @@ describe("Marketplace", function () { }) it("changes state to Started once all slots are filled", async function () { - await waitUntilStarted( - marketplace, - request.ask.slots, - slot.request, - proof - ) + await waitUntilStarted(marketplace, request, slot, proof) await expect(await marketplace.state(slot.request)).to.equal( RequestState.Started ) }) it("state is Failed once too many slots are freed", async function () { - await waitUntilStarted( - marketplace, - request.ask.slots, - slot.request, - proof - ) - await waitUntilFailed(marketplace, slot, request.ask.maxSlotLoss) + await waitUntilStarted(marketplace, request, slot, proof) + await waitUntilFailed(marketplace, request, slot) await expect(await marketplace.state(slot.request)).to.equal( RequestState.Failed ) }) it("state is Finished once slot is paid out", async function () { - await waitUntilStarted( - marketplace, - request.ask.slots, - slot.request, - proof - ) - await waitUntilFinished(marketplace, slotId(slot)) + const lastSlot = await waitUntilStarted(marketplace, request, slot, proof) + await waitUntilFinished(marketplace, lastSlot) await marketplace.payoutSlot(slot.request, slot.index) await expect(await marketplace.state(slot.request)).to.equal( RequestState.Finished @@ -535,7 +528,7 @@ describe("Marketplace", function () { }) it("changes state to Cancelled once request is cancelled", async function () { - await waitUntilCancelled(request.expiry) + await waitUntilCancelled(request) await expect(await marketplace.state(slot.request)).to.equal( RequestState.Cancelled ) @@ -543,7 +536,7 @@ describe("Marketplace", function () { it("changes isCancelled to true once request is cancelled", async function () { await expect(await marketplace.isCancelled(slot.request)).to.be.false - await waitUntilCancelled(request.expiry) + await waitUntilCancelled(request) await expect(await marketplace.isCancelled(slot.request)).to.be.true }) @@ -556,7 +549,7 @@ describe("Marketplace", function () { it("changes isSlotCancelled to true once request is cancelled", async function () { await marketplace.fillSlot(slot.request, slot.index, proof) await expect(await marketplace.isSlotCancelled(slotId(slot))).to.be.false - await waitUntilCancelled(request.expiry) + await waitUntilCancelled(request) await expect(await marketplace.isSlotCancelled(slotId(slot))).to.be.true }) @@ -565,7 +558,7 @@ describe("Marketplace", function () { await expect(await marketplace.proofEnd(slotId(slot))).to.be.gt( await currentTime() ) - await waitUntilCancelled(request.expiry) + await waitUntilCancelled(request) await expect(await marketplace.proofEnd(slotId(slot))).to.be.lt( await currentTime() ) @@ -584,7 +577,7 @@ describe("Marketplace", function () { describe("accepting proofs", function () { it("fails when request Cancelled (isCancelled is true)", async function () { await marketplace.fillSlot(slot.request, slot.index, proof) - await waitUntilCancelled(request.expiry) + await waitUntilCancelled(request) await expect( marketplace.testAcceptsProofs(slotId(slot)) ).to.be.revertedWith("Slot not accepting proofs") @@ -592,7 +585,7 @@ describe("Marketplace", function () { it("fails when request Cancelled (state set to Cancelled)", async function () { await marketplace.fillSlot(slot.request, slot.index, proof) - await waitUntilCancelled(request.expiry) + await waitUntilCancelled(request) switchAccount(client) await marketplace.withdrawFunds(slot.request) await expect( @@ -601,26 +594,26 @@ describe("Marketplace", function () { }) it("fails when request Finished (isFinished is true)", async function () { - await waitUntilStarted( + const lastSlot = await waitUntilStarted( marketplace, - request.ask.slots, - slot.request, + request, + slot, proof ) - await waitUntilFinished(marketplace, slotId(slot)) + await waitUntilFinished(marketplace, lastSlot) await expect( marketplace.testAcceptsProofs(slotId(slot)) ).to.be.revertedWith("Slot not accepting proofs") }) it("fails when request Finished (state set to Finished)", async function () { - await waitUntilStarted( + const lastSlot = await waitUntilStarted( marketplace, - request.ask.slots, - slot.request, + request, + slot, proof ) - await waitUntilFinished(marketplace, slotId(slot)) + await waitUntilFinished(marketplace, lastSlot) await marketplace.payoutSlot(slot.request, slot.index) await expect( marketplace.testAcceptsProofs(slotId(slot)) @@ -628,12 +621,7 @@ describe("Marketplace", function () { }) it("fails when request Failed", async function () { - await waitUntilStarted( - marketplace, - request.ask.slots, - slot.request, - proof - ) + await waitUntilStarted(marketplace, request, slot, proof) for (let i = 0; i <= request.ask.maxSlotLoss; i++) { slot.index = i let id = slotId(slot) diff --git a/test/Proofs.test.js b/test/Proofs.test.js index 03e9762..af99803 100644 --- a/test/Proofs.test.js +++ b/test/Proofs.test.js @@ -14,7 +14,6 @@ const { periodic, hours, minutes } = require("./time") describe("Proofs", function () { const id = hexlify(randomBytes(32)) - const endId = hexlify(randomBytes(32)) const period = 30 * 60 const timeout = 5 const downtime = 64 @@ -36,20 +35,20 @@ describe("Proofs", function () { }) it("calculates an end time based on duration", async function () { - await proofs.expectProofs(id, endId, probability, duration) + await proofs.expectProofs(id, probability, duration) let end = (await currentTime()) + duration - expect((await proofs.end(endId)).toNumber()).to.be.closeTo(end, 1) + 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, endId, probability, duration) + await proofs.expectProofs(id, probability, duration) await expect( - proofs.expectProofs(id, endId, probability, duration) + 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, endId, probability, duration) + await proofs.expectProofs(id, probability, duration) let amount = 0 for (let i = 0; i < 100; i++) { if (await proofs.isProofRequired(id)) { @@ -64,7 +63,7 @@ describe("Proofs", function () { it("requires no proofs in the start period", async function () { const startPeriod = Math.floor((await currentTime()) / period) const probability = 1 - await proofs.expectProofs(id, endId, probability, duration) + 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)) @@ -73,14 +72,14 @@ describe("Proofs", function () { it("requires no proofs in the end period", async function () { const probability = 1 - await proofs.expectProofs(id, endId, probability, duration) + 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, endId, probability, duration) + await proofs.expectProofs(id, probability, duration) await advanceTime(duration + timeout) expect(await proofs.isProofRequired(id)).to.be.false }) @@ -90,7 +89,7 @@ describe("Proofs", function () { let id2 = hexlify(randomBytes(32)) let id3 = hexlify(randomBytes(32)) for (let id of [id1, id2, id3]) { - await proofs.expectProofs(id, endId, probability, duration) + await proofs.expectProofs(id, probability, duration) } let req1, req2, req3 while (req1 === req2 && req2 === req3) { @@ -119,7 +118,7 @@ describe("Proofs", function () { } beforeEach(async function () { - await proofs.expectProofs(id, endId, probability, duration) + await proofs.expectProofs(id, probability, duration) await advanceTimeTo(periodEnd(periodOf(await currentTime()))) await waitUntilProofWillBeRequired() }) @@ -152,7 +151,7 @@ describe("Proofs", function () { const proof = hexlify(randomBytes(42)) beforeEach(async function () { - await proofs.expectProofs(id, endId, probability, duration) + await proofs.expectProofs(id, probability, duration) }) async function waitUntilProofIsRequired(id) { @@ -271,87 +270,4 @@ describe("Proofs", function () { await expect(await proofs.isProofRequired(id)).to.be.false }) }) - - describe("extend proof end", function () { - const proof = hexlify(randomBytes(42)) - - beforeEach(async function () { - await proofs.expectProofs(id, endId, 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) - } - } - - async function isProofRequiredBefore(id, ending) { - let start = periodOf(await currentTime()) - let end = periodOf(ending) - let periods = end - start - await advanceTimeTo(periodEnd(periodOf(await currentTime()))) - for (let i = 0; i < periods; i++) { - if (await proofs.isProofRequired(id)) { - return true - } - await advanceTime(period) - } - return false - } - - it("can't extend if proof doesn't exist", async function () { - let ending = (await currentTime()) + duration - const otherId = hexlify(randomBytes(32)) - await expect( - proofs.extendProofEndTo(otherId, ending + 1) - ).to.be.revertedWith("endId for given id doesn't exist") - }) - - it("can't extend already lapsed proof ending", async function () { - let ending = (await currentTime()) + duration - await waitUntilProofIsRequired(id) - await advanceTimeTo(ending + 1) - await expect(proofs.extendProofEndTo(id, ending + 1)).to.be.revertedWith( - "Proof already ended" - ) - }) - - it("requires no proofs when ending has not been extended", async function () { - let ending = (await currentTime()) + duration - await expect(await isProofRequiredBefore(id, ending)).to.be.true - let endingExtended = ending + hours(1) - await advanceTimeTo(periodEnd(periodOf(endingExtended) + 1)) - await expect(await isProofRequiredBefore(id, endingExtended)).to.be.false - }) - - it("requires proofs when ending has been extended", async function () { - let ending = (await currentTime()) + duration - await expect(await isProofRequiredBefore(id, ending)).to.be.true - let endingExtended = ending + hours(1) - await proofs.extendProofEndTo(id, endingExtended) - await expect(await isProofRequiredBefore(id, endingExtended)).to.be.true - }) - - it("no longer requires proofs after extension lapsed", async function () { - async function expectNoProofsForPeriods(id, periods) { - await advanceTimeTo(periodEnd(periodOf(await currentTime()))) - for (let i = 0; i < periods; i++) { - await expect(await proofs.isProofRequired(id)).to.be.false - await advanceTime(period) - } - } - - let ending = (await currentTime()) + duration - let endingExtended = ending + hours(1) - await proofs.extendProofEndTo(id, endingExtended) - await advanceTimeTo(periodEnd(periodOf(endingExtended) + 1)) - await expectNoProofsForPeriods(id, 100) - }) - }) }) diff --git a/test/Storage.test.js b/test/Storage.test.js index 1bffc20..4d2c39e 100644 --- a/test/Storage.test.js +++ b/test/Storage.test.js @@ -76,7 +76,7 @@ describe("Storage", function () { describe("ending the contract", function () { it("unlocks the host collateral", async function () { await storage.fillSlot(slot.request, slot.index, proof) - await waitUntilFinished(storage, slotId(slot)) + await waitUntilFinished(storage, slot) await expect(storage.withdraw()).not.to.be.reverted }) }) @@ -121,7 +121,7 @@ describe("Storage", function () { it("frees slot when collateral slashed below minimum threshold", async function () { const id = slotId(slot) - await waitUntilStarted(storage, request.ask.slots, slot.request, proof) + await waitUntilStarted(storage, request, slot, proof) // max slashes before dropping below collateral threshold const maxSlashes = 10 @@ -172,7 +172,7 @@ describe("Storage", function () { it("fails to mark proof as missing when cancelled", async function () { await storage.fillSlot(slot.request, slot.index, proof) - await waitUntilCancelled(request.expiry) + await waitUntilCancelled(request) let missedPeriod = periodOf(await currentTime()) await expect( storage.markProofAsMissing(slotId(slot), missedPeriod) diff --git a/test/marketplace.js b/test/marketplace.js index 050d0ef..94317bb 100644 --- a/test/marketplace.js +++ b/test/marketplace.js @@ -1,24 +1,26 @@ const { advanceTimeTo } = require("./evm") const { slotId } = require("./ids") -async function waitUntilCancelled(expiry) { - await advanceTimeTo(expiry + 1) +async function waitUntilCancelled(request) { + await advanceTimeTo(request.expiry + 1) } -async function waitUntilStarted(contract, numSlots, requestId, proof) { - const lastSlot = numSlots - 1 - for (let i = 0; i <= lastSlot; i++) { - await contract.fillSlot(requestId, i, proof) +async function waitUntilStarted(contract, request, slot, proof) { + const lastSlotIdx = request.ask.slots - 1 + for (let i = 0; i <= lastSlotIdx; i++) { + await contract.fillSlot(slot.request, i, proof) } + return { ...slot, index: lastSlotIdx } } -async function waitUntilFinished(contract, slotId) { - const end = (await contract.proofEnd(slotId)).toNumber() +async function waitUntilFinished(contract, lastSlot) { + const lastSlotId = slotId(lastSlot) + const end = (await contract.proofEnd(lastSlotId)).toNumber() await advanceTimeTo(end + 1) } -async function waitUntilFailed(contract, slot, maxSlotLoss) { - for (let i = 0; i <= maxSlotLoss; i++) { +async function waitUntilFailed(contract, request, slot) { + for (let i = 0; i <= request.ask.maxSlotLoss; i++) { slot.index = i let id = slotId(slot) await contract.freeSlot(id)