[marketplace] update contract state to failed

Update contract state to failed when too many slots have been freed.
This commit is contained in:
Eric Mastro 2022-08-24 15:30:55 +10:00 committed by Eric Mastro
parent 9f8affdcaa
commit 980647876f
5 changed files with 24 additions and 8 deletions

View File

@ -55,10 +55,12 @@ contract Marketplace is Collateral, Proofs {
RequestContext storage context = requestContexts[requestId]; RequestContext storage context = requestContexts[requestId];
require(context.state == RequestState.Started, "Invalid state"); require(context.state == RequestState.Started, "Invalid state");
_removeAccountLock(slot.host, requestId); _removeAccountLock(slot.host, requestId);
// TODO: burn host's collateral except for repair costs + mark proof
// TODO: burn host's slot collateral except for repair costs + mark proof
// missing reward // missing reward
// Slot collateral is not yet implemented as the design decision was
// not finalised.
_unexpectProofs(slotId); _unexpectProofs(slotId);
@ -66,6 +68,17 @@ contract Marketplace is Collateral, Proofs {
slot.requestId = 0; slot.requestId = 0;
context.slotsFilled -= 1; context.slotsFilled -= 1;
emit SlotFreed(requestId, slotId); emit SlotFreed(requestId, slotId);
Request memory request = _request(requestId);
uint256 slotsLost = request.ask.slots - context.slotsFilled;
if (slotsLost > request.ask.maxSlotLoss) {
context.state = RequestState.Failed;
emit RequestFailed(requestId);
// TODO: burn all remaining slot collateral (note: slot collateral not
// yet implemented)
// TODO: send client remaining funds
}
} }
function fillSlot( function fillSlot(
@ -74,10 +87,10 @@ contract Marketplace is Collateral, Proofs {
bytes calldata proof bytes calldata proof
) public marketplaceInvariant { ) public marketplaceInvariant {
Request storage request = _request(requestId); Request storage request = _request(requestId);
// TODO: change below to check !_isCancelled(requestId) instead?
require(request.expiry > block.timestamp, "Request expired");
require(slotIndex < request.ask.slots, "Invalid slot"); require(slotIndex < request.ask.slots, "Invalid slot");
RequestContext storage context = requestContexts[requestId]; RequestContext storage context = requestContexts[requestId];
// TODO: change below to check !_isCancelled(requestId) instead?
require(!_isCancelled(requestId), "Request cancelled");
// TODO: in the case of repair, update below require condition by adding // TODO: in the case of repair, update below require condition by adding
// || context.state == RequestState.Started // || context.state == RequestState.Started
require(context.state == RequestState.New, "Invalid state"); require(context.state == RequestState.New, "Invalid state");
@ -273,6 +286,7 @@ contract Marketplace is Collateral, Proofs {
uint256 duration; // how long content should be stored (in seconds) uint256 duration; // how long content should be stored (in seconds)
uint256 proofProbability; // how often storage proofs are required uint256 proofProbability; // how often storage proofs are required
uint256 reward; // amount of tokens paid per second per slot to hosts uint256 reward; // amount of tokens paid per second per slot to hosts
uint64 maxSlotLoss; // Max slots that can be lost without data considered to be lost
} }
struct Content { struct Content {
@ -312,6 +326,7 @@ contract Marketplace is Collateral, Proofs {
event StorageRequested(bytes32 requestId, Ask ask); event StorageRequested(bytes32 requestId, Ask ask);
event RequestFulfilled(bytes32 indexed requestId); event RequestFulfilled(bytes32 indexed requestId);
event RequestFailed(bytes32 indexed requestId);
event SlotFilled( event SlotFilled(
bytes32 indexed requestId, bytes32 indexed requestId,
uint256 indexed slotIndex, uint256 indexed slotIndex,

View File

@ -118,7 +118,6 @@ contract Proofs {
pointer = _getPointer(id, proofPeriod); pointer = _getPointer(id, proofPeriod);
bytes32 challenge = _getChallenge(pointer); bytes32 challenge = _getChallenge(pointer);
uint256 probability = (probabilities[id] * (256 - downtime)) / 256; uint256 probability = (probabilities[id] * (256 - downtime)) / 256;
// TODO: add test for below change
isRequired = ids[id] && uint256(challenge) % probability == 0; isRequired = ids[id] && uint256(challenge) % probability == 0;
} }

View File

@ -215,7 +215,7 @@ describe("Marketplace", function () {
).to.be.revertedWith("Unknown request") ).to.be.revertedWith("Unknown request")
}) })
it("is rejected when request is expired", async function () { it("is rejected when request is expired/cancelled", async function () {
switchAccount(client) switchAccount(client)
let expired = { ...request, expiry: now() - hours(1) } let expired = { ...request, expiry: now() - hours(1) }
await token.approve(marketplace.address, price(request)) await token.approve(marketplace.address, price(request))
@ -223,7 +223,7 @@ describe("Marketplace", function () {
switchAccount(host) switchAccount(host)
await expect( await expect(
marketplace.fillSlot(requestId(expired), slot.index, proof) marketplace.fillSlot(requestId(expired), slot.index, proof)
).to.be.revertedWith("Request expired") ).to.be.revertedWith("Request cancelled")
}) })
it("is rejected when slot index not in range", async function () { it("is rejected when slot index not in range", async function () {

View File

@ -10,6 +10,7 @@ const exampleRequest = () => ({
duration: hours(10), duration: hours(10),
proofProbability: 4, // require a proof roughly once every 4 periods proofProbability: 4, // require a proof roughly once every 4 periods
reward: 84, reward: 84,
maxSlotLoss: 2,
}, },
content: { content: {
cid: "zb2rhheVmk3bLks5MgzTqyznLu1zqGH5jrfTA1eAZXrjx7Vob", cid: "zb2rhheVmk3bLks5MgzTqyznLu1zqGH5jrfTA1eAZXrjx7Vob",

View File

@ -2,7 +2,7 @@ const { ethers } = require("hardhat")
const { keccak256, defaultAbiCoder } = ethers.utils const { keccak256, defaultAbiCoder } = ethers.utils
function requestId(request) { function requestId(request) {
const Ask = "tuple(int64, uint256, uint256, uint256, uint256)" const Ask = "tuple(int64, uint256, uint256, uint256, uint256, int64)"
const Erasure = "tuple(uint64)" const Erasure = "tuple(uint64)"
const PoR = "tuple(bytes, bytes, bytes)" const PoR = "tuple(bytes, bytes, bytes)"
const Content = "tuple(string, " + Erasure + ", " + PoR + ")" const Content = "tuple(string, " + Erasure + ", " + PoR + ")"
@ -18,6 +18,7 @@ function askToArray(ask) {
ask.duration, ask.duration,
ask.proofProbability, ask.proofProbability,
ask.reward, ask.reward,
ask.maxSlotLoss,
] ]
} }