feat: slots rest api (#443)

Co-authored-by: markspanbroek <mark@spanbroek.net>
This commit is contained in:
Adam Uhlíř 2023-06-20 14:52:15 +02:00 committed by GitHub
parent 219c7704b9
commit 4cd8dd2e05
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 82 additions and 13 deletions

View File

@ -1,4 +1,5 @@
import std/strutils import std/strutils
import std/strformat
import pkg/chronicles import pkg/chronicles
import pkg/ethers import pkg/ethers
import pkg/ethers/testing import pkg/ethers/testing
@ -52,7 +53,10 @@ method myRequests*(market: OnChainMarket): Future[seq[RequestId]] {.async.} =
return await market.contract.myRequests return await market.contract.myRequests
method mySlots*(market: OnChainMarket): Future[seq[SlotId]] {.async.} = method mySlots*(market: OnChainMarket): Future[seq[SlotId]] {.async.} =
return await market.contract.mySlots() let slots = await market.contract.mySlots()
debug "Fetched my slots", numSlots=len(slots)
return slots
method requestStorage(market: OnChainMarket, request: StorageRequest){.async.} = method requestStorage(market: OnChainMarket, request: StorageRequest){.async.} =
debug "Requesting storage" debug "Requesting storage"

View File

@ -56,6 +56,7 @@ proc prove(proving: Proving, slot: Slot) {.async.} =
without onProve =? proving.onProve: without onProve =? proving.onProve:
raiseAssert "onProve callback not set" raiseAssert "onProve callback not set"
try: try:
debug "Proving slot"
let proof = await onProve(slot) let proof = await onProve(slot)
await proving.market.submitProof(slot.id, proof) await proving.market.submitProof(slot.id, proof)
except CatchableError as e: except CatchableError as e:

View File

@ -313,6 +313,17 @@ proc initRestApi*(node: CodexNodeRef, conf: CodexConf): RestRouter =
trace "debug/peer returning peer record" trace "debug/peer returning peer record"
return RestApiResponse.response($json) return RestApiResponse.response($json)
router.api(
MethodGet,
"/api/codex/v1/sales/slots") do () -> RestApiResponse:
## Returns active slots for the host
without contracts =? node.contracts.host:
return RestApiResponse.error(Http503, "Sales unavailable")
let json = %(await contracts.sales.mySlots())
return RestApiResponse.response($json, contentType="application/json")
router.api( router.api(
MethodGet, MethodGet,
"/api/codex/v1/sales/availability") do () -> RestApiResponse: "/api/codex/v1/sales/availability") do () -> RestApiResponse:

View File

@ -55,6 +55,13 @@ func `%`*(arr: openArray[byte]): JsonNode =
func `%`*(id: RequestId | SlotId | Nonce | AvailabilityId): JsonNode = func `%`*(id: RequestId | SlotId | Nonce | AvailabilityId): JsonNode =
% id.toArray % id.toArray
func `%`*(obj: StorageRequest | Slot): JsonNode =
let jsonObj = newJObject()
for k, v in obj.fieldPairs: jsonObj[k] = %v
jsonObj["id"] = %(obj.id)
return jsonObj
func `%`*(purchase: Purchase): JsonNode = func `%`*(purchase: Purchase): JsonNode =
%*{ %*{
"state": purchase.state |? "none", "state": purchase.state |? "none",

View File

@ -100,20 +100,28 @@ proc handleRequest(sales: Sales,
agent.start(SaleDownloading()) agent.start(SaleDownloading())
sales.agents.add agent sales.agents.add agent
proc load*(sales: Sales) {.async.} = proc mySlots*(sales: Sales): Future[seq[Slot]] {.async.} =
let market = sales.context.market let market = sales.context.market
let slotIds = await market.mySlots() let slotIds = await market.mySlots()
var slots: seq[Slot] = @[]
for slotId in slotIds: for slotId in slotIds:
if slot =? (await market.getActiveSlot(slotId)): if slot =? (await market.getActiveSlot(slotId)):
let agent = newSalesAgent( slots.add slot
sales.context,
slot.request.id, return slots
slot.slotIndex,
some slot.request) proc load*(sales: Sales) {.async.} =
agent.start(SaleUnknown()) let slots = await sales.mySlots()
sales.agents.add agent
for slot in slots:
let agent = newSalesAgent(
sales.context,
slot.request.id,
slot.slotIndex,
some slot.request)
agent.start(SaleUnknown())
sales.agents.add agent
proc start*(sales: Sales) {.async.} = proc start*(sales: Sales) {.async.} =
doAssert sales.subscription.isNone, "Sales already started" doAssert sales.subscription.isNone, "Sales already started"

View File

@ -116,6 +116,18 @@ components:
type: string type: string
description: Maximum collateral user is willing to pay per filled Slot (in amount of tokens) description: Maximum collateral user is willing to pay per filled Slot (in amount of tokens)
Slot:
type: object
properties:
id:
type: string
description: Slot ID
request:
$ref: "#/components/schemas/StorageRequest"
slotIndex:
type: string
description: Slot Index as hexadecimal string
StorageRequestCreation: StorageRequestCreation:
type: object type: object
required: required:
@ -166,6 +178,9 @@ components:
StorageRequest: StorageRequest:
type: object type: object
properties: properties:
id:
type: string
description: Request ID
client: client:
$ref: "#/components/schemas/EthereumAddress" $ref: "#/components/schemas/EthereumAddress"
ask: ask:
@ -286,14 +301,32 @@ paths:
"500": "500":
description: Well it was bad-bad and the upload did not work out description: Well it was bad-bad and the upload did not work out
"/sales/slots":
get:
summary: "Returns active slots"
tags: [ Marketplace ]
operationId: getActiveSlots
responses:
"200":
description: Retrieved active slots
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Slot"
"503":
description: Sales are unavailable
"/sales/availability": "/sales/availability":
get: get:
summary: "Returns storage that is for sale" summary: "Returns storage that is for sale"
tags: [ Marketplace ] tags: [ Marketplace ]
operationId: getsOfferedStorage operationId: getOfferedStorage
responses: responses:
"200": "200":
description: Retrieved content specified by CID description: Retrieved storage availabilities of the node
content: content:
application/json: application/json:
schema: schema:

View File

@ -50,6 +50,11 @@ proc getPurchase*(client: CodexClient, purchase: string): JsonNode =
let body = client.http.getContent(url) let body = client.http.getContent(url)
parseJson(body).catch |? nil parseJson(body).catch |? nil
proc getSlots*(client: CodexClient): JsonNode =
let url = client.baseurl & "/sales/slots"
let body = client.http.getContent(url)
parseJson(body).catch |? nil
proc postAvailability*(client: CodexClient, proc postAvailability*(client: CodexClient,
size, duration, minPrice: uint64, maxCollateral: uint64): JsonNode = size, duration, minPrice: uint64, maxCollateral: uint64): JsonNode =
let url = client.baseurl & "/sales/availability" let url = client.baseurl & "/sales/availability"

2
vendor/nim-ethers vendored

@ -1 +1 @@
Subproject commit 5a4f786757124c903ab46499689db8273ee5ac80 Subproject commit 18e225607cc6add166b93df6ac4229936a641318