Clear active slots by host

Allow for clearing of active slots by host, by incrementing an mapping index. The new index points to a fresh instance of EnumerableSet, effectively wiping it clean.
This commit is contained in:
Eric Mastro 2022-11-15 16:53:31 +11:00
parent 17a04d6c09
commit 6303b54e2a
No known key found for this signature in database
GPG Key ID: 141E3048D95A4E63
2 changed files with 27 additions and 10 deletions

View File

@ -19,7 +19,8 @@ contract Marketplace is Collateral, Proofs {
mapping(RequestId => RequestContext) private requestContexts; mapping(RequestId => RequestContext) private requestContexts;
mapping(SlotId => Slot) private slots; mapping(SlotId => Slot) private slots;
mapping(address => EnumerableSet.Bytes32Set) private activeRequests; mapping(address => EnumerableSet.Bytes32Set) private activeRequests;
mapping(address => EnumerableSet.Bytes32Set) private activeSlots; mapping(address => mapping(uint8 => EnumerableSet.Bytes32Set)) private activeSlots;
mapping(address => uint8) private activeSlotsIdx;
constructor( constructor(
IERC20 _token, IERC20 _token,
@ -40,7 +41,25 @@ contract Marketplace is Collateral, Proofs {
} }
function mySlots() public view returns (SlotId[] memory) { function mySlots() public view returns (SlotId[] memory) {
return _toSlotIds(activeSlots[msg.sender].values()); EnumerableSet.Bytes32Set storage slotIds = _activeSlotsForHost(msg.sender);
return _toSlotIds(slotIds.values());
}
function _activeSlotsForHost(address host)
internal
view
returns (EnumerableSet.Bytes32Set storage)
{
mapping(uint8 => EnumerableSet.Bytes32Set) storage active = activeSlots[host];
uint8 idx = activeSlotsIdx[host];
return active[idx];
}
/// @notice Clears active slots for a host
/// @dev Because there are no efficient ways to clear an EnumerableSet, an index is updated that points to a new instance.
/// @param host address of the host for which to clear the active slots
function _clearActiveSlots(address host) internal {
activeSlotsIdx[host] = activeSlotsIdx[host] + 1;
} }
function requestStorage(Request calldata request) function requestStorage(Request calldata request)
@ -94,7 +113,7 @@ contract Marketplace is Collateral, Proofs {
slot.requestId = requestId; slot.requestId = requestId;
RequestContext storage context = _context(requestId); RequestContext storage context = _context(requestId);
context.slotsFilled += 1; context.slotsFilled += 1;
activeSlots[slot.host].add(SlotId.unwrap(slotId)); _activeSlotsForHost(slot.host).add(SlotId.unwrap(slotId));
emit SlotFilled(requestId, slotIndex, slotId); emit SlotFilled(requestId, slotIndex, slotId);
if (context.slotsFilled == request.ask.slots) { if (context.slotsFilled == request.ask.slots) {
context.state = RequestState.Started; context.state = RequestState.Started;
@ -121,7 +140,8 @@ contract Marketplace is Collateral, Proofs {
_unexpectProofs(_toProofId(slotId)); _unexpectProofs(_toProofId(slotId));
activeSlots[slot.host].remove(SlotId.unwrap(slotId)); address slotHost = slot.host;
_activeSlotsForHost(slotHost).remove(SlotId.unwrap(slotId));
slot.host = address(0); slot.host = address(0);
slot.requestId = RequestId.wrap(0); slot.requestId = RequestId.wrap(0);
context.slotsFilled -= 1; context.slotsFilled -= 1;
@ -137,9 +157,7 @@ contract Marketplace is Collateral, Proofs {
_setProofEnd(_toEndId(requestId), block.timestamp - 1); _setProofEnd(_toEndId(requestId), block.timestamp - 1);
context.endsAt = block.timestamp - 1; context.endsAt = block.timestamp - 1;
activeRequests[request.client].remove(RequestId.unwrap(requestId)); activeRequests[request.client].remove(RequestId.unwrap(requestId));
// NOTE: not removing any remaining active slots for the host as listing _clearActiveSlots(slotHost);
// values of enumerable set could be too expensive (copies from storage to
// memory)
emit RequestFailed(requestId); emit RequestFailed(requestId);
// TODO: burn all remaining slot collateral (note: slot collateral not // TODO: burn all remaining slot collateral (note: slot collateral not
@ -160,7 +178,7 @@ contract Marketplace is Collateral, Proofs {
SlotId slotId = _toSlotId(requestId, slotIndex); SlotId slotId = _toSlotId(requestId, slotIndex);
Slot storage slot = _slot(slotId); Slot storage slot = _slot(slotId);
require(!slot.hostPaid, "Already paid"); require(!slot.hostPaid, "Already paid");
activeSlots[slot.host].remove(SlotId.unwrap(slotId)); _activeSlotsForHost(slot.host).remove(SlotId.unwrap(slotId));
uint256 amount = pricePerSlot(requests[requestId]); uint256 amount = pricePerSlot(requests[requestId]);
funds.sent += amount; funds.sent += amount;
funds.balance -= amount; funds.balance -= amount;

View File

@ -763,8 +763,7 @@ describe("Marketplace", function () {
it("removes all slots from list when request fails", async function () { it("removes all slots from list when request fails", async function () {
await waitUntilStarted(marketplace, request, proof) await waitUntilStarted(marketplace, request, proof)
await waitUntilFailed(marketplace, request, slot) await waitUntilFailed(marketplace, request, slot)
let expectedLength = request.ask.slots - (request.ask.maxSlotLoss + 1) expect((await marketplace.mySlots())).to.deep.equal([])
expect((await marketplace.mySlots()).length).to.equal(expectedLength)
}) })
it("removes slots from list when request finishes", async function () { it("removes slots from list when request finishes", async function () {