[marketplace] update contract state to failed
Update contract state to failed when too many slots have been freed.
This commit is contained in:
parent
9f8affdcaa
commit
980647876f
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 () {
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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,
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue