diff --git a/codex/node.nim b/codex/node.nim index 870c4f40..c89d0dad 100644 --- a/codex/node.nim +++ b/codex/node.nim @@ -312,10 +312,15 @@ proc start*(node: CodexNodeRef) {.async.} = await node.discovery.start() if contracts =? node.contracts: - contracts.sales.store = proc(cid: string) {.async.} = + contracts.sales.store = proc(cid: string, _: Availability) {.async.} = + # store data in local storage (await node.store(Cid.init(cid).tryGet())).tryGet() + contracts.sales.onClear = proc(availability: Availability, request: StorageRequest) = + # TODO: remove data from local storage + discard contracts.sales.prove = proc(cid: string): Future[seq[byte]] {.async.} = - return @[42'u8] # TODO: generate actual proof + # TODO: generate proof + return @[42'u8] await contracts.start() node.networkId = node.switch.peerInfo.peerId diff --git a/codex/sales.nim b/codex/sales.nim index eed2c033..39fa6ea4 100644 --- a/codex/sales.nim +++ b/codex/sales.nim @@ -17,6 +17,7 @@ type available*: seq[Availability] store: ?Store prove: ?Prove + onClear: ?OnClear onSale: ?OnSale Availability* = object id*: array[32, byte] @@ -33,8 +34,9 @@ type running: ?Future[void] waiting: ?Future[void] finished: bool - Store = proc(cid: string): Future[void] {.gcsafe, upraises: [].} + Store = proc(cid: string, availability: Availability): Future[void] {.gcsafe, upraises: [].} Prove = proc(cid: string): Future[seq[byte]] {.gcsafe, upraises: [].} + OnClear = proc(availability: Availability, request: StorageRequest) {.gcsafe, upraises: [].} OnSale = proc(availability: Availability, request: StorageRequest) {.gcsafe, upraises: [].} func new*(_: type Sales, market: Market, clock: Clock): Sales = @@ -57,6 +59,9 @@ proc `store=`*(sales: Sales, store: Store) = proc `prove=`*(sales: Sales, prove: Prove) = sales.prove = some prove +proc `onClear=`*(sales: Sales, onClear: OnClear) = + sales.onClear = some onClear + proc `onSale=`*(sales: Sales, callback: OnSale) = sales.onSale = some callback @@ -88,10 +93,12 @@ proc finish(agent: SalesAgent, success: bool) = if waiting =? agent.waiting: waiting.cancel() - if success and request =? agent.request: - if onSale =? agent.sales.onSale: + if success: + if onSale =? agent.sales.onSale and request =? agent.request: onSale(agent.availability, request) else: + if onClear =? agent.sales.onClear and request =? agent.request: + onClear(agent.availability, request) agent.sales.add(agent.availability) proc onFulfill(agent: SalesAgent, requestId: array[32, byte]) {.async.} = @@ -139,7 +146,7 @@ proc start(agent: SalesAgent) {.async.} = agent.waiting = some agent.waitForExpiry() - await store(request.content.cid) + await store(request.content.cid, availability) let proof = await prove(request.content.cid) await market.fulfillRequest(request.id, proof) except CancelledError: diff --git a/tests/codex/testsales.nim b/tests/codex/testsales.nim index 4bef9ac7..a1fd1f4c 100644 --- a/tests/codex/testsales.nim +++ b/tests/codex/testsales.nim @@ -32,8 +32,10 @@ suite "Sales": market = MockMarket.new() clock = MockClock.new() sales = Sales.new(market, clock) - sales.store = proc(_: string) {.async.} = discard - sales.prove = proc(_: string): Future[seq[byte]] {.async.} = return proof + sales.store = proc(cid: string, availability: Availability) {.async.} = + discard + sales.prove = proc(cid: string): Future[seq[byte]] {.async.} = + return proof await sales.start() request.expiry = (clock.now() + 42).u256 @@ -76,14 +78,18 @@ suite "Sales": test "retrieves and stores data locally": var storingCid: string - sales.store = proc(cid: string) {.async.} = storingCid = cid + var storingAvailability: Availability + sales.store = proc(cid: string, availability: Availability) {.async.} = + storingCid = cid + storingAvailability = availability sales.add(availability) discard await market.requestStorage(request) check storingCid == request.content.cid test "makes storage available again when data retrieval fails": let error = newException(IOError, "data retrieval failed") - sales.store = proc(cid: string) {.async.} = raise error + sales.store = proc(cid: string, availability: Availability) {.async.} = + raise error sales.add(availability) discard await market.requestStorage(request) check sales.available == @[availability] @@ -114,16 +120,31 @@ suite "Sales": check soldAvailability == availability check soldRequest == request + test "calls onClear when storage becomes available again": + sales.prove = proc(cid: string): Future[seq[byte]] {.async.} = + raise newException(IOError, "proof failed") + var clearedAvailability: Availability + var clearedRequest: StorageRequest + sales.onClear = proc(availability: Availability, request: StorageRequest) = + clearedAvailability = availability + clearedRequest = request + sales.add(availability) + discard await market.requestStorage(request) + check clearedAvailability == availability + check clearedRequest == request + test "makes storage available again when other host fulfills request": let otherHost = Address.example - sales.store = proc(_: string) {.async.} = await sleepAsync(1.hours) + sales.store = proc(cid: string, availability: Availability) {.async.} = + await sleepAsync(1.hours) sales.add(availability) discard await market.requestStorage(request) market.fulfillRequest(request.id, proof, otherHost) check sales.available == @[availability] test "makes storage available again when request expires": - sales.store = proc(_: string) {.async.} = await sleepAsync(1.hours) + sales.store = proc(cid: string, availability: Availability) {.async.} = + await sleepAsync(1.hours) sales.add(availability) discard await market.requestStorage(request) clock.set(request.expiry.truncate(int64))