diff --git a/codex/purchasing.nim b/codex/purchasing.nim index 65a677d7..7500b711 100644 --- a/codex/purchasing.nim +++ b/codex/purchasing.nim @@ -1,4 +1,3 @@ -import std/hashes import std/tables import pkg/stint import pkg/chronos @@ -6,9 +5,11 @@ import pkg/questionable import pkg/nimcrypto import ./market import ./clock +import ./purchasing/purchase export questionable export market +export purchase type Purchasing* = ref object @@ -17,25 +18,11 @@ type purchases: Table[PurchaseId, Purchase] proofProbability*: UInt256 requestExpiryInterval*: UInt256 - Purchase* = ref object - future: Future[void] - market: Market - clock: Clock - request*: StorageRequest PurchaseTimeout* = Timeout - PurchaseId* = distinct array[32, byte] const DefaultProofProbability = 100.u256 const DefaultRequestExpiryInterval = (10 * 60).u256 -proc start(purchase: Purchase) {.gcsafe.} -func id*(purchase: Purchase): PurchaseId -proc `==`*(x, y: PurchaseId): bool {.borrow.} -proc hash*(x: PurchaseId): Hash {.borrow.} -# Using {.borrow.} for toHex does not borrow correctly and causes a -# C-compilation error, so we must do it long form -proc toHex*(x: PurchaseId): string = array[32, byte](x).toHex - proc new*(_: type Purchasing, market: Market, clock: Clock): Purchasing = Purchasing( market: market, @@ -57,11 +44,7 @@ proc populate*(purchasing: Purchasing, request: StorageRequest): StorageRequest proc purchase*(purchasing: Purchasing, request: StorageRequest): Purchase = let request = purchasing.populate(request) - let purchase = Purchase( - request: request, - market: purchasing.market, - clock: purchasing.clock, - ) + let purchase = newPurchase(request, purchasing.market, purchasing.clock) purchase.start() purchasing.purchases[purchase.id] = purchase purchase @@ -71,54 +54,3 @@ func getPurchase*(purchasing: Purchasing, id: PurchaseId): ?Purchase = some purchasing.purchases[id] else: none Purchase - -proc run(purchase: Purchase) {.async.} = - let market = purchase.market - let clock = purchase.clock - - proc requestStorage {.async.} = - purchase.request = await market.requestStorage(purchase.request) - - proc waitUntilFulfilled {.async.} = - let done = newFuture[void]() - proc callback(_: RequestId) = - done.complete() - let request = purchase.request - let subscription = await market.subscribeFulfillment(request.id, callback) - await done - await subscription.unsubscribe() - - proc withTimeout(future: Future[void]) {.async.} = - let expiry = purchase.request.expiry.truncate(int64) - await future.withTimeout(clock, expiry) - - await requestStorage() - try: - await waitUntilFulfilled().withTimeout() - except PurchaseTimeout as e: - # If contract was fulfilled, the state would be RequestState.Started. - # Otherwise, the request would have timed out and should be considered - # cancelled. However, the request state hasn't been updated to - # RequestState.Cancelled yet so we can't check for that state or listen for - # an event emission. Instead, the state will be updated when the client - # requests to withdraw funds from the storage request. - await market.withdrawFunds(purchase.request.id) - raise e - -proc start(purchase: Purchase) = - purchase.future = purchase.run() - -proc wait*(purchase: Purchase) {.async.} = - await purchase.future - -func id*(purchase: Purchase): PurchaseId = - PurchaseId(purchase.request.id) - -func finished*(purchase: Purchase): bool = - purchase.future.finished - -func error*(purchase: Purchase): ?(ref CatchableError) = - if purchase.future.failed: - some purchase.future.error - else: - none (ref CatchableError) diff --git a/codex/purchasing/purchase.nim b/codex/purchasing/purchase.nim new file mode 100644 index 00000000..73920b12 --- /dev/null +++ b/codex/purchasing/purchase.nim @@ -0,0 +1,58 @@ +import ../market +import ../clock +import ./purchaseid + +export purchaseid + +type + Purchase* = ref object + future: Future[void] + market: Market + clock: Clock + request*: StorageRequest + +func newPurchase*(request: StorageRequest, + market: Market, + clock: Clock): Purchase = + Purchase(request: request, market: market, clock: clock) + +proc run(purchase: Purchase) {.async.} = + let market = purchase.market + let clock = purchase.clock + + proc requestStorage {.async.} = + purchase.request = await market.requestStorage(purchase.request) + + proc waitUntilFulfilled {.async.} = + let done = newFuture[void]() + proc callback(_: RequestId) = + done.complete() + let request = purchase.request + let subscription = await market.subscribeFulfillment(request.id, callback) + await done + await subscription.unsubscribe() + + proc withTimeout(future: Future[void]) {.async.} = + let expiry = purchase.request.expiry.truncate(int64) + await future.withTimeout(clock, expiry) + + await requestStorage() + await waitUntilFulfilled().withTimeout() + +proc start*(purchase: Purchase) = + purchase.future = purchase.run() + +proc wait*(purchase: Purchase) {.async.} = + await purchase.future + +func id*(purchase: Purchase): PurchaseId = + PurchaseId(purchase.request.id) + +func finished*(purchase: Purchase): bool = + purchase.future.finished + +func error*(purchase: Purchase): ?(ref CatchableError) = + if purchase.future.failed: + some purchase.future.error + else: + none (ref CatchableError) diff --git a/codex/purchasing/purchaseid.nim b/codex/purchasing/purchaseid.nim new file mode 100644 index 00000000..ee5c3a16 --- /dev/null +++ b/codex/purchasing/purchaseid.nim @@ -0,0 +1,8 @@ +import std/hashes +import pkg/nimcrypto + +type PurchaseId* = distinct array[32, byte] + +proc hash*(x: PurchaseId): Hash {.borrow.} +proc `==`*(x, y: PurchaseId): bool {.borrow.} +proc toHex*(x: PurchaseId): string = array[32, byte](x).toHex