nim-codex/tests/codex/helpers/mockmarket.nim
Eric Mastro 0c3fbad470 [purchasing] Withdraw funds when request times out
When a request for storage times out (not enough slots filled), the client will initiate a withdraw request to retrieve its funds out of the contract, setting the state of the request to RequestState.Cancelled. The client will also emit a RequestCancelled event for others to listen to (ie hosts will need to listen for this event to withdraw its collateral).

Add unit test that checks for emission of RequestCancelled after request is purchased request expires.

Update dagger-contracts dependency to commit that holds the changes supporting withdrawing of funds.
2022-10-25 15:10:35 +11:00

179 lines
5.9 KiB
Nim

import std/sequtils
import pkg/codex/market
export market
type
MockMarket* = ref object of Market
requested*: seq[StorageRequest]
fulfilled*: seq[Fulfillment]
filled*: seq[Slot]
signer: Address
subscriptions: Subscriptions
Fulfillment* = object
requestId*: RequestId
proof*: seq[byte]
host*: Address
Slot* = object
requestId*: RequestId
slotIndex*: UInt256
proof*: seq[byte]
host*: Address
Subscriptions = object
onRequest: seq[RequestSubscription]
onFulfillment: seq[FulfillmentSubscription]
onSlotFilled: seq[SlotFilledSubscription]
onRequestCancelled: seq[RequestCancelledSubscription]
RequestSubscription* = ref object of Subscription
market: MockMarket
callback: OnRequest
FulfillmentSubscription* = ref object of Subscription
market: MockMarket
requestId: RequestId
callback: OnFulfillment
SlotFilledSubscription* = ref object of Subscription
market: MockMarket
requestId: RequestId
slotIndex: UInt256
callback: OnSlotFilled
RequestCancelledSubscription* = ref object of Subscription
market: MockMarket
requestId: array[32, byte]
callback: OnRequestCancelled
proc new*(_: type MockMarket): MockMarket =
MockMarket(signer: Address.example)
method getSigner*(market: MockMarket): Future[Address] {.async.} =
return market.signer
method requestStorage*(market: MockMarket,
request: StorageRequest):
Future[StorageRequest] {.async.} =
market.requested.add(request)
var subscriptions = market.subscriptions.onRequest
for subscription in subscriptions:
subscription.callback(request.id, request.ask)
return request
method getRequest(market: MockMarket,
id: RequestId): Future[?StorageRequest] {.async.} =
for request in market.requested:
if request.id == id:
return some request
return none StorageRequest
method getHost(market: MockMarket,
requestId: RequestId,
slotIndex: UInt256): Future[?Address] {.async.} =
for slot in market.filled:
if slot.requestId == requestId and slot.slotIndex == slotIndex:
return some slot.host
return none Address
proc emitSlotFilled*(market: MockMarket,
requestId: RequestId,
slotIndex: UInt256) =
var subscriptions = market.subscriptions.onSlotFilled
for subscription in subscriptions:
if subscription.requestId == requestId and
subscription.slotIndex == slotIndex:
subscription.callback(requestId, slotIndex)
proc emitRequestCancelled*(market: MockMarket,
requestId: array[32, byte]) =
var subscriptions = market.subscriptions.onRequestCancelled
for subscription in subscriptions:
if subscription.requestId == requestId:
subscription.callback(requestId)
proc emitRequestFulfilled*(market: MockMarket, requestId: RequestId) =
var subscriptions = market.subscriptions.onFulfillment
for subscription in subscriptions:
if subscription.requestId == requestId:
subscription.callback(requestId)
proc fillSlot*(market: MockMarket,
requestId: RequestId,
slotIndex: UInt256,
proof: seq[byte],
host: Address) =
let slot = Slot(
requestId: requestId,
slotIndex: slotIndex,
proof: proof,
host: host
)
market.filled.add(slot)
market.emitSlotFilled(requestId, slotIndex)
method fillSlot*(market: MockMarket,
requestId: RequestId,
slotIndex: UInt256,
proof: seq[byte]) {.async.} =
market.fillSlot(requestId, slotIndex, proof, market.signer)
method withdrawFunds*(market: MockMarket,
requestId: array[32, byte]) {.async.} =
market.emitRequestCancelled(requestId)
method subscribeRequests*(market: MockMarket,
callback: OnRequest):
Future[Subscription] {.async.} =
let subscription = RequestSubscription(
market: market,
callback: callback
)
market.subscriptions.onRequest.add(subscription)
return subscription
method subscribeFulfillment*(market: MockMarket,
requestId: RequestId,
callback: OnFulfillment):
Future[Subscription] {.async.} =
let subscription = FulfillmentSubscription(
market: market,
requestId: requestId,
callback: callback
)
market.subscriptions.onFulfillment.add(subscription)
return subscription
method subscribeSlotFilled*(market: MockMarket,
requestId: RequestId,
slotIndex: UInt256,
callback: OnSlotFilled):
Future[Subscription] {.async.} =
let subscription = SlotFilledSubscription(
market: market,
requestId: requestId,
slotIndex: slotIndex,
callback: callback
)
market.subscriptions.onSlotFilled.add(subscription)
return subscription
method subscribeRequestCancelled*(market: MockMarket,
requestId: array[32, byte],
callback: OnRequestCancelled):
Future[Subscription] {.async.} =
let subscription = RequestCancelledSubscription(
market: market,
requestId: requestId,
callback: callback
)
market.subscriptions.onRequestCancelled.add(subscription)
return subscription
method unsubscribe*(subscription: RequestSubscription) {.async.} =
subscription.market.subscriptions.onRequest.keepItIf(it != subscription)
method unsubscribe*(subscription: FulfillmentSubscription) {.async.} =
subscription.market.subscriptions.onFulfillment.keepItIf(it != subscription)
method unsubscribe*(subscription: SlotFilledSubscription) {.async.} =
subscription.market.subscriptions.onSlotFilled.keepItIf(it != subscription)
method unsubscribe*(subscription: RequestCancelledSubscription) {.async.} =
subscription.market.subscriptions.onRequestCancelled.keepItIf(it != subscription)