[purchasing] Update to latest dagger-contracts

This commit is contained in:
Mark Spanbroek 2022-06-14 15:25:48 +02:00 committed by markspanbroek
parent b7ab9481d9
commit 4b5cfe8e41
3 changed files with 50 additions and 75 deletions

View File

@ -3,6 +3,7 @@ import pkg/chronos
type type
Clock* = ref object of RootObj Clock* = ref object of RootObj
SecondsSince1970* = int64 SecondsSince1970* = int64
Timeout* = object of CatchableError
method now*(clock: Clock): SecondsSince1970 {.base.} = method now*(clock: Clock): SecondsSince1970 {.base.} =
raiseAssert "not implemented" raiseAssert "not implemented"
@ -10,3 +11,15 @@ method now*(clock: Clock): SecondsSince1970 {.base.} =
proc waitUntil*(clock: Clock, time: SecondsSince1970) {.async.} = proc waitUntil*(clock: Clock, time: SecondsSince1970) {.async.} =
while clock.now() < time: while clock.now() < time:
await sleepAsync(1.seconds) await sleepAsync(1.seconds)
proc withTimeout*(future: Future[void],
clock: Clock,
expiry: SecondsSince1970) {.async.} =
let timeout = clock.waitUntil(expiry)
try:
await future or timeout
finally:
await timeout.cancelAndWait()
if not future.completed:
await future.cancelAndWait()
raise newException(Timeout, "Timed out")

View File

@ -25,6 +25,7 @@ type
request*: StorageRequest request*: StorageRequest
offers*: seq[StorageOffer] offers*: seq[StorageOffer]
selected*: ?StorageOffer selected*: ?StorageOffer
PurchaseTimeout* = Timeout
const DefaultProofProbability = 100.u256 const DefaultProofProbability = 100.u256
const DefaultRequestExpiryInterval = (10 * 60).u256 const DefaultRequestExpiryInterval = (10 * 60).u256
@ -69,29 +70,30 @@ func getPurchase*(purchasing: Purchasing, id: array[32, byte]): ?Purchase =
else: else:
none Purchase none Purchase
proc selectOffer(purchase: Purchase) {.async.} =
var cheapest: ?StorageOffer
for offer in purchase.offers:
without purchase.clock.now().u256 < offer.expiry - purchase.offerExpiryMargin:
continue
without current =? cheapest:
cheapest = some offer
continue
if current.price > offer.price:
cheapest = some offer
if cheapest =? cheapest:
await purchase.market.selectOffer(cheapest.id)
purchase.selected = some cheapest
proc run(purchase: Purchase) {.async.} = proc run(purchase: Purchase) {.async.} =
proc onOffer(offer: StorageOffer) =
purchase.offers.add(offer)
let market = purchase.market let market = purchase.market
purchase.request = await market.requestStorage(purchase.request) let clock = purchase.clock
let subscription = await market.subscribeOffers(purchase.request.id, onOffer)
await purchase.clock.waitUntil(purchase.request.expiry.truncate(int64)) proc requestStorage {.async.} =
await purchase.selectOffer() purchase.request = await market.requestStorage(purchase.request)
await subscription.unsubscribe()
proc waitUntilFulfilled {.async.} =
let done = newFuture[void]()
proc callback(_: array[32, byte]) =
done.complete()
let request = purchase.request
let subscription = await market.subscribeFulfillment(request.id, callback)
try:
await done
finally:
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) = proc start(purchase: Purchase) =
purchase.future = purchase.run() purchase.future = purchase.run()

View File

@ -25,13 +25,8 @@ suite "Purchasing":
) )
) )
proc purchaseAndWait(request: StorageRequest) {.async.} =
let purchase = purchasing.purchase(request)
clock.set(market.requested[^1].expiry.truncate(int64))
await purchase.wait()
test "submits a storage request when asked": test "submits a storage request when asked":
await purchaseAndWait(request) discard purchasing.purchase(request)
let submitted = market.requested[0] let submitted = market.requested[0]
check submitted.ask.duration == request.ask.duration check submitted.ask.duration == request.ask.duration
check submitted.ask.size == request.ask.size check submitted.ask.size == request.ask.size
@ -48,12 +43,12 @@ suite "Purchasing":
test "can change default value for proof probability": test "can change default value for proof probability":
purchasing.proofProbability = 42.u256 purchasing.proofProbability = 42.u256
await purchaseAndWait(request) discard purchasing.purchase(request)
check market.requested[0].ask.proofProbability == 42.u256 check market.requested[0].ask.proofProbability == 42.u256
test "can override proof probability per request": test "can override proof probability per request":
request.ask.proofProbability = 42.u256 request.ask.proofProbability = 42.u256
await purchaseAndWait(request) discard purchasing.purchase(request)
check market.requested[0].ask.proofProbability == 42.u256 check market.requested[0].ask.proofProbability == 42.u256
test "has a default value for request expiration interval": test "has a default value for request expiration interval":
@ -62,66 +57,31 @@ suite "Purchasing":
test "can change default value for request expiration interval": test "can change default value for request expiration interval":
purchasing.requestExpiryInterval = 42.u256 purchasing.requestExpiryInterval = 42.u256
let start = getTime().toUnix() let start = getTime().toUnix()
await purchaseAndWait(request) discard purchasing.purchase(request)
check market.requested[0].expiry == (start + 42).u256 check market.requested[0].expiry == (start + 42).u256
test "can override expiry time per request": test "can override expiry time per request":
let expiry = (getTime().toUnix() + 42).u256 let expiry = (getTime().toUnix() + 42).u256
request.expiry = expiry request.expiry = expiry
await purchaseAndWait(request) discard purchasing.purchase(request)
check market.requested[0].expiry == expiry check market.requested[0].expiry == expiry
test "includes a random nonce in every storage request": test "includes a random nonce in every storage request":
await purchaseAndWait(request) discard purchasing.purchase(request)
await purchaseAndWait(request) discard purchasing.purchase(request)
check market.requested[0].nonce != market.requested[1].nonce check market.requested[0].nonce != market.requested[1].nonce
proc createOffer(request: StorageRequest): StorageOffer = test "succeeds when request is fulfilled":
StorageOffer(
requestId: request.id,
expiry: (getTime() + initDuration(hours = 1)).toUnix().u256
)
test "selects the cheapest offer":
let purchase = purchasing.purchase(request) let purchase = purchasing.purchase(request)
let request = market.requested[0] let request = market.requested[0]
var offer1, offer2 = createOffer(request) let proof = seq[byte].example
offer1.price = 20.u256 await market.fulfillRequest(request.id, proof)
offer2.price = 10.u256
discard await market.offerStorage(offer1)
discard await market.offerStorage(offer2)
clock.set(request.expiry.truncate(int64))
await purchase.wait() await purchase.wait()
check purchase.selected == some offer2 check purchase.error.isNone
check market.selected[0] == offer2.id
test "ignores offers that expired": test "fails when request times out":
let expired = (getTime() - initTimeInterval(hours = 1)).toUnix().u256
let purchase = purchasing.purchase(request) let purchase = purchasing.purchase(request)
let request = market.requested[0] let request = market.requested[0]
var offer1, offer2 = request.createOffer()
offer1.price = 20.u256
offer2.price = 10.u256
offer2.expiry = expired
discard await market.offerStorage(offer1)
discard await market.offerStorage(offer2)
clock.set(request.expiry.truncate(int64)) clock.set(request.expiry.truncate(int64))
await purchase.wait() expect PurchaseTimeout:
check market.selected[0] == offer1.id await purchase.wait()
test "has a default expiration margin for offers":
check purchasing.offerExpiryMargin != 0.u256
test "ignores offers that are about to expire":
let expiryMargin = purchasing.offerExpiryMargin
let purchase = purchasing.purchase(request)
let request = market.requested[0]
var offer1, offer2 = request.createOffer()
offer1.price = 20.u256
offer2.price = 10.u256
offer2.expiry = getTime().toUnix().u256 + expiryMargin - 1
discard await market.offerStorage(offer1)
discard await market.offerStorage(offer2)
clock.set(request.expiry.truncate(int64))
await purchase.wait()
check market.selected[0] == offer1.id