[marketplace] test & fix slotState()

This commit is contained in:
Mark Spanbroek 2023-01-18 15:26:21 +01:00 committed by markspanbroek
parent 70d8967f26
commit b62eeb564a
7 changed files with 104 additions and 22 deletions

View File

@ -247,24 +247,25 @@ contract Marketplace is Collateral, Proofs, StateRetrieval {
} }
} }
function slotState(SlotId slotId) internal view override returns (SlotState) { function slotState(SlotId slotId) public view override returns (SlotState) {
Slot storage slot = slots[slotId]; Slot storage slot = slots[slotId];
if (RequestId.unwrap(slot.requestId) == 0) {
return SlotState.Free;
}
RequestState reqState = requestState(slot.requestId); RequestState reqState = requestState(slot.requestId);
if (slot.state == SlotState.Paid) { if (slot.state == SlotState.Paid) {
return SlotState.Paid; return SlotState.Paid;
} else if (
slot.state == SlotState.Failed || reqState == RequestState.Failed
) {
return SlotState.Failed;
} else if (
slot.state == SlotState.Finished ||
reqState == RequestState.Finished ||
reqState == RequestState.Cancelled
) {
return SlotState.Finished;
} else {
return slot.state;
} }
if (reqState == RequestState.Cancelled) {
return SlotState.Finished;
}
if (reqState == RequestState.Finished) {
return SlotState.Finished;
}
if (reqState == RequestState.Failed) {
return SlotState.Failed;
}
return slot.state;
} }
struct RequestContext { struct RequestContext {

View File

@ -19,7 +19,7 @@ abstract contract Proofs is Periods {
mapping(SlotId => mapping(Period => bool)) private received; mapping(SlotId => mapping(Period => bool)) private received;
mapping(SlotId => mapping(Period => bool)) private missing; mapping(SlotId => mapping(Period => bool)) private missing;
function slotState(SlotId id) internal view virtual returns (SlotState); function slotState(SlotId id) public view virtual returns (SlotState);
function missingProofs(SlotId slotId) public view returns (uint256) { function missingProofs(SlotId slotId) public view returns (uint256) {
return missed[slotId]; return missed[slotId];

View File

@ -46,10 +46,10 @@ enum RequestState {
} }
enum SlotState { enum SlotState {
Free, // [default] not filled yet, or host has freed slot Free, // [default] not filled yet, or host has vacated the slot
Filled, // host has filled slot Filled, // host has filled slot
Finished, // successfully completed Finished, // successfully completed
Failed, // host has missed too many proofs Failed, // the request has failed
Paid // host has been paid Paid // host has been paid
} }

View File

@ -8,10 +8,9 @@ contract TestMarketplace is Marketplace {
constructor( constructor(
IERC20 token, IERC20 token,
MarketplaceConfig memory config MarketplaceConfig memory config
) Marketplace(token, config) // solhint-disable-next-line no-empty-blocks )
{ Marketplace(token, config) // solhint-disable-next-line no-empty-blocks
{}
}
function forciblyFreeSlot(SlotId slotId) public { function forciblyFreeSlot(SlotId slotId) public {
_forciblyFreeSlot(slotId); _forciblyFreeSlot(slotId);

View File

@ -10,7 +10,7 @@ contract TestProofs is Proofs {
// solhint-disable-next-line no-empty-blocks // solhint-disable-next-line no-empty-blocks
constructor(ProofConfig memory config) Proofs(config) {} constructor(ProofConfig memory config) Proofs(config) {}
function slotState(SlotId slotId) internal view override returns (SlotState) { function slotState(SlotId slotId) public view override returns (SlotState) {
return states[slotId]; return states[slotId];
} }

View File

@ -6,7 +6,7 @@ const { expect } = require("chai")
const { exampleConfiguration, exampleRequest } = require("./examples") const { exampleConfiguration, exampleRequest } = require("./examples")
const { periodic, hours } = require("./time") const { periodic, hours } = require("./time")
const { requestId, slotId, askToArray } = require("./ids") const { requestId, slotId, askToArray } = require("./ids")
const { RequestState } = require("./requests") const { RequestState, SlotState } = require("./requests")
const { const {
waitUntilCancelled, waitUntilCancelled,
waitUntilStarted, waitUntilStarted,
@ -548,6 +548,86 @@ describe("Marketplace", function () {
}) })
}) })
describe("slot state", function () {
const { Free, Filled, Finished, Failed, Paid } = SlotState
let period, periodEnd
beforeEach(async function () {
period = config.proofs.period
;({ periodOf, periodEnd } = periodic(period))
switchAccount(client)
await token.approve(marketplace.address, price(request))
await marketplace.requestStorage(request)
switchAccount(host)
await token.approve(marketplace.address, config.collateral.initialAmount)
await marketplace.deposit(config.collateral.initialAmount)
})
async function waitUntilProofIsRequired(id) {
await advanceTimeTo(periodEnd(periodOf(await currentTime())))
while (
!(
(await marketplace.isProofRequired(id)) &&
(await marketplace.getPointer(id)) < 250
)
) {
await advanceTime(period)
}
}
it("is 'Free' initially", async function () {
expect(await marketplace.slotState(slotId(slot))).to.equal(Free)
})
it("changes to 'Filled' when slot is filled", async function () {
await marketplace.fillSlot(slot.request, slot.index, proof)
expect(await marketplace.slotState(slotId(slot))).to.equal(Filled)
})
it("changes to 'Finished' when request finishes", async function () {
await waitUntilStarted(marketplace, request, proof)
await waitUntilFinished(marketplace, slot.request)
expect(await marketplace.slotState(slotId(slot))).to.equal(Finished)
})
it("changes to 'Finished' when request is cancelled", async function () {
await marketplace.fillSlot(slot.request, slot.index, proof)
await waitUntilCancelled(request)
expect(await marketplace.slotState(slotId(slot))).to.equal(Finished)
})
it("changes to 'Free' when host frees the slot", async function () {
await marketplace.fillSlot(slot.request, slot.index, proof)
await marketplace.freeSlot(slotId(slot))
expect(await marketplace.slotState(slotId(slot))).to.equal(Free)
})
it("changes to 'Free' when too many proofs are missed", async function () {
await waitUntilStarted(marketplace, request, proof)
while ((await marketplace.slotState(slotId(slot))) === Filled) {
await waitUntilProofIsRequired(slotId(slot))
const missedPeriod = periodOf(await currentTime())
await advanceTime(period)
await marketplace.markProofAsMissing(slotId(slot), missedPeriod)
}
expect(await marketplace.slotState(slotId(slot))).to.equal(Free)
})
it("changes to 'Failed' when request fails", async function () {
await waitUntilStarted(marketplace, request, proof)
await waitUntilSlotFailed(marketplace, request, slot)
expect(await marketplace.slotState(slotId(slot))).to.equal(Failed)
})
it("changes to 'Paid' when host has been paid", async function () {
await waitUntilStarted(marketplace, request, proof)
await waitUntilFinished(marketplace, slot.request)
await marketplace.freeSlot(slotId(slot))
expect(await marketplace.slotState(slotId(slot))).to.equal(Paid)
})
})
describe("proof requirements", function () { describe("proof requirements", function () {
let period, periodOf, periodEnd let period, periodOf, periodEnd

View File

@ -10,6 +10,8 @@ const SlotState = {
Free: 0, Free: 0,
Filled: 1, Filled: 1,
Finished: 2, Finished: 2,
Failed: 3,
Paid: 4,
} }
module.exports = { RequestState, SlotState } module.exports = { RequestState, SlotState }