diff --git a/codex/rng.nim b/codex/rng.nim index 19452cd4..c16fef56 100644 --- a/codex/rng.nim +++ b/codex/rng.nim @@ -15,7 +15,7 @@ import pkg/libp2p/crypto/crypto import pkg/bearssl/rand type - RngSampleError = object of CatchableError + RngSampleError* = object of CatchableError Rng* = ref HmacDrbgContext var rng {.threadvar.}: Rng diff --git a/codex/sales.nim b/codex/sales.nim index 01f3da77..9b50b9e5 100644 --- a/codex/sales.nim +++ b/codex/sales.nim @@ -4,7 +4,6 @@ import pkg/upraises import pkg/stint import pkg/chronicles import pkg/datastore -import ./rng import ./market import ./clock import ./proving @@ -13,7 +12,7 @@ import ./contracts/requests import ./sales/salescontext import ./sales/salesagent import ./sales/statemachine -import ./sales/states/downloading +import ./sales/states/preparing import ./sales/states/unknown ## Sales holds a list of available storage that it may sell. @@ -74,10 +73,7 @@ func new*(_: type Sales, reservations: Reservations.new(repo) )) -proc randomSlotIndex(numSlots: uint64): UInt256 = - let rng = Rng.instance - let slotIndex = rng.rand(numSlots - 1) - return slotIndex.u256 + proc handleRequest(sales: Sales, requestId: RequestId, @@ -87,17 +83,15 @@ proc handleRequest(sales: Sales, slots = ask.slots, slotSize = ask.slotSize, duration = ask.duration, reward = ask.reward, maxSlotLoss = ask.maxSlotLoss - # TODO: check if random slot is actually available (not already filled) - let slotIndex = randomSlotIndex(ask.slots) let agent = newSalesAgent( sales.context, requestId, - slotIndex, + none UInt256, none StorageRequest ) agent.context.onIgnored = proc {.gcsafe, upraises:[].} = sales.agents.keepItIf(it != agent) - agent.start(SaleDownloading()) + agent.start(SalePreparing()) sales.agents.add agent proc load*(sales: Sales) {.async.} = @@ -110,7 +104,7 @@ proc load*(sales: Sales) {.async.} = let agent = newSalesAgent( sales.context, slot.request.id, - slot.slotIndex, + some slot.slotIndex, some slot.request) agent.start(SaleUnknown()) sales.agents.add agent diff --git a/codex/sales/salesagent.nim b/codex/sales/salesagent.nim index 372c3da8..81858702 100644 --- a/codex/sales/salesagent.nim +++ b/codex/sales/salesagent.nim @@ -1,8 +1,13 @@ +import std/sequtils import pkg/chronos import pkg/chronicles +import pkg/questionable +import pkg/questionable/results import pkg/stint import ../contracts/requests import ../utils/asyncspawn +import ../rng +import ../errors import ./statemachine import ./salescontext import ./salesdata @@ -13,10 +18,13 @@ export reservations logScope: topics = "sales statemachine" -type SalesAgent* = ref object of Machine - context*: SalesContext - data*: SalesData - subscribed: bool +type + SalesAgent* = ref object of Machine + context*: SalesContext + data*: SalesData + subscribed: bool + SalesAgentError = object of CodexError + AllSlotsFilledError* = object of SalesAgentError func `==`*(a, b: SalesAgent): bool = a.data.requestId == b.data.requestId and @@ -24,7 +32,7 @@ func `==`*(a, b: SalesAgent): bool = proc newSalesAgent*(context: SalesContext, requestId: RequestId, - slotIndex: UInt256, + slotIndex: ?UInt256, request: ?StorageRequest): SalesAgent = SalesAgent( context: context, @@ -39,6 +47,43 @@ proc retrieveRequest*(agent: SalesAgent) {.async.} = if data.request.isNone: data.request = await market.getRequest(data.requestId) +proc nextRandom(sample: openArray[uint64]): uint64 = + let rng = Rng.instance + return rng.sample(sample) + +proc assignRandomSlotIndex*(agent: SalesAgent, + numSlots: uint64): Future[?!void] {.async.} = + let market = agent.context.market + let data = agent.data + + if numSlots == 0: + agent.data.slotIndex = none UInt256 + let error = newException(ValueError, "numSlots must be greater than zero") + return failure(error) + + var idx: UInt256 + var sample = toSeq(0'u64..