nim-codex/codex/sales.nim

113 lines
3.4 KiB
Nim
Raw Normal View History

2022-03-30 10:51:28 +00:00
import pkg/questionable
import pkg/upraises
import pkg/stint
import pkg/nimcrypto
import pkg/chronicles
2022-08-01 12:12:05 +00:00
import ./rng
2022-03-30 10:51:28 +00:00
import ./market
2022-05-17 15:02:03 +00:00
import ./clock
import ./proving
import ./contracts/requests
import ./sales/salesagent
import ./sales/statemachine
import ./sales/states/[downloading, unknown]
2022-03-30 10:51:28 +00:00
2022-07-07 14:36:48 +00:00
## 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 ---> |
2022-03-30 10:51:28 +00:00
export stint
export salesagent
export statemachine
2022-03-30 10:51:28 +00:00
func new*(_: type Sales,
market: Market,
clock: Clock,
proving: Proving): Sales =
2022-05-17 15:02:03 +00:00
Sales(
market: market,
clock: clock,
proving: proving
2022-05-17 15:02:03 +00:00
)
2022-03-30 10:51:28 +00:00
proc init*(_: type Availability,
size: UInt256,
duration: UInt256,
2022-03-30 10:51:28 +00:00
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
)
2022-08-01 12:12:05 +00:00
await agent.init(ask.slots)
await agent.switchAsync(SaleDownloading())
sales.agents.add agent
proc load*(sales: Sales) {.async.} =
let market = sales.market
2022-07-05 07:39:59 +00:00
# TODO: restore availability from disk
2022-07-05 13:04:25 +00:00
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)
2022-03-31 12:35:53 +00:00
await agent.init(request.ask.slots)
await agent.switchAsync(SaleUnknown())
sales.agents.add agent
2022-03-30 10:51:28 +00:00
proc start*(sales: Sales) {.async.} =
2022-03-30 10:51:28 +00:00
doAssert sales.subscription.isNone, "Sales already started"
proc onRequest(requestId: RequestId, ask: StorageAsk) {.gcsafe, upraises:[], async.} =
await sales.handleRequest(requestId, ask)
2022-03-30 10:51:28 +00:00
try:
sales.subscription = some await sales.market.subscribeRequests(onRequest)
except CatchableError as e:
error "Unable to start sales", msg = e.msg
2022-03-30 10:51:28 +00:00
proc stop*(sales: Sales) {.async.} =
2022-03-30 10:51:28 +00:00
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()