From d4a0521f330f830d6bd1ae3af8f2a6d86b532ab7 Mon Sep 17 00:00:00 2001 From: Eric Mastro Date: Thu, 24 Nov 2022 18:49:16 +1100 Subject: [PATCH] WIP: initial implementation of one-to-many Needs to be cleaned up and reorganised. --- contracts/Marketplace.sol | 188 +++++++++++++++++++----------- contracts/libs/Debug.sol | 60 ++++++++++ contracts/libs/ORM2.sol | 233 ++++++++++++++++++++++++++++++++++++++ contracts/libs/Utils.sol | 2 +- test/Marketplace.test.js | 75 ++---------- 5 files changed, 423 insertions(+), 135 deletions(-) create mode 100644 contracts/libs/Debug.sol create mode 100644 contracts/libs/ORM2.sol diff --git a/contracts/Marketplace.sol b/contracts/Marketplace.sol index 26b7bc7..e1cead5 100644 --- a/contracts/Marketplace.sol +++ b/contracts/Marketplace.sol @@ -8,6 +8,9 @@ import "./Collateral.sol"; import "./Proofs.sol"; import "./libs/SetMap.sol"; import "./libs/Utils.sol"; +import "./libs/ORM2.sol"; + +import "hardhat/console.sol"; // DELETE ME contract Marketplace is Collateral, Proofs { using EnumerableSet for EnumerableSet.Bytes32Set; @@ -15,6 +18,7 @@ contract Marketplace is Collateral, Proofs { using SetMap for SetMap.Bytes32SetMap; using SetMap for SetMap.AddressBytes32SetMap; using SetMap for SetMap.Bytes32AddressSetMap; + using ORM2 for ORM2.OneToMany; type RequestId is bytes32; type SlotId is bytes32; @@ -24,10 +28,19 @@ contract Marketplace is Collateral, Proofs { mapping(RequestId => Request) private requests; mapping(RequestId => RequestContext) private requestContexts; mapping(SlotId => Slot) private slots; - SetMap.AddressBytes32SetMap private activeRequestsForClients; // purchasing - SetMap.Bytes32AddressSetMap private activeRequestsForHosts; // purchasing + // SetMap.AddressBytes32SetMap private activeRequestsForClients; // purchasing + //SetMap.Bytes32AddressSetMap private activeRequestsForHosts; // sales + // ORM.Table private activeRequestsForHosts; // sales SetMap.Bytes32SetMap private activeSlots; // sales + ORM2.OneToMany private activeClientRequests; + + // address => RequestId + ORM2.OneToMany private activeHostRequests; + // RequestId => SlotId + ORM2.OneToMany private activeRequestSlots; + + constructor( IERC20 _token, uint256 _collateral, @@ -43,53 +56,61 @@ contract Marketplace is Collateral, Proofs { } function myRequests() public view returns (RequestId[] memory) { - SetMap.AddressBytes32SetMapKey key = _toAddressSetMapKey(msg.sender); - RequestId[] memory requestIds = _toRequestIds(activeRequestsForClients.values(key)); - RequestId[] memory result = new RequestId[](requestIds.length); - uint8 counter = 0; + uint256 counter = 0; + bytes32[] storage requestIds = + activeClientRequests.getManyKeys(_toBytes32(msg.sender)); + bytes32[] memory result = new bytes32[](requestIds.length); for (uint8 i = 0; i < requestIds.length; i++) { - if (!_isCancelled(requestIds[i])) { - result[counter] = requestIds[i]; - counter++; + // There may exist slots that are still "active", but are part of a request + // that is expired but has not been set to the cancelled state yet. In that + // case, return an empty array. + // TODO: remove cancelled lookups https://discord.com/channels/@me/958221374076366898/1044947242013954140 + bytes32 requestId = requestIds[i]; + if (_isCancelled(RequestId.wrap(requestId))) { + continue; } + result[counter] = requestId; + counter++; } - return _toRequestIds(Utils._resize(_toBytes32s(result), counter)); + return _toRequestIds(Utils._resize(result, counter)); } - function requestsForHost(address host) public view returns(RequestId[] memory) { - EnumerableSet.Bytes32Set storage keys = activeRequestsForHosts.keys(); - uint256 keyLength = keys.length(); - RequestId[] memory result = new RequestId[](keyLength); - - uint8 counter = 0; // should be big enough - for (uint8 i = 0; i < keyLength; i++) { - RequestId requestId = RequestId.wrap(keys.at(i)); - SetMap.Bytes32AddressSetMapKey key = _toBytes32AddressSetMapKey(requestId); - if (activeRequestsForHosts.contains(key, host) && - !_isCancelled(requestId)) - { - result[counter] = requestId; - counter++; - } - } - return _toRequestIds(Utils._resize(_toBytes32s(result), counter)); - } - - function mySlots(RequestId requestId) + function mySlots() public view returns (SlotId[] memory) { - // There may exist slots that are still "active", but are part of a request - // that is expired but has not been set to the cancelled state yet. In that - // case, return an empty array. - if (_isCancelled(requestId)) { - SlotId[] memory result; - return result; + uint256 counter = 0; + uint256 totalSlots = activeRequestSlots.getTotalManyCount(); // set this bigger than our possible filtered list size + console.log("[mySlots] total slotIds: ", totalSlots); + if (totalSlots == 0) { + return new SlotId[](0); } - bytes32[] memory slotIds = - activeSlots.values(_toBytes32SetMapKey(requestId), msg.sender); - return _toSlotIds(slotIds); + bytes32[] memory result = new bytes32[](totalSlots); + bytes32[] storage requestIds = + activeHostRequests.getManyKeys(_toBytes32(msg.sender)); + console.log("[mySlots] total requestIds: ", requestIds.length); + for (uint256 i = 0; i < requestIds.length; i++) { + // There may exist slots that are still "active", but are part of a request + // that is expired but has not been set to the cancelled state yet. In that + // case, return an empty array. + // TODO: remove cancelled lookups https://discord.com/channels/@me/958221374076366898/1044947242013954140 + bytes32 requestId = requestIds[i]; + if (_isCancelled(RequestId.wrap(requestId))) { + continue; + } + if (activeRequestSlots.isOne(requestIds[i])) { + bytes32[] storage slotIds = activeRequestSlots.getManyKeys(requestIds[i]); + console.log("[mySlots] requestId: "); + console.logBytes32(requestIds[i]); + console.log("[mySlots] total slotsIds for requestId: ", slotIds.length); + for (uint256 j = 0; j < slotIds.length; j++) { + result[counter] = slotIds[j]; + counter++; + } + } + } + return _toSlotIds(Utils._resize(result, counter)); } function _equals(RequestId a, RequestId b) internal pure returns (bool) { @@ -111,8 +132,17 @@ contract Marketplace is Collateral, Proofs { context.endsAt = block.timestamp + request.ask.duration; _setProofEnd(_toEndId(id), context.endsAt); - activeRequestsForClients.add(_toAddressSetMapKey(request.client), - RequestId.unwrap(id)); + bytes32 addrBytes32 = _toBytes32(request.client); + if (!activeClientRequests.isOne(addrBytes32)) { + activeClientRequests.createOne(addrBytes32); + } + if (!activeClientRequests.isMany(RequestId.unwrap(id))) { + activeClientRequests.createMany(addrBytes32, RequestId.unwrap(id)); + } + + if (!activeRequestSlots.isOne(RequestId.unwrap(id))) { + activeRequestSlots.createOne(RequestId.unwrap(id)); + } _createLock(_toLockId(id), request.expiry); @@ -148,11 +178,24 @@ contract Marketplace is Collateral, Proofs { slot.requestId = requestId; RequestContext storage context = _context(requestId); context.slotsFilled += 1; - activeSlots.add(_toBytes32SetMapKey(requestId), - slot.host, - SlotId.unwrap(slotId)); - activeRequestsForHosts.add(_toBytes32AddressSetMapKey(requestId), - slot.host); + + console.log("FILLING slotId: "); + console.logBytes32(SlotId.unwrap(slotId)); + + bytes32 sender = _toBytes32(msg.sender); + if (!activeHostRequests.isOne(sender)) { + activeHostRequests.createOne(sender); + } + // address => RequestId + if (!activeHostRequests.isMany(RequestId.unwrap(requestId))) { + activeHostRequests.createMany(sender, RequestId.unwrap(requestId)); + } + + // RequestId => SlotId + if (!activeRequestSlots.isMany(SlotId.unwrap(slotId))) { + activeRequestSlots.createMany(RequestId.unwrap(requestId), SlotId.unwrap(slotId)); + } + emit SlotFilled(requestId, slotIndex, slotId); if (context.slotsFilled == request.ask.slots) { context.state = RequestState.Started; @@ -179,13 +222,10 @@ contract Marketplace is Collateral, Proofs { _unexpectProofs(_toProofId(slotId)); - SetMap.Bytes32SetMapKey requestIdKey = _toBytes32SetMapKey(requestId); - activeSlots.remove(requestIdKey, - slot.host, - SlotId.unwrap(slotId)); - if (activeSlots.length(requestIdKey, slot.host) == 0) { - activeRequestsForHosts.remove(_toBytes32AddressSetMapKey(requestId), - slot.host); + console.log("FREEING slotId: "); + console.logBytes32(SlotId.unwrap(slotId)); + if (activeRequestSlots.isMany(SlotId.unwrap(slotId))) { + activeRequestSlots.deleteMany(SlotId.unwrap(slotId)); } slot.host = address(0); slot.requestId = RequestId.wrap(0); @@ -201,10 +241,11 @@ contract Marketplace is Collateral, Proofs { context.state = RequestState.Failed; _setProofEnd(_toEndId(requestId), block.timestamp - 1); context.endsAt = block.timestamp - 1; - activeRequestsForClients.remove(_toAddressSetMapKey(request.client), - RequestId.unwrap(requestId)); - activeRequestsForHosts.clear(_toBytes32AddressSetMapKey(requestId)); - activeSlots.clear(_toBytes32SetMapKey(requestId)); + console.log("about to delete many"); + activeClientRequests.deleteMany(RequestId.unwrap(requestId)); + console.log("about to clear all manys"); + activeRequestSlots.clearAllManys(RequestId.unwrap(requestId)); + console.log("about to cleared all manys"); emit RequestFailed(requestId); // TODO: burn all remaining slot collateral (note: slot collateral not @@ -219,18 +260,19 @@ contract Marketplace is Collateral, Proofs { { require(_isFinished(requestId), "Contract not ended"); RequestContext storage context = _context(requestId); - Request storage request = _request(requestId); + // Request storage request = _request(requestId); context.state = RequestState.Finished; - activeRequestsForClients.remove(_toAddressSetMapKey(request.client), - RequestId.unwrap(requestId)); + if (activeClientRequests.isMany(RequestId.unwrap(requestId))) { + activeClientRequests.deleteMany(RequestId.unwrap(requestId)); + } SlotId slotId = _toSlotId(requestId, slotIndex); Slot storage slot = _slot(slotId); require(!slot.hostPaid, "Already paid"); - activeSlots.remove(_toBytes32SetMapKey(requestId), - slot.host, - SlotId.unwrap(slotId)); - activeRequestsForHosts.remove(_toBytes32AddressSetMapKey(requestId), - slot.host); + activeRequestSlots.deleteMany(SlotId.unwrap(slotId)); + if (activeRequestSlots.getManyCount() == 0) { + activeRequestSlots.deleteOne(RequestId.unwrap(requestId)); + activeHostRequests.deleteMany(RequestId.unwrap(requestId)); + } uint256 amount = pricePerSlot(requests[requestId]); funds.sent += amount; funds.balance -= amount; @@ -251,10 +293,10 @@ contract Marketplace is Collateral, Proofs { // Update request state to Cancelled. Handle in the withdraw transaction // as there needs to be someone to pay for the gas to update the state context.state = RequestState.Cancelled; - activeRequestsForClients.remove(_toAddressSetMapKey(request.client), - RequestId.unwrap(requestId)); - activeRequestsForHosts.clear(_toBytes32AddressSetMapKey(requestId)); - activeSlots.clear(_toBytes32SetMapKey(requestId)); + activeClientRequests.deleteMany(RequestId.unwrap(requestId)); + + activeRequestSlots.clearAllManys(RequestId.unwrap(requestId)); + // TODO: handle dangling RequestId in activeHostRequests (for address) emit RequestCancelled(requestId); // TODO: To be changed once we start paying out hosts for the time they @@ -454,6 +496,14 @@ contract Marketplace is Collateral, Proofs { } } + function _toBytes32(address addr) + private + pure + returns (bytes32 result) + { + return bytes32(uint(uint160(addr))); + } + function _toBytes32s(RequestId[] memory array) private pure diff --git a/contracts/libs/Debug.sol b/contracts/libs/Debug.sol new file mode 100644 index 0000000..e3e164d --- /dev/null +++ b/contracts/libs/Debug.sol @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.8; + +import "./ORM2.sol"; +import "hardhat/console.sol"; // DELETE ME + +library Debug { + function _toHex16 (bytes16 data) private pure returns (bytes32 result) { + result = bytes32 (data) & 0xFFFFFFFFFFFFFFFF000000000000000000000000000000000000000000000000 | + (bytes32 (data) & 0x0000000000000000FFFFFFFFFFFFFFFF00000000000000000000000000000000) >> 64; + result = result & 0xFFFFFFFF000000000000000000000000FFFFFFFF000000000000000000000000 | + (result & 0x00000000FFFFFFFF000000000000000000000000FFFFFFFF0000000000000000) >> 32; + result = result & 0xFFFF000000000000FFFF000000000000FFFF000000000000FFFF000000000000 | + (result & 0x0000FFFF000000000000FFFF000000000000FFFF000000000000FFFF00000000) >> 16; + result = result & 0xFF000000FF000000FF000000FF000000FF000000FF000000FF000000FF000000 | + (result & 0x00FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF0000) >> 8; + result = (result & 0xF000F000F000F000F000F000F000F000F000F000F000F000F000F000F000F000) >> 4 | + (result & 0x0F000F000F000F000F000F000F000F000F000F000F000F000F000F000F000F00) >> 8; + result = bytes32 (0x3030303030303030303030303030303030303030303030303030303030303030 + + uint256 (result) + + (uint256 (result) + 0x0606060606060606060606060606060606060606060606060606060606060606 >> 4 & + 0x0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F) * 7); + } + + function _toHex (bytes32 data) internal pure returns (string memory) { + return string (abi.encodePacked ("0x", _toHex16 (bytes16 (data)), _toHex16 (bytes16 (data << 128)))); + } + + // @notice Prints the contents of the one-to-many table + // Usage example (from ORM): Debug._printTable(db._oneList, + // getManyKeys(db, oneId), + // getTotalManyCount(db)); + // @dev Explain to a developer any extra details + // @param oneList list of one ids + // @param manyKeys list of one ids + // @param totalManyCount list of one ids + // function _printTable(bytes32[] storage oneList, + // bytes32[] storage manyKeys, + // uint256 totalManyCount) + function _printTable(ORM2.OneToMany storage db) + internal + view + { + console.log("|-----------------------------------------------------------------------------------------------------------------------------------------|"); + console.log("| Key | Value |"); + console.log("| ------------------------------------------------------------------ | ------------------------------------------------------------------ |"); + for(uint8 i = 0; i < db._oneList.length; i++) { + bytes32 oneId = db._oneList[i]; + console.log("|", _toHex(oneId), "| |"); + + bytes32[] storage manyKeys = ORM2.getManyKeys(db, oneId); + for(uint8 j = 0; j < manyKeys.length; j++) { + bytes32 slotId = manyKeys[j]; + console.log("| |", _toHex(slotId), "|"); + } + } + console.log("|_________________________________________________________________________________________________________________________________________|"); + console.log(" TOTAL Values: ", ORM2.getTotalManyCount(db)); + } +} diff --git a/contracts/libs/ORM2.sol b/contracts/libs/ORM2.sol new file mode 100644 index 0000000..224715a --- /dev/null +++ b/contracts/libs/ORM2.sol @@ -0,0 +1,233 @@ +// SPDX-License-Identifier: MIT +// heavily inspired by: https://bitbucket.org/rhitchens2/soliditystoragepatterns/src/master/GeneralizedCollection.sol +pragma solidity ^0.8.8; + +import "hardhat/console.sol"; +import "./Debug.sol"; // DELETE ME + +library ORM2 { + // first entity is called a "One" + struct OneStruct { + // needed to delete a "One" + uint _oneListPointer; + // One has many "Many" + bytes32[] _manyIds; + mapping(bytes32 => uint) _manyIdPointers; // manyId => row of _manyIds + // more app data + } + + // other entity is called a "Many" + struct ManyStruct { + // needed to delete a "Many" + uint _manyListPointer; + // many has exactly one "One" + bytes32 _oneId; + // add app fields + } + + struct OneToMany { + mapping(bytes32 => OneStruct) _oneStructs; + bytes32[] _oneList; + mapping(bytes32 => ManyStruct) _manyStructs; + bytes32[] _manyList; + } + + function getOneCount(OneToMany storage db) + internal + view + returns(uint) + { + return db._oneList.length; + } + + function getManyCount(OneToMany storage db) internal view returns(uint) { + return db._manyList.length; + } + + function isOne(OneToMany storage db, bytes32 oneId) + internal + view + returns(bool) + { + if(db._oneList.length == 0) return false; + return db._oneList[db._oneStructs[oneId]._oneListPointer] == oneId; + } + + function isMany(OneToMany storage db, bytes32 manyId) + internal + view + returns(bool) + { + if(db._manyList.length == 0) return false; + uint256 row = db._manyStructs[manyId]._manyListPointer; + bool retVal = db._manyList[row] == manyId; + return retVal; + } + + // Iterate over a One's Many keys + function getManyCount(OneToMany storage db, bytes32 oneId) + internal + view + returns(uint manyCount) + { + require(isOne(db, oneId), "oneId does not exist"); + return db._oneStructs[oneId]._manyIds.length; + } + + function getTotalManyCount(OneToMany storage db) + internal + view + returns(uint manyCount) + { + return db._manyList.length; + } + + function getManyKeyAtIndex(OneToMany storage db, + bytes32 oneId, + uint row) + internal + view + returns(bytes32 manyKey) + { + require(isOne(db, oneId), "oneId does not exist"); + return db._oneStructs[oneId]._manyIds[row]; + } + + function getManyKeys(OneToMany storage db, + bytes32 oneId) + internal + view + returns(bytes32[] storage manyKeys) + { + require(isOne(db, oneId), "oneId does not exist"); + return db._oneStructs[oneId]._manyIds; + } + + // Insert + function createOne(OneToMany storage db, bytes32 oneId) + internal + returns(bool) + { + require(!isOne(db, oneId), "oneId already exists"); // duplicate key prohibited + + db._oneList.push(oneId); + db._oneStructs[oneId]._oneListPointer = getOneCount(db) - 1; + return true; + } + + function createMany(OneToMany storage db, bytes32 oneId, bytes32 manyId) + internal + returns(bool) + { + require(isOne(db, oneId), "oneId does not exist"); + require(!isMany(db, manyId), "manyId already exists"); // duplicate key prohibited + + ManyStruct storage manyRow = db._manyStructs[manyId]; + db._manyList.push(manyId); + manyRow._manyListPointer = db._manyList.length - 1; + manyRow._oneId = oneId; // each many has exactly one "One", so this is mandatory + + // We also maintain a list of "Many" that refer to the "One", so ... + OneStruct storage oneRow = db._oneStructs[oneId]; + oneRow._manyIds.push(manyId); + oneRow._manyIdPointers[manyId] = oneRow._manyIds.length - 1; + return true; + } + + // Delete + function deleteOne(OneToMany storage db, bytes32 oneId) + internal + returns(bool) + { + require(isOne(db, oneId), "oneId does not exist"); + require(db._oneStructs[oneId]._manyIds.length == 0, "references manys"); // this would break referential integrity + + uint rowToDelete = db._oneStructs[oneId]._oneListPointer; + bytes32 keyToMove = db._oneList[db._oneList.length-1]; + db._oneList[rowToDelete] = keyToMove; + db._oneStructs[keyToMove]._oneListPointer = rowToDelete; + db._oneList.pop(); + delete db._oneStructs[oneId]; + return true; + } + + function deleteMany(OneToMany storage db, bytes32 manyId) + internal + returns(bool) + { + require(isMany(db, manyId), "manys do not exist"); // non-existant key + + console.log("deleting many, manyId: "); + console.logBytes32(manyId); + // delete from the Many table + uint256 toDeleteIndex = db._manyStructs[manyId]._manyListPointer; + + uint256 lastIndex = db._manyList.length - 1; + + if (lastIndex != toDeleteIndex) { + bytes32 lastValue = db._manyList[lastIndex]; + + // Move the last value to the index where the value to delete is + db._manyList[toDeleteIndex] = lastValue; + // Update the index for the moved value + db._manyStructs[lastValue]._manyListPointer = toDeleteIndex; // Replace lastvalue's index to valueIndex + } + db._manyList.pop(); + + bytes32 oneId = db._manyStructs[manyId]._oneId; + OneStruct storage oneRow = db._oneStructs[oneId]; + toDeleteIndex = oneRow._manyIdPointers[manyId]; + lastIndex = oneRow._manyIds.length - 1; + if (lastIndex != toDeleteIndex) { + bytes32 lastValue = oneRow._manyIds[lastIndex]; + + // Move the last value to the index where the value to delete is + oneRow._manyIds[toDeleteIndex] = lastValue; + // Update the index for the moved value + oneRow._manyIdPointers[lastValue] = toDeleteIndex; // Replace lastvalue's index to valueIndex + } + oneRow._manyIds.pop(); + delete oneRow._manyIdPointers[manyId]; + + delete db._manyStructs[manyId]; + + + + // uint rowToDelete = db._manyStructs[manyId]._manyListPointer; + // console.log("row to delete: ", rowToDelete); + // bytes32 keyToMove = db._manyList[db._manyList.length-1]; + // db._manyList[rowToDelete] = keyToMove; + // uint rowToMove = db._manyStructs[keyToMove]._manyListPointer; + // db._manyStructs[manyId]._manyListPointer = rowToDelete; + // db._manyStructs[keyToMove]._manyListPointer = rowToMove; + // db._manyList.pop(); + + // we ALSO have to delete this key from the list in the ONE that was joined to this Many + // bytes32 oneId = db._manyStructs[manyId]._oneId; // it's still there, just not dropped from index + // rowToDelete = db._oneStructs[oneId]._manyIdPointers[manyId]; + // keyToMove = db._oneStructs[oneId]._manyIds[db._oneStructs[oneId]._manyIds.length-1]; + // db._oneStructs[oneId]._manyIds[rowToDelete] = keyToMove; + // db._oneStructs[oneId]._manyIdPointers[keyToMove] = rowToDelete; + // db._oneStructs[oneId]._manyIds.pop(); + return true; + } + + + + function clearAllManys(OneToMany storage db, bytes32 oneId) + internal + returns(bool) + { + require(isOne(db, oneId), "oneId does not exist"); // non-existant key + + console.log("[clearAllMany] clearing all slotIds for requestId: ", Debug._toHex(oneId)); + console.log("[clearAllMany] BEFORE clearing"); + Debug._printTable(db); + // delete db._manyList; + delete db._oneStructs[oneId]._manyIds; + bool result = deleteOne(db, oneId); + console.log("[clearAllMany] AFTER clearing"); + Debug._printTable(db); + return result; + } +} diff --git a/contracts/libs/Utils.sol b/contracts/libs/Utils.sol index b15fd13..8dafbd6 100644 --- a/contracts/libs/Utils.sol +++ b/contracts/libs/Utils.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.8; library Utils { - function _resize(bytes32[] memory array, uint8 newSize) + function _resize(bytes32[] memory array, uint256 newSize) internal pure returns (bytes32[] memory) diff --git a/test/Marketplace.test.js b/test/Marketplace.test.js index 2f719fe..b113cc9 100644 --- a/test/Marketplace.test.js +++ b/test/Marketplace.test.js @@ -691,7 +691,7 @@ describe("Marketplace", function () { }) }) - describe("list of active requests", function () { + describe("list of active requests for client", function () { beforeEach(async function () { switchAccount(host) await token.approve(marketplace.address, collateral) @@ -738,56 +738,6 @@ describe("Marketplace", function () { }) }) - describe("list of active requests for host", 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("is empty when no slot is filled", async function () { - expect(await marketplace.requestsForHost(host.address)).to.deep.equal([]) - }) - - it("adds request to list when filling slot", async function () { - await marketplace.fillSlot(slot.request, slot.index, proof) - expect(await marketplace.requestsForHost(host.address)).to.deep.equal([ - slot.request, - ]) - }) - - it("removes request from list when cancelled", async function () { - await marketplace.fillSlot(slot.request, slot.index, proof) - await waitUntilCancelled(request) - expect(await marketplace.requestsForHost(host.address)).to.deep.equal([]) - }) - - it("removes request from list when funds are withdrawn", async function () { - await marketplace.fillSlot(slot.request, slot.index, proof) - await waitUntilCancelled(request) - switchAccount(client) - await marketplace.withdrawFunds(slot.request) - expect(await marketplace.requestsForHost(host.address)).to.deep.equal([]) - }) - - it("removes request from list when request fails", async function () { - await waitUntilStarted(marketplace, request, proof) - await waitUntilFailed(marketplace, request, slot) - expect(await marketplace.requestsForHost(host.address)).to.deep.equal([]) - }) - - it("removes request from list when request finishes", async function () { - switchAccount(host) - await waitUntilStarted(marketplace, request, proof) - await waitUntilFinished(marketplace, requestId(request)) - await marketplace.payoutSlot(slot.request, slot.index) - expect(await marketplace.requestsForHost(host.address)).to.deep.equal([]) - }) - }) - describe("list of active slots", function () { beforeEach(async function () { switchAccount(client) @@ -802,7 +752,7 @@ describe("Marketplace", function () { await marketplace.fillSlot(slot.request, slot.index, proof) let slot1 = { ...slot, index: slot.index + 1 } await marketplace.fillSlot(slot.request, slot1.index, proof) - expect(await marketplace.mySlots(slot.request)).to.deep.equal([ + expect(await marketplace.mySlots()).to.deep.equal([ slotId(slot), slotId(slot1), ]) @@ -813,9 +763,7 @@ describe("Marketplace", function () { let slot1 = { ...slot, index: slot.index + 1 } await marketplace.fillSlot(slot.request, slot1.index, proof) await marketplace.freeSlot(slotId(slot)) - expect(await marketplace.mySlots(slot.request)).to.deep.equal([ - slotId(slot1), - ]) + expect(await marketplace.mySlots()).to.deep.equal([slotId(slot1)]) }) it("returns no slots when cancelled", async function () { @@ -823,7 +771,7 @@ describe("Marketplace", function () { let slot1 = { ...slot, index: slot.index + 1 } await marketplace.fillSlot(slot.request, slot1.index, proof) await waitUntilCancelled(request) - expect(await marketplace.mySlots(slot.request)).to.deep.equal([]) + expect(await marketplace.mySlots()).to.deep.equal([]) }) it("removes active slots for all hosts in a request when it fails", async function () { @@ -843,9 +791,8 @@ describe("Marketplace", function () { } await waitUntilFailed(marketplace, request, slot) - expect(await marketplace.mySlots(slot.request)).to.deep.equal([]) switchAccount(host) - expect(await marketplace.mySlots(slot.request)).to.deep.equal([]) + expect(await marketplace.mySlots()).to.deep.equal([]) }) it("doesn't remove active slots for hosts in request that didn't fail", async function () { @@ -864,6 +811,9 @@ describe("Marketplace", function () { // wait until first request fails await waitUntilFailed(marketplace, request, slot) + console.log("1st requestId: ", requestId(request)) + console.log("2nd requestId: ", requestId(request2)) + // check that our active slots only contains slotIds from second request let expected = [] let expectedSlot = { ...slot, index: 0, request: requestId(request2) } @@ -872,19 +822,14 @@ describe("Marketplace", function () { let id = slotId(expectedSlot) expected.push(id) } - expect(await marketplace.mySlots(slot.request)).to.deep.equal([]) - expect(await marketplace.mySlots(expectedSlot.request)).to.deep.equal( - expected - ) + expect(await marketplace.mySlots()).to.deep.equal(expected) }) it("removes slots from list when request finishes", async function () { await waitUntilStarted(marketplace, request, proof) await waitUntilFinished(marketplace, requestId(request)) await marketplace.payoutSlot(slot.request, slot.index) - expect(await marketplace.mySlots(slot.request)).to.not.contain( - slotId(slot) - ) + expect(await marketplace.mySlots()).to.not.contain(slotId(slot)) }) }) })