[purchasing] move Purchase and PurchaseId into separate modules

This commit is contained in:
Mark Spanbroek 2022-09-27 10:28:36 +02:00 committed by Eric Mastro
parent 16024f21e9
commit bc3734b1a8
3 changed files with 69 additions and 71 deletions

View File

@ -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)

View File

@ -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)

View File

@ -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