diff --git a/codex/sales.nim b/codex/sales.nim index c025d867..42da851f 100644 --- a/codex/sales.nim +++ b/codex/sales.nim @@ -42,7 +42,7 @@ export stint export reservations logScope: - topics = "sales" + topics = "sales marketplace" type Sales* = ref object @@ -121,6 +121,7 @@ proc mySlots*(sales: Sales): Future[seq[Slot]] {.async.} = let slotIds = await market.mySlots() var slots: seq[Slot] = @[] + info "Loading active slots", slotsCount = len(slots) for slotId in slotIds: if slot =? (await market.getActiveSlot(slotId)): slots.add slot @@ -393,6 +394,7 @@ proc unsubscribe(sales: Sales) {.async.} = proc start*(sales: Sales) {.async.} = await sales.startSlotQueue() await sales.subscribe() + await sales.load() proc stop*(sales: Sales) {.async.} = trace "stopping sales" diff --git a/tests/codex/sales/testsales.nim b/tests/codex/sales/testsales.nim index 332e8e25..2f5bc627 100644 --- a/tests/codex/sales/testsales.nim +++ b/tests/codex/sales/testsales.nim @@ -22,6 +22,95 @@ import ../helpers/eventually import ../examples import ./helpers +asyncchecksuite "Sales - start": + let proof = exampleProof() + + var request: StorageRequest + var sales: Sales + var market: MockMarket + var clock: MockClock + var proving: Proving + var reservations: Reservations + var repo: RepoStore + var queue: SlotQueue + var itemsProcessed: seq[SlotQueueItem] + + setup: + request = StorageRequest( + ask: StorageAsk( + slots: 4, + slotSize: 100.u256, + duration: 60.u256, + reward: 10.u256, + collateral: 200.u256, + ), + content: StorageContent( + cid: "some cid" + ), + expiry: (getTime() + initDuration(hours=1)).toUnix.u256 + ) + + market = MockMarket.new() + clock = MockClock.new() + proving = Proving.new() + let repoDs = SQLiteDatastore.new(Memory).tryGet() + let metaDs = SQLiteDatastore.new(Memory).tryGet() + repo = RepoStore.new(repoDs, metaDs) + await repo.start() + sales = Sales.new(market, clock, proving, repo) + reservations = sales.context.reservations + sales.onStore = proc(request: StorageRequest, + slot: UInt256, + onBatch: BatchProc): Future[?!void] {.async.} = + return success() + queue = sales.context.slotQueue + proving.onProve = proc(slot: Slot): Future[seq[byte]] {.async.} = + return proof + itemsProcessed = @[] + request.expiry = (clock.now() + 42).u256 + + teardown: + await sales.stop() + await repo.stop() + + proc fillSlot(slotIdx: UInt256 = 0.u256) {.async.} = + let address = await market.getSigner() + let slot = MockSlot(requestId: request.id, + slotIndex: slotIdx, + proof: proof, + host: address) + market.filled.add slot + market.slotState[slotId(request.id, slotIdx)] = SlotState.Filled + + test "load slots when Sales module starts": + let me = await market.getSigner() + + request.ask.slots = 2 + market.requested = @[request] + market.requestState[request.id] = RequestState.New + + let slot0 = MockSlot(requestId: request.id, + slotIndex: 0.u256, + proof: proof, + host: me) + await fillSlot(slot0.slotIndex) + + let slot1 = MockSlot(requestId: request.id, + slotIndex: 1.u256, + proof: proof, + host: me) + await fillSlot(slot1.slotIndex) + + market.activeSlots[me] = @[request.slotId(0.u256), request.slotId(1.u256)] + market.requested = @[request] + market.activeRequests[me] = @[request.id] + + await sales.start() + + check eventually sales.agents.len == 2 + check sales.agents.any(agent => agent.data.requestId == request.id and agent.data.slotIndex == 0.u256) + check sales.agents.any(agent => agent.data.requestId == request.id and agent.data.slotIndex == 1.u256) + asyncchecksuite "Sales": let proof = exampleProof() @@ -58,6 +147,10 @@ asyncchecksuite "Sales": ) market = MockMarket.new() + + let me = await market.getSigner() + market.activeSlots[me] = @[] + clock = MockClock.new() proving = Proving.new() let repoDs = SQLiteDatastore.new(Memory).tryGet() @@ -113,7 +206,7 @@ asyncchecksuite "Sales": check isOk await reservations.reserve(availability) await market.requestStorage(request) let items = SlotQueueItem.init(request) - check eventuallyCheck items.allIt(itemsProcessed.contains(it)) + check eventually items.allIt(itemsProcessed.contains(it)) test "removes slots from slot queue once RequestCancelled emitted": let request1 = await addRequestToSaturatedQueue() @@ -146,7 +239,7 @@ asyncchecksuite "Sales": market.emitSlotFreed(request.id, 2.u256) let expected = SlotQueueItem.init(request, 2.uint16) - check eventuallyCheck itemsProcessed.contains(expected) + check eventually itemsProcessed.contains(expected) test "request slots are not added to the slot queue when no availabilities exist": var itemsProcessed: seq[SlotQueueItem] = @[] @@ -199,7 +292,7 @@ asyncchecksuite "Sales": check isOk await reservations.reserve(availability) await market.requestStorage(request) - check eventuallyCheck used + check eventually used test "reduces remaining availability size after download": let blk = bt.Block.example @@ -212,7 +305,7 @@ asyncchecksuite "Sales": return success() check isOk await reservations.reserve(availability) await market.requestStorage(request) - check eventuallyCheck getAvailability().?size == success 1.u256 + check eventually getAvailability().?size == success 1.u256 test "ignores download when duration not long enough": availability.duration = request.ask.duration - 1 @@ -265,7 +358,7 @@ asyncchecksuite "Sales": return success() check isOk await reservations.reserve(availability) await market.requestStorage(request) - check eventuallyCheck storingRequest == request + check eventually storingRequest == request check storingSlot < request.ask.slots.u256 test "handles errors during state run": @@ -280,7 +373,7 @@ asyncchecksuite "Sales": saleFailed = true check isOk await reservations.reserve(availability) await market.requestStorage(request) - check eventuallyCheck saleFailed + check eventually saleFailed test "makes storage available again when data retrieval fails": let error = newException(IOError, "data retrieval failed") @@ -290,7 +383,7 @@ asyncchecksuite "Sales": return failure(error) check isOk await reservations.reserve(availability) await market.requestStorage(request) - check eventuallyCheck getAvailability().?used == success false + check eventually getAvailability().?used == success false check getAvailability().?size == success availability.size test "generates proof of storage": @@ -301,7 +394,7 @@ asyncchecksuite "Sales": provingSlot = slot.slotIndex check isOk await reservations.reserve(availability) await market.requestStorage(request) - check eventuallyCheck provingRequest == request + check eventually provingRequest == request check provingSlot < request.ask.slots.u256 test "fills a slot": @@ -325,7 +418,7 @@ asyncchecksuite "Sales": soldSlotIndex = slotIndex check isOk await reservations.reserve(availability) await market.requestStorage(request) - check eventuallyCheck soldAvailability == availability + check eventually soldAvailability == availability check soldRequest == request check soldSlotIndex < request.ask.slots.u256 @@ -342,7 +435,7 @@ asyncchecksuite "Sales": clearedSlotIndex = slotIndex check isOk await reservations.reserve(availability) await market.requestStorage(request) - check eventuallyCheck clearedRequest == request + check eventually clearedRequest == request check clearedSlotIndex < request.ask.slots.u256 test "makes storage available again when other host fills the slot": @@ -356,7 +449,7 @@ asyncchecksuite "Sales": await market.requestStorage(request) for slotIndex in 0.. agent.data == expected) + check eventually sales.agents.len == 2 + check sales.agents.any(agent => agent.data.requestId == request.id and agent.data.slotIndex == 0.u256) + check sales.agents.any(agent => agent.data.requestId == request.id and agent.data.slotIndex == 1.u256)