[purchasing] Select cheapest offer
This commit is contained in:
parent
03140fdf49
commit
fe23cb89d7
|
@ -8,6 +8,32 @@ export offers
|
|||
|
||||
type
|
||||
Market* = ref object of RootObj
|
||||
Subscription* = ref object of RootObj
|
||||
OnRequest* = proc(request: StorageRequest) {.gcsafe.}
|
||||
OnOffer* = proc(offer: StorageOffer) {.gcsafe.}
|
||||
|
||||
method requestStorage*(market: Market, request: StorageRequest) {.base, async.} =
|
||||
raiseAssert("not implemented")
|
||||
|
||||
method offerStorage*(market: Market, offer: StorageOffer) {.base, async.} =
|
||||
raiseAssert("not implemented")
|
||||
|
||||
method selectOffer*(market: Market, id: array[32, byte]) {.base, async.} =
|
||||
raiseAssert("not implemented")
|
||||
|
||||
method waitUntil*(market: Market, expiry: UInt256) {.base, async.} =
|
||||
raiseAssert("not implemented")
|
||||
|
||||
method subscribeRequests*(market: Market,
|
||||
callback: OnRequest):
|
||||
Future[Subscription] {.base, async.} =
|
||||
raiseAssert("not implemented")
|
||||
|
||||
method subscribeOffers*(market: Market,
|
||||
requestId: array[32, byte],
|
||||
callback: OnOffer):
|
||||
Future[Subscription] {.base, async.} =
|
||||
raiseAssert("not implemented")
|
||||
|
||||
method unsubscribe*(subscription: Subscription) {.base, async.} =
|
||||
raiseAssert("not implemented")
|
||||
|
|
|
@ -47,8 +47,27 @@ proc purchase*(purchasing: Purchasing, request: StorageRequest): Purchase =
|
|||
purchase.start()
|
||||
purchase
|
||||
|
||||
proc selectOffer(purchase: Purchase) {.async.} =
|
||||
var cheapest: ?StorageOffer
|
||||
for offer in purchase.offers:
|
||||
if current =? cheapest:
|
||||
if current.price > offer.price:
|
||||
cheapest = some offer
|
||||
else:
|
||||
cheapest = some offer
|
||||
if cheapest =? cheapest:
|
||||
await purchase.market.selectOffer(cheapest.id)
|
||||
|
||||
proc run(purchase: Purchase) {.async.} =
|
||||
await purchase.market.requestStorage(purchase.request)
|
||||
proc onOffer(offer: StorageOffer) =
|
||||
purchase.offers.add(offer)
|
||||
let market = purchase.market
|
||||
let request = purchase.request
|
||||
let subscription = await market.subscribeOffers(request.id, onOffer)
|
||||
await market.requestStorage(request)
|
||||
await market.waitUntil(request.expiry)
|
||||
await purchase.selectOffer()
|
||||
await subscription.unsubscribe()
|
||||
|
||||
proc start(purchase: Purchase) =
|
||||
purchase.future = purchase.run()
|
||||
|
|
|
@ -1,8 +1,84 @@
|
|||
import std/sequtils
|
||||
import std/heapqueue
|
||||
import pkg/dagger/market
|
||||
|
||||
type
|
||||
MockMarket* = ref object of Market
|
||||
requested*: seq[StorageRequest]
|
||||
offered*: seq[StorageOffer]
|
||||
selected*: seq[array[32, byte]]
|
||||
subscriptions: Subscriptions
|
||||
time: UInt256
|
||||
waiting: HeapQueue[Expiry]
|
||||
Subscriptions = object
|
||||
onRequest: seq[RequestSubscription]
|
||||
onOffer: seq[OfferSubscription]
|
||||
RequestSubscription* = ref object of Subscription
|
||||
market: MockMarket
|
||||
callback: OnRequest
|
||||
OfferSubscription* = ref object of Subscription
|
||||
market: MockMarket
|
||||
requestId: array[32, byte]
|
||||
callback: OnOffer
|
||||
Expiry = object
|
||||
future: Future[void]
|
||||
expiry: UInt256
|
||||
|
||||
method requestStorage*(market: MockMarket, request: StorageRequest) {.async.} =
|
||||
market.requested.add(request)
|
||||
for subscription in market.subscriptions.onRequest:
|
||||
subscription.callback(request)
|
||||
|
||||
method offerStorage*(market: MockMarket, offer: StorageOffer) {.async.} =
|
||||
market.offered.add(offer)
|
||||
for subscription in market.subscriptions.onOffer:
|
||||
if subscription.requestId == offer.requestId:
|
||||
subscription.callback(offer)
|
||||
|
||||
method selectOffer*(market: MockMarket, id: array[32, byte]) {.async.} =
|
||||
market.selected.add(id)
|
||||
|
||||
method subscribeRequests*(market: MockMarket,
|
||||
callback: OnRequest):
|
||||
Future[Subscription] {.async.} =
|
||||
let subscription = RequestSubscription(
|
||||
market: market,
|
||||
callback: callback
|
||||
)
|
||||
market.subscriptions.onRequest.add(subscription)
|
||||
return subscription
|
||||
|
||||
method subscribeOffers*(market: MockMarket,
|
||||
requestId: array[32, byte],
|
||||
callback: OnOffer):
|
||||
Future[Subscription] {.async.} =
|
||||
let subscription = OfferSubscription(
|
||||
market: market,
|
||||
requestId: requestId,
|
||||
callback: callback
|
||||
)
|
||||
market.subscriptions.onOffer.add(subscription)
|
||||
return subscription
|
||||
|
||||
method unsubscribe*(subscription: RequestSubscription) {.async.} =
|
||||
subscription.market.subscriptions.onRequest.keepItIf(it != subscription)
|
||||
|
||||
method unsubscribe*(subscription: OfferSubscription) {.async.} =
|
||||
subscription.market.subscriptions.onOffer.keepItIf(it != subscription)
|
||||
|
||||
func `<`(a, b: Expiry): bool =
|
||||
a.expiry < b.expiry
|
||||
|
||||
method waitUntil*(market: MockMarket, expiry: UInt256): Future[void] =
|
||||
let future = Future[void]()
|
||||
if expiry > market.time:
|
||||
market.waiting.push(Expiry(future: future, expiry: expiry))
|
||||
else:
|
||||
future.complete()
|
||||
future
|
||||
|
||||
proc advanceTimeTo*(market: MockMarket, time: UInt256) =
|
||||
doAssert(time >= market.time)
|
||||
market.time = time
|
||||
while market.waiting.len > 0 and market.waiting[0].expiry <= time:
|
||||
market.waiting.pop().future.complete()
|
||||
|
|
|
@ -21,8 +21,13 @@ suite "Purchasing":
|
|||
contentHash: array[32, byte].example
|
||||
)
|
||||
|
||||
proc purchaseAndWait(request: StorageRequest) {.async.} =
|
||||
let purchase = purchasing.purchase(request)
|
||||
market.advanceTimeTo(market.requested[^1].expiry)
|
||||
await purchase.wait()
|
||||
|
||||
test "submits a storage request when asked":
|
||||
await purchasing.purchase(request).wait()
|
||||
await purchaseAndWait(request)
|
||||
let submitted = market.requested[0]
|
||||
check submitted.duration == request.duration
|
||||
check submitted.size == request.size
|
||||
|
@ -34,12 +39,12 @@ suite "Purchasing":
|
|||
|
||||
test "can change default value for proof probability":
|
||||
purchasing.proofProbability = 42.u256
|
||||
await purchasing.purchase(request).wait()
|
||||
await purchaseAndWait(request)
|
||||
check market.requested[0].proofProbability == 42.u256
|
||||
|
||||
test "can override proof probability per request":
|
||||
request.proofProbability = 42.u256
|
||||
await purchasing.purchase(request).wait()
|
||||
await purchaseAndWait(request)
|
||||
check market.requested[0].proofProbability == 42.u256
|
||||
|
||||
test "has a default value for request expiration interval":
|
||||
|
@ -48,16 +53,27 @@ suite "Purchasing":
|
|||
test "can change default value for request expiration interval":
|
||||
purchasing.requestExpiryInterval = 42.u256
|
||||
let start = getTime().toUnix()
|
||||
await purchasing.purchase(request).wait()
|
||||
await purchaseAndWait(request)
|
||||
check market.requested[0].expiry == (start + 42).u256
|
||||
|
||||
test "can override expiry time per request":
|
||||
let expiry = (getTime().toUnix() + 42).u256
|
||||
request.expiry = expiry
|
||||
await purchasing.purchase(request).wait()
|
||||
await purchaseAndWait(request)
|
||||
check market.requested[0].expiry == expiry
|
||||
|
||||
test "includes a random nonce in every storage request":
|
||||
await purchasing.purchase(request).wait()
|
||||
await purchasing.purchase(request).wait()
|
||||
await purchaseAndWait(request)
|
||||
await purchaseAndWait(request)
|
||||
check market.requested[0].nonce != market.requested[1].nonce
|
||||
|
||||
test "selects the cheapest offer":
|
||||
let purchase = purchasing.purchase(request)
|
||||
let request = market.requested[0]
|
||||
let offer1 = StorageOffer(requestId: request.id, price: 20.u256)
|
||||
let offer2 = StorageOffer(requestId: request.id, price: 10.u256)
|
||||
await market.offerStorage(offer1)
|
||||
await market.offerStorage(offer2)
|
||||
market.advanceTimeTo(request.expiry)
|
||||
await purchase.wait()
|
||||
check market.selected[0] == offer2.id
|
||||
|
|
Loading…
Reference in New Issue