[marketplace] sales state machine tests
This commit is contained in:
parent
fb96a9eb17
commit
a3f9e54cc1
|
@ -69,7 +69,7 @@ method getHost(market: OnChainMarket,
|
||||||
else:
|
else:
|
||||||
return none Address
|
return none Address
|
||||||
|
|
||||||
method getSlot(market: OnChainMarket, slotId: SlotId): Future[?Slot] {.async.} =
|
method getSlot*(market: OnChainMarket, slotId: SlotId): Future[?Slot] {.async.} =
|
||||||
try:
|
try:
|
||||||
return some await market.contract.getSlot(slotId)
|
return some await market.contract.getSlot(slotId)
|
||||||
except ProviderError as e:
|
except ProviderError as e:
|
||||||
|
|
|
@ -39,12 +39,10 @@ type
|
||||||
Cancelled
|
Cancelled
|
||||||
Finished
|
Finished
|
||||||
Failed
|
Failed
|
||||||
Slot* = object
|
Slot* = object of RootObj
|
||||||
host*: Address
|
host*: Address
|
||||||
hostPaid*: bool
|
hostPaid*: bool
|
||||||
requestId*: RequestId
|
requestId*: RequestId
|
||||||
slotIndex*: UInt256
|
|
||||||
proof*: seq[byte]
|
|
||||||
|
|
||||||
proc `==`*(x, y: Nonce): bool {.borrow.}
|
proc `==`*(x, y: Nonce): bool {.borrow.}
|
||||||
proc `==`*(x, y: RequestId): bool {.borrow.}
|
proc `==`*(x, y: RequestId): bool {.borrow.}
|
||||||
|
@ -117,6 +115,9 @@ func solidityType*(_: type StorageAsk): string =
|
||||||
func solidityType*(_: type StorageRequest): string =
|
func solidityType*(_: type StorageRequest): string =
|
||||||
solidityType(StorageRequest.fieldTypes)
|
solidityType(StorageRequest.fieldTypes)
|
||||||
|
|
||||||
|
func solidityType*(_: type Slot): string =
|
||||||
|
solidityType(Slot.fieldTypes)
|
||||||
|
|
||||||
func solidityType*[T: RequestId | SlotId | Nonce](_: type T): string =
|
func solidityType*[T: RequestId | SlotId | Nonce](_: type T): string =
|
||||||
solidityType(array[32, byte])
|
solidityType(array[32, byte])
|
||||||
|
|
||||||
|
|
|
@ -111,7 +111,6 @@ method exit(state: AsyncState) =
|
||||||
proc switchAsync*(machine: StateMachineAsync, newState: AsyncState) {.async.} =
|
proc switchAsync*(machine: StateMachineAsync, newState: AsyncState) {.async.} =
|
||||||
if state =? (machine.state as AsyncState):
|
if state =? (machine.state as AsyncState):
|
||||||
trace "Switching sales state", `from`=state, to=newState
|
trace "Switching sales state", `from`=state, to=newState
|
||||||
debugEcho "switching from ", state, " to ", newState
|
|
||||||
if activeTransition =? state.activeTransition and
|
if activeTransition =? state.activeTransition and
|
||||||
not activeTransition.completed:
|
not activeTransition.completed:
|
||||||
await activeTransition.cancelAndWait()
|
await activeTransition.cancelAndWait()
|
||||||
|
@ -121,7 +120,6 @@ proc switchAsync*(machine: StateMachineAsync, newState: AsyncState) {.async.} =
|
||||||
state.context = none StateMachine
|
state.context = none StateMachine
|
||||||
else:
|
else:
|
||||||
trace "Switching sales state", `from`="no state", to=newState
|
trace "Switching sales state", `from`="no state", to=newState
|
||||||
debugEcho "switching from no state to ", newState
|
|
||||||
|
|
||||||
machine.state = some State(newState)
|
machine.state = some State(newState)
|
||||||
newState.context = some StateMachine(machine)
|
newState.context = some StateMachine(machine)
|
||||||
|
|
|
@ -2,6 +2,7 @@ import std/sequtils
|
||||||
import std/tables
|
import std/tables
|
||||||
import std/hashes
|
import std/hashes
|
||||||
import pkg/codex/market
|
import pkg/codex/market
|
||||||
|
import pkg/codex/contracts/requests
|
||||||
|
|
||||||
export market
|
export market
|
||||||
export tables
|
export tables
|
||||||
|
@ -14,7 +15,7 @@ type
|
||||||
requestEnds*: Table[RequestId, SecondsSince1970]
|
requestEnds*: Table[RequestId, SecondsSince1970]
|
||||||
state*: Table[RequestId, RequestState]
|
state*: Table[RequestId, RequestState]
|
||||||
fulfilled*: seq[Fulfillment]
|
fulfilled*: seq[Fulfillment]
|
||||||
filled*: seq[Slot]
|
filled*: seq[MockSlot]
|
||||||
withdrawn*: seq[RequestId]
|
withdrawn*: seq[RequestId]
|
||||||
signer: Address
|
signer: Address
|
||||||
subscriptions: Subscriptions
|
subscriptions: Subscriptions
|
||||||
|
@ -22,6 +23,9 @@ type
|
||||||
requestId*: RequestId
|
requestId*: RequestId
|
||||||
proof*: seq[byte]
|
proof*: seq[byte]
|
||||||
host*: Address
|
host*: Address
|
||||||
|
MockSlot* = object of Slot
|
||||||
|
slotIndex*: UInt256
|
||||||
|
proof*: seq[byte]
|
||||||
Subscriptions = object
|
Subscriptions = object
|
||||||
onRequest: seq[RequestSubscription]
|
onRequest: seq[RequestSubscription]
|
||||||
onFulfillment: seq[FulfillmentSubscription]
|
onFulfillment: seq[FulfillmentSubscription]
|
||||||
|
@ -83,6 +87,14 @@ method getRequest(market: MockMarket,
|
||||||
return some request
|
return some request
|
||||||
return none StorageRequest
|
return none StorageRequest
|
||||||
|
|
||||||
|
method getSlot*(market: MockMarket,
|
||||||
|
slotId: SlotId): Future[?Slot] {.async.} =
|
||||||
|
for slot in market.filled:
|
||||||
|
if slotId(slot.requestId, slot.slotIndex) == slotId:
|
||||||
|
return some Slot(host: slot.host,
|
||||||
|
requestId: slot.requestId)
|
||||||
|
return none Slot
|
||||||
|
|
||||||
method getState*(market: MockMarket,
|
method getState*(market: MockMarket,
|
||||||
requestId: RequestId): Future[?RequestState] {.async.} =
|
requestId: RequestId): Future[?RequestState] {.async.} =
|
||||||
return market.state.?[requestId]
|
return market.state.?[requestId]
|
||||||
|
@ -132,7 +144,7 @@ proc fillSlot*(market: MockMarket,
|
||||||
slotIndex: UInt256,
|
slotIndex: UInt256,
|
||||||
proof: seq[byte],
|
proof: seq[byte],
|
||||||
host: Address) =
|
host: Address) =
|
||||||
let slot = Slot(
|
let slot = MockSlot(
|
||||||
requestId: requestId,
|
requestId: requestId,
|
||||||
slotIndex: slotIndex,
|
slotIndex: slotIndex,
|
||||||
proof: proof,
|
proof: proof,
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
import std/sets
|
import std/sets
|
||||||
|
import std/sequtils
|
||||||
|
import std/sugar
|
||||||
import std/times
|
import std/times
|
||||||
import pkg/asynctest
|
import pkg/asynctest
|
||||||
import pkg/chronos
|
import pkg/chronos
|
||||||
import pkg/codex/contracts/requests
|
# import pkg/codex/contracts/requests
|
||||||
import pkg/codex/sales
|
import pkg/codex/sales
|
||||||
|
import pkg/codex/sales/states/[downloading, cancelled, errored, filled, filling,
|
||||||
|
failed, proving, finished, unknown]
|
||||||
import ./helpers/mockmarket
|
import ./helpers/mockmarket
|
||||||
import ./helpers/mockclock
|
import ./helpers/mockclock
|
||||||
import ./examples
|
import ./examples
|
||||||
|
@ -214,3 +218,301 @@ suite "Sales":
|
||||||
discard await market.requestStorage(request)
|
discard await market.requestStorage(request)
|
||||||
check proving.slots.len == 1
|
check proving.slots.len == 1
|
||||||
check proving.slots.contains(request.slotId(soldSlotIndex))
|
check proving.slots.contains(request.slotId(soldSlotIndex))
|
||||||
|
|
||||||
|
suite "Sales state machine":
|
||||||
|
|
||||||
|
let availability = Availability.init(
|
||||||
|
size=100.u256,
|
||||||
|
duration=60.u256,
|
||||||
|
minPrice=600.u256
|
||||||
|
)
|
||||||
|
var request = StorageRequest(
|
||||||
|
ask: StorageAsk(
|
||||||
|
slots: 4,
|
||||||
|
slotSize: 100.u256,
|
||||||
|
duration: 60.u256,
|
||||||
|
reward: 10.u256,
|
||||||
|
),
|
||||||
|
content: StorageContent(
|
||||||
|
cid: "some cid"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
let proof = exampleProof()
|
||||||
|
|
||||||
|
var sales: Sales
|
||||||
|
var market: MockMarket
|
||||||
|
var clock: MockClock
|
||||||
|
var proving: Proving
|
||||||
|
|
||||||
|
setup:
|
||||||
|
market = MockMarket.new()
|
||||||
|
clock = MockClock.new()
|
||||||
|
proving = Proving.new()
|
||||||
|
sales = Sales.new(market, clock, proving)
|
||||||
|
sales.onStore = proc(request: StorageRequest,
|
||||||
|
slot: UInt256,
|
||||||
|
availability: ?Availability) {.async.} =
|
||||||
|
discard
|
||||||
|
sales.onProve = proc(request: StorageRequest,
|
||||||
|
slot: UInt256): Future[seq[byte]] {.async.} =
|
||||||
|
return proof
|
||||||
|
await sales.start()
|
||||||
|
request.expiry = (clock.now() + 42).u256
|
||||||
|
|
||||||
|
teardown:
|
||||||
|
await sales.stop()
|
||||||
|
|
||||||
|
proc newSalesAgent(slotIdx: UInt256 = 0.u256): SalesAgent =
|
||||||
|
let agent = sales.newSalesAgent(request.id,
|
||||||
|
some availability,
|
||||||
|
some request)
|
||||||
|
agent.slotIndex = some slotIdx
|
||||||
|
return agent
|
||||||
|
|
||||||
|
proc fillSlot(slotIdx: UInt256 = 0.u256) {.async.} =
|
||||||
|
let address = await market.getSigner()
|
||||||
|
let slot = MockSlot(requestId: request.id,
|
||||||
|
slotIndex: slotIdx,
|
||||||
|
proof: proof,
|
||||||
|
host: address)
|
||||||
|
market.filled.add slot
|
||||||
|
|
||||||
|
test "moves to SaleErrored when SaleFilled errors":
|
||||||
|
let agent = newSalesAgent()
|
||||||
|
market.state[request.id] = RequestState.New
|
||||||
|
await agent.switchAsync(SaleUnknown())
|
||||||
|
let state = (agent.state as SaleErrored)
|
||||||
|
check state.isSome
|
||||||
|
check (!state).error.msg == "Sale host mismatch"
|
||||||
|
|
||||||
|
test "moves to SaleFinished when request state is New":
|
||||||
|
let agent = newSalesAgent()
|
||||||
|
await fillSlot()
|
||||||
|
market.state[request.id] = RequestState.New
|
||||||
|
await agent.switchAsync(SaleUnknown())
|
||||||
|
check (agent.state as SaleFinished).isSome
|
||||||
|
|
||||||
|
test "moves to SaleFinished when request state is Started":
|
||||||
|
let agent = newSalesAgent()
|
||||||
|
await fillSlot()
|
||||||
|
market.state[request.id] = RequestState.Started
|
||||||
|
agent.switch(SaleUnknown())
|
||||||
|
check (agent.state as SaleFinished).isSome
|
||||||
|
|
||||||
|
test "moves to SaleFinished when request state is Finished":
|
||||||
|
let agent = newSalesAgent()
|
||||||
|
market.state[request.id] = RequestState.Finished
|
||||||
|
agent.switch(SaleUnknown())
|
||||||
|
check (agent.state as SaleFinished).isSome
|
||||||
|
|
||||||
|
test "moves to SaleErrored when request state is Cancelled":
|
||||||
|
let agent = newSalesAgent()
|
||||||
|
market.state[request.id] = RequestState.Cancelled
|
||||||
|
agent.switch(SaleUnknown())
|
||||||
|
let state = (agent.state as SaleErrored)
|
||||||
|
check state.isSome
|
||||||
|
check (!state).error.msg == "Sale cancelled due to timeout"
|
||||||
|
|
||||||
|
test "moves to SaleErrored when request state is Failed":
|
||||||
|
let agent = newSalesAgent()
|
||||||
|
market.state[request.id] = RequestState.Failed
|
||||||
|
agent.switch(SaleUnknown())
|
||||||
|
let state = (agent.state as SaleErrored)
|
||||||
|
check state.isSome
|
||||||
|
check (!state).error.msg == "Sale failed"
|
||||||
|
|
||||||
|
test "moves to SaleErrored when Downloading and request expires":
|
||||||
|
sales.onStore = proc(request: StorageRequest,
|
||||||
|
slot: UInt256,
|
||||||
|
availability: ?Availability) {.async.} =
|
||||||
|
await sleepAsync(chronos.minutes(1)) # "far" in the future
|
||||||
|
request.expiry = (getTime() + initDuration(seconds=2)).toUnix.u256
|
||||||
|
let agent = newSalesAgent()
|
||||||
|
await agent.init(request.ask.slots)
|
||||||
|
market.requested.add request
|
||||||
|
market.state[request.id] = RequestState.New
|
||||||
|
await agent.switchAsync(SaleDownloading())
|
||||||
|
clock.set(request.expiry.truncate(int64))
|
||||||
|
await sleepAsync chronos.seconds(2)
|
||||||
|
|
||||||
|
let state = (agent.state as SaleErrored)
|
||||||
|
check state.isSome
|
||||||
|
check (!state).error.msg == "Sale cancelled due to timeout"
|
||||||
|
|
||||||
|
test "moves to SaleErrored when Downloading and request fails":
|
||||||
|
sales.onStore = proc(request: StorageRequest,
|
||||||
|
slot: UInt256,
|
||||||
|
availability: ?Availability) {.async.} =
|
||||||
|
await sleepAsync(chronos.minutes(1)) # "far" in the future
|
||||||
|
let agent = newSalesAgent()
|
||||||
|
await agent.init(request.ask.slots)
|
||||||
|
market.requested.add request
|
||||||
|
market.state[request.id] = RequestState.New
|
||||||
|
await agent.switchAsync(SaleDownloading())
|
||||||
|
market.emitRequestFailed(request.id)
|
||||||
|
await sleepAsync chronos.seconds(2)
|
||||||
|
|
||||||
|
let state = (agent.state as SaleErrored)
|
||||||
|
check state.isSome
|
||||||
|
check (!state).error.msg == "Sale failed"
|
||||||
|
|
||||||
|
test "moves to SaleErrored when Filling and request expires":
|
||||||
|
request.expiry = (getTime() + initDuration(seconds=2)).toUnix.u256
|
||||||
|
let agent = newSalesAgent()
|
||||||
|
await agent.init(request.ask.slots)
|
||||||
|
market.requested.add request
|
||||||
|
market.state[request.id] = RequestState.New
|
||||||
|
await agent.switchAsync(SaleFilling())
|
||||||
|
clock.set(request.expiry.truncate(int64))
|
||||||
|
await sleepAsync chronos.seconds(2)
|
||||||
|
|
||||||
|
let state = (agent.state as SaleErrored)
|
||||||
|
check state.isSome
|
||||||
|
check (!state).error.msg == "Sale cancelled due to timeout"
|
||||||
|
|
||||||
|
test "moves to SaleErrored when Filling and request fails":
|
||||||
|
let agent = newSalesAgent()
|
||||||
|
await agent.init(request.ask.slots)
|
||||||
|
market.requested.add request
|
||||||
|
market.state[request.id] = RequestState.New
|
||||||
|
await agent.switchAsync(SaleFilling())
|
||||||
|
market.emitRequestFailed(request.id)
|
||||||
|
await sleepAsync chronos.seconds(2)
|
||||||
|
|
||||||
|
let state = (agent.state as SaleErrored)
|
||||||
|
check state.isSome
|
||||||
|
check (!state).error.msg == "Sale failed"
|
||||||
|
|
||||||
|
test "moves to SaleErrored when Finished and request expires":
|
||||||
|
request.expiry = (getTime() + initDuration(seconds=2)).toUnix.u256
|
||||||
|
let agent = newSalesAgent()
|
||||||
|
await agent.init(request.ask.slots)
|
||||||
|
market.requested.add request
|
||||||
|
market.state[request.id] = RequestState.Finished
|
||||||
|
await agent.switchAsync(SaleFinished())
|
||||||
|
clock.set(request.expiry.truncate(int64))
|
||||||
|
await sleepAsync chronos.seconds(2)
|
||||||
|
|
||||||
|
let state = (agent.state as SaleErrored)
|
||||||
|
check state.isSome
|
||||||
|
check (!state).error.msg == "Sale cancelled due to timeout"
|
||||||
|
|
||||||
|
test "moves to SaleErrored when Finished and request fails":
|
||||||
|
let agent = newSalesAgent()
|
||||||
|
await agent.init(request.ask.slots)
|
||||||
|
market.requested.add request
|
||||||
|
market.state[request.id] = RequestState.Finished
|
||||||
|
await agent.switchAsync(SaleFinished())
|
||||||
|
market.emitRequestFailed(request.id)
|
||||||
|
await sleepAsync chronos.seconds(2)
|
||||||
|
|
||||||
|
let state = (agent.state as SaleErrored)
|
||||||
|
check state.isSome
|
||||||
|
check (!state).error.msg == "Sale failed"
|
||||||
|
|
||||||
|
test "moves to SaleErrored when Proving and request expires":
|
||||||
|
sales.onProve = proc(request: StorageRequest,
|
||||||
|
slot: UInt256): Future[seq[byte]] {.async.} =
|
||||||
|
await sleepAsync(chronos.minutes(1)) # "far" in the future
|
||||||
|
return @[]
|
||||||
|
request.expiry = (getTime() + initDuration(seconds=2)).toUnix.u256
|
||||||
|
let agent = newSalesAgent()
|
||||||
|
await agent.init(request.ask.slots)
|
||||||
|
market.requested.add request
|
||||||
|
market.state[request.id] = RequestState.New
|
||||||
|
await agent.switchAsync(SaleProving())
|
||||||
|
clock.set(request.expiry.truncate(int64))
|
||||||
|
await sleepAsync chronos.seconds(2)
|
||||||
|
|
||||||
|
let state = (agent.state as SaleErrored)
|
||||||
|
check state.isSome
|
||||||
|
check (!state).error.msg == "Sale cancelled due to timeout"
|
||||||
|
|
||||||
|
test "moves to SaleErrored when Proving and request fails":
|
||||||
|
sales.onProve = proc(request: StorageRequest,
|
||||||
|
slot: UInt256): Future[seq[byte]] {.async.} =
|
||||||
|
await sleepAsync(chronos.minutes(1)) # "far" in the future
|
||||||
|
return @[]
|
||||||
|
let agent = newSalesAgent()
|
||||||
|
await agent.init(request.ask.slots)
|
||||||
|
market.requested.add request
|
||||||
|
market.state[request.id] = RequestState.New
|
||||||
|
await agent.switchAsync(SaleProving())
|
||||||
|
market.emitRequestFailed(request.id)
|
||||||
|
await sleepAsync chronos.seconds(2)
|
||||||
|
|
||||||
|
let state = (agent.state as SaleErrored)
|
||||||
|
check state.isSome
|
||||||
|
check (!state).error.msg == "Sale failed"
|
||||||
|
|
||||||
|
test "moves from SaleDownloading to SaleFinished, calling necessary callbacks":
|
||||||
|
var onProveCalled, onStoreCalled, onClearCalled, onSaleCalled: bool
|
||||||
|
sales.onProve = proc(request: StorageRequest,
|
||||||
|
slot: UInt256): Future[seq[byte]] {.async.} =
|
||||||
|
onProveCalled = true
|
||||||
|
return @[]
|
||||||
|
sales.onStore = proc(request: StorageRequest,
|
||||||
|
slot: UInt256,
|
||||||
|
availability: ?Availability) {.async.} =
|
||||||
|
onStoreCalled = true
|
||||||
|
sales.onClear = proc(availability: ?Availability,
|
||||||
|
request: StorageRequest,
|
||||||
|
slotIndex: UInt256) =
|
||||||
|
onClearCalled = true
|
||||||
|
sales.onSale = proc(availability: ?Availability,
|
||||||
|
request: StorageRequest,
|
||||||
|
slotIndex: UInt256) =
|
||||||
|
onSaleCalled = true
|
||||||
|
|
||||||
|
let agent = newSalesAgent()
|
||||||
|
await agent.init(request.ask.slots)
|
||||||
|
market.requested.add request
|
||||||
|
market.state[request.id] = RequestState.New
|
||||||
|
await fillSlot(!agent.slotIndex)
|
||||||
|
await agent.switchAsync(SaleDownloading())
|
||||||
|
market.emitRequestFulfilled(request.id)
|
||||||
|
await sleepAsync chronos.seconds(2)
|
||||||
|
|
||||||
|
let state = (agent.state as SaleFinished)
|
||||||
|
check state.isSome
|
||||||
|
check onProveCalled
|
||||||
|
check onStoreCalled
|
||||||
|
check not onClearCalled
|
||||||
|
check onSaleCalled
|
||||||
|
|
||||||
|
test "loads active slots from market":
|
||||||
|
let me = await market.getSigner()
|
||||||
|
|
||||||
|
request.ask.slots = 2
|
||||||
|
market.requested = @[request]
|
||||||
|
market.state[request.id] = RequestState.New
|
||||||
|
|
||||||
|
let slot0 = MockSlot(requestId: request.id,
|
||||||
|
slotIndex: 0.u256,
|
||||||
|
proof: proof,
|
||||||
|
host: me)
|
||||||
|
await fillSlot(slot0.slotIndex)
|
||||||
|
|
||||||
|
let slot1 = MockSlot(requestId: request.id,
|
||||||
|
slotIndex: 1.u256,
|
||||||
|
proof: proof,
|
||||||
|
host: me)
|
||||||
|
await fillSlot(slot1.slotIndex)
|
||||||
|
market.activeSlots[me] = @[request.slotId(0.u256), request.slotId(1.u256)]
|
||||||
|
|
||||||
|
await sales.load()
|
||||||
|
let expected = SalesAgent(sales: sales,
|
||||||
|
requestId: request.id,
|
||||||
|
availability: none Availability,
|
||||||
|
request: some request)
|
||||||
|
# because sales.load() calls agent.init, we won't know the slotIndex
|
||||||
|
# randomly selected for the agent, and we also won't know the value of
|
||||||
|
# `failed`/`fulfilled`/`cancelled` futures, so we need to compare
|
||||||
|
# the properties we know
|
||||||
|
proc `==` (agent0, agent1: SalesAgent): bool =
|
||||||
|
return agent0.sales == agent1.sales and
|
||||||
|
agent0.requestId == agent1.requestId and
|
||||||
|
agent0.availability == agent1.availability and
|
||||||
|
agent0.request == agent1.request
|
||||||
|
|
||||||
|
check sales.agents.all(agent => agent == expected)
|
||||||
|
|
|
@ -80,7 +80,7 @@ ethersuite "On-Chain Market":
|
||||||
test "supports request subscriptions":
|
test "supports request subscriptions":
|
||||||
var receivedIds: seq[RequestId]
|
var receivedIds: seq[RequestId]
|
||||||
var receivedAsks: seq[StorageAsk]
|
var receivedAsks: seq[StorageAsk]
|
||||||
proc onRequest(id: RequestId, ask: StorageAsk) =
|
proc onRequest(id: RequestId, ask: StorageAsk) {.async.} =
|
||||||
receivedIds.add(id)
|
receivedIds.add(id)
|
||||||
receivedAsks.add(ask)
|
receivedAsks.add(ask)
|
||||||
let subscription = await market.subscribeRequests(onRequest)
|
let subscription = await market.subscribeRequests(onRequest)
|
||||||
|
@ -107,7 +107,7 @@ ethersuite "On-Chain Market":
|
||||||
discard await market.requestStorage(request)
|
discard await market.requestStorage(request)
|
||||||
var receivedIds: seq[RequestId]
|
var receivedIds: seq[RequestId]
|
||||||
var receivedSlotIndices: seq[UInt256]
|
var receivedSlotIndices: seq[UInt256]
|
||||||
proc onSlotFilled(id: RequestId, slotIndex: UInt256) =
|
proc onSlotFilled(id: RequestId, slotIndex: UInt256) {.async.} =
|
||||||
receivedIds.add(id)
|
receivedIds.add(id)
|
||||||
receivedSlotIndices.add(slotIndex)
|
receivedSlotIndices.add(slotIndex)
|
||||||
let subscription = await market.subscribeSlotFilled(request.id, slotIndex, onSlotFilled)
|
let subscription = await market.subscribeSlotFilled(request.id, slotIndex, onSlotFilled)
|
||||||
|
@ -121,7 +121,7 @@ ethersuite "On-Chain Market":
|
||||||
await token.approve(storage.address, request.price)
|
await token.approve(storage.address, request.price)
|
||||||
discard await market.requestStorage(request)
|
discard await market.requestStorage(request)
|
||||||
var receivedSlotIndices: seq[UInt256]
|
var receivedSlotIndices: seq[UInt256]
|
||||||
proc onSlotFilled(requestId: RequestId, slotIndex: UInt256) =
|
proc onSlotFilled(requestId: RequestId, slotIndex: UInt256) {.async.} =
|
||||||
receivedSlotIndices.add(slotIndex)
|
receivedSlotIndices.add(slotIndex)
|
||||||
let subscription = await market.subscribeSlotFilled(request.id, slotIndex, onSlotFilled)
|
let subscription = await market.subscribeSlotFilled(request.id, slotIndex, onSlotFilled)
|
||||||
await market.fillSlot(request.id, slotIndex - 1, proof)
|
await market.fillSlot(request.id, slotIndex - 1, proof)
|
||||||
|
@ -134,7 +134,7 @@ ethersuite "On-Chain Market":
|
||||||
await token.approve(storage.address, request.price)
|
await token.approve(storage.address, request.price)
|
||||||
discard await market.requestStorage(request)
|
discard await market.requestStorage(request)
|
||||||
var receivedIds: seq[RequestId]
|
var receivedIds: seq[RequestId]
|
||||||
proc onFulfillment(id: RequestId) =
|
proc onFulfillment(id: RequestId) {.async.} =
|
||||||
receivedIds.add(id)
|
receivedIds.add(id)
|
||||||
let subscription = await market.subscribeFulfillment(request.id, onFulfillment)
|
let subscription = await market.subscribeFulfillment(request.id, onFulfillment)
|
||||||
for slotIndex in 0..<request.ask.slots:
|
for slotIndex in 0..<request.ask.slots:
|
||||||
|
@ -152,7 +152,7 @@ ethersuite "On-Chain Market":
|
||||||
discard await market.requestStorage(otherRequest)
|
discard await market.requestStorage(otherRequest)
|
||||||
|
|
||||||
var receivedIds: seq[RequestId]
|
var receivedIds: seq[RequestId]
|
||||||
proc onFulfillment(id: RequestId) =
|
proc onFulfillment(id: RequestId) {.async.} =
|
||||||
receivedIds.add(id)
|
receivedIds.add(id)
|
||||||
|
|
||||||
let subscription = await market.subscribeFulfillment(request.id, onFulfillment)
|
let subscription = await market.subscribeFulfillment(request.id, onFulfillment)
|
||||||
|
@ -171,7 +171,7 @@ ethersuite "On-Chain Market":
|
||||||
discard await market.requestStorage(request)
|
discard await market.requestStorage(request)
|
||||||
|
|
||||||
var receivedIds: seq[RequestId]
|
var receivedIds: seq[RequestId]
|
||||||
proc onRequestCancelled(id: RequestId) =
|
proc onRequestCancelled(id: RequestId) {.async.} =
|
||||||
receivedIds.add(id)
|
receivedIds.add(id)
|
||||||
let subscription = await market.subscribeRequestCancelled(request.id, onRequestCancelled)
|
let subscription = await market.subscribeRequestCancelled(request.id, onRequestCancelled)
|
||||||
|
|
||||||
|
@ -185,7 +185,7 @@ ethersuite "On-Chain Market":
|
||||||
discard await market.requestStorage(request)
|
discard await market.requestStorage(request)
|
||||||
|
|
||||||
var receivedIds: seq[RequestId]
|
var receivedIds: seq[RequestId]
|
||||||
proc onRequestFailed(id: RequestId) =
|
proc onRequestFailed(id: RequestId) {.async.} =
|
||||||
receivedIds.add(id)
|
receivedIds.add(id)
|
||||||
let subscription = await market.subscribeRequestFailed(request.id, onRequestFailed)
|
let subscription = await market.subscribeRequestFailed(request.id, onRequestFailed)
|
||||||
|
|
||||||
|
@ -213,7 +213,7 @@ ethersuite "On-Chain Market":
|
||||||
discard await market.requestStorage(otherRequest)
|
discard await market.requestStorage(otherRequest)
|
||||||
|
|
||||||
var receivedIds: seq[RequestId]
|
var receivedIds: seq[RequestId]
|
||||||
proc onRequestCancelled(requestId: RequestId) =
|
proc onRequestCancelled(requestId: RequestId) {.async.} =
|
||||||
receivedIds.add(requestId)
|
receivedIds.add(requestId)
|
||||||
|
|
||||||
let subscription = await market.subscribeRequestCancelled(request.id, onRequestCancelled)
|
let subscription = await market.subscribeRequestCancelled(request.id, onRequestCancelled)
|
||||||
|
@ -244,3 +244,27 @@ ethersuite "On-Chain Market":
|
||||||
for slotIndex in 0..<request.ask.slots:
|
for slotIndex in 0..<request.ask.slots:
|
||||||
await market.fillSlot(request.id, slotIndex.u256, proof)
|
await market.fillSlot(request.id, slotIndex.u256, proof)
|
||||||
check (await market.getState(request.id)) == RequestState.Started
|
check (await market.getState(request.id)) == RequestState.Started
|
||||||
|
|
||||||
|
test "can retrieve active slots":
|
||||||
|
await token.approve(storage.address, request.price)
|
||||||
|
discard await market.requestStorage(request)
|
||||||
|
await market.fillSlot(request.id, slotIndex - 1, proof)
|
||||||
|
await market.fillSlot(request.id, slotIndex, proof)
|
||||||
|
let slotId1 = request.slotId(slotIndex - 1)
|
||||||
|
let slotId2 = request.slotId(slotIndex)
|
||||||
|
check (await market.mySlots()) == @[slotId1, slotId2]
|
||||||
|
|
||||||
|
test "returns none when slot is empty":
|
||||||
|
await token.approve(storage.address, request.price)
|
||||||
|
discard await market.requestStorage(request)
|
||||||
|
let slotId = request.slotId(slotIndex)
|
||||||
|
check (await market.getSlot(slotId)) == none Slot
|
||||||
|
|
||||||
|
test "can retrieve slot details":
|
||||||
|
await token.approve(storage.address, request.price)
|
||||||
|
discard await market.requestStorage(request)
|
||||||
|
await market.fillSlot(request.id, slotIndex, proof)
|
||||||
|
let slotId = request.slotId(slotIndex)
|
||||||
|
let expected = Slot(host: request.client,
|
||||||
|
requestId: request.id)
|
||||||
|
check (await market.getSlot(slotId)) == some expected
|
||||||
|
|
Loading…
Reference in New Issue