From 4cd8dd2e058c8cdeaf2b3066145c4a597d3665d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Uhl=C3=AD=C5=99?= Date: Tue, 20 Jun 2023 14:52:15 +0200 Subject: [PATCH] feat: slots rest api (#443) Co-authored-by: markspanbroek --- codex/contracts/market.nim | 6 ++++- codex/proving.nim | 1 + codex/rest/api.nim | 11 +++++++++ codex/rest/json.nim | 7 ++++++ codex/sales.nim | 26 ++++++++++++++-------- openapi.yaml | 37 +++++++++++++++++++++++++++++-- tests/integration/codexclient.nim | 5 +++++ vendor/nim-ethers | 2 +- 8 files changed, 82 insertions(+), 13 deletions(-) diff --git a/codex/contracts/market.nim b/codex/contracts/market.nim index 841e4138..9650df24 100644 --- a/codex/contracts/market.nim +++ b/codex/contracts/market.nim @@ -1,4 +1,5 @@ import std/strutils +import std/strformat import pkg/chronicles import pkg/ethers import pkg/ethers/testing @@ -52,7 +53,10 @@ method myRequests*(market: OnChainMarket): Future[seq[RequestId]] {.async.} = return await market.contract.myRequests 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.} = debug "Requesting storage" diff --git a/codex/proving.nim b/codex/proving.nim index 101baae2..6ba5dc1b 100644 --- a/codex/proving.nim +++ b/codex/proving.nim @@ -56,6 +56,7 @@ proc prove(proving: Proving, slot: Slot) {.async.} = without onProve =? proving.onProve: raiseAssert "onProve callback not set" try: + debug "Proving slot" let proof = await onProve(slot) await proving.market.submitProof(slot.id, proof) except CatchableError as e: diff --git a/codex/rest/api.nim b/codex/rest/api.nim index 865ae633..5a7f69d1 100644 --- a/codex/rest/api.nim +++ b/codex/rest/api.nim @@ -313,6 +313,17 @@ proc initRestApi*(node: CodexNodeRef, conf: CodexConf): RestRouter = trace "debug/peer returning peer record" 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( MethodGet, "/api/codex/v1/sales/availability") do () -> RestApiResponse: diff --git a/codex/rest/json.nim b/codex/rest/json.nim index ff087467..28457af2 100644 --- a/codex/rest/json.nim +++ b/codex/rest/json.nim @@ -55,6 +55,13 @@ func `%`*(arr: openArray[byte]): JsonNode = func `%`*(id: RequestId | SlotId | Nonce | AvailabilityId): JsonNode = % 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 = %*{ "state": purchase.state |? "none", diff --git a/codex/sales.nim b/codex/sales.nim index 01f3da77..8efeaf61 100644 --- a/codex/sales.nim +++ b/codex/sales.nim @@ -100,20 +100,28 @@ proc handleRequest(sales: Sales, agent.start(SaleDownloading()) sales.agents.add agent -proc load*(sales: Sales) {.async.} = +proc mySlots*(sales: Sales): Future[seq[Slot]] {.async.} = let market = sales.context.market - let slotIds = await market.mySlots() + var slots: seq[Slot] = @[] for slotId in slotIds: if slot =? (await market.getActiveSlot(slotId)): - let agent = newSalesAgent( - sales.context, - slot.request.id, - slot.slotIndex, - some slot.request) - agent.start(SaleUnknown()) - sales.agents.add agent + slots.add slot + + return slots + +proc load*(sales: Sales) {.async.} = + let slots = await sales.mySlots() + + 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.} = doAssert sales.subscription.isNone, "Sales already started" diff --git a/openapi.yaml b/openapi.yaml index 7576aa49..085e532d 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -116,6 +116,18 @@ components: type: string 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: type: object required: @@ -166,6 +178,9 @@ components: StorageRequest: type: object properties: + id: + type: string + description: Request ID client: $ref: "#/components/schemas/EthereumAddress" ask: @@ -286,14 +301,32 @@ paths: "500": 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": get: summary: "Returns storage that is for sale" tags: [ Marketplace ] - operationId: getsOfferedStorage + operationId: getOfferedStorage responses: "200": - description: Retrieved content specified by CID + description: Retrieved storage availabilities of the node content: application/json: schema: diff --git a/tests/integration/codexclient.nim b/tests/integration/codexclient.nim index cc3e5eef..92117111 100644 --- a/tests/integration/codexclient.nim +++ b/tests/integration/codexclient.nim @@ -50,6 +50,11 @@ proc getPurchase*(client: CodexClient, purchase: string): JsonNode = let body = client.http.getContent(url) 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, size, duration, minPrice: uint64, maxCollateral: uint64): JsonNode = let url = client.baseurl & "/sales/availability" diff --git a/vendor/nim-ethers b/vendor/nim-ethers index 5a4f7867..18e22560 160000 --- a/vendor/nim-ethers +++ b/vendor/nim-ethers @@ -1 +1 @@ -Subproject commit 5a4f786757124c903ab46499689db8273ee5ac80 +Subproject commit 18e225607cc6add166b93df6ac4229936a641318