113 lines
3.4 KiB
Nim
113 lines
3.4 KiB
Nim
import pkg/questionable
|
|
import pkg/upraises
|
|
import pkg/stint
|
|
import pkg/nimcrypto
|
|
import pkg/chronicles
|
|
import ./rng
|
|
import ./market
|
|
import ./clock
|
|
import ./proving
|
|
import ./contracts/requests
|
|
import ./sales/salesagent
|
|
import ./sales/statemachine
|
|
import ./sales/states/[downloading, unknown]
|
|
|
|
## Sales holds a list of available storage that it may sell.
|
|
##
|
|
## When storage is requested on the market that matches availability, the Sales
|
|
## object will instruct the Codex node to persist the requested data. Once the
|
|
## data has been persisted, it uploads a proof of storage to the market in an
|
|
## attempt to win a storage contract.
|
|
##
|
|
## Node Sales Market
|
|
## | | |
|
|
## | -- add availability --> | |
|
|
## | | <-- storage request --- |
|
|
## | <----- store data ------ | |
|
|
## | -----------------------> | |
|
|
## | | |
|
|
## | <----- prove data ---- | |
|
|
## | -----------------------> | |
|
|
## | | ---- storage proof ---> |
|
|
|
|
export stint
|
|
export salesagent
|
|
export statemachine
|
|
|
|
func new*(_: type Sales,
|
|
market: Market,
|
|
clock: Clock,
|
|
proving: Proving): Sales =
|
|
Sales(
|
|
market: market,
|
|
clock: clock,
|
|
proving: proving
|
|
)
|
|
|
|
proc init*(_: type Availability,
|
|
size: UInt256,
|
|
duration: UInt256,
|
|
minPrice: UInt256): Availability =
|
|
var id: array[32, byte]
|
|
doAssert randomBytes(id) == 32
|
|
Availability(id: id, size: size, duration: duration, minPrice: minPrice)
|
|
|
|
proc handleRequest(sales: Sales,
|
|
requestId: RequestId,
|
|
ask: StorageAsk) {.async.} =
|
|
let availability = sales.findAvailability(ask)
|
|
let agent = newSalesAgent(
|
|
sales,
|
|
requestId,
|
|
availability,
|
|
none StorageRequest
|
|
)
|
|
|
|
await agent.init(ask.slots)
|
|
await agent.switchAsync(SaleDownloading())
|
|
sales.agents.add agent
|
|
|
|
proc load*(sales: Sales) {.async.} =
|
|
let market = sales.market
|
|
|
|
# TODO: restore availability from disk
|
|
|
|
let slotIds = await market.mySlots()
|
|
for slotId in slotIds:
|
|
# TODO: this needs to be optimised
|
|
if slot =? await market.getSlot(slotId):
|
|
if request =? await market.getRequest(slot.requestId):
|
|
let availability = sales.findAvailability(request.ask)
|
|
let agent = newSalesAgent(
|
|
sales,
|
|
slot.requestId,
|
|
availability,
|
|
some request)
|
|
|
|
await agent.init(request.ask.slots)
|
|
await agent.switchAsync(SaleUnknown())
|
|
sales.agents.add agent
|
|
|
|
proc start*(sales: Sales) {.async.} =
|
|
doAssert sales.subscription.isNone, "Sales already started"
|
|
|
|
proc onRequest(requestId: RequestId, ask: StorageAsk) {.gcsafe, upraises:[], async.} =
|
|
await sales.handleRequest(requestId, ask)
|
|
|
|
try:
|
|
sales.subscription = some await sales.market.subscribeRequests(onRequest)
|
|
except CatchableError as e:
|
|
error "Unable to start sales", msg = e.msg
|
|
|
|
proc stop*(sales: Sales) {.async.} =
|
|
if subscription =? sales.subscription:
|
|
sales.subscription = market.Subscription.none
|
|
try:
|
|
await subscription.unsubscribe()
|
|
except CatchableError as e:
|
|
warn "Unsubscribe failed", msg = e.msg
|
|
|
|
for agent in sales.agents:
|
|
await agent.deinit()
|
|
|