From 655327989cb2df2957df25b8a059252c2738c1e4 Mon Sep 17 00:00:00 2001 From: Redm4x <2829180+Redm4x@users.noreply.github.com> Date: Fri, 8 Dec 2023 10:57:09 -0500 Subject: [PATCH 1/3] Add provider deployments endpoint --- api/src/db/deploymentProvider.ts | 82 +++++++++++++++++++++++++++- api/src/routers/apiRouter.ts | 19 +++++++ shared/dbSchemas/akash/deployment.ts | 6 +- shared/dbSchemas/akash/lease.ts | 3 + 4 files changed, 107 insertions(+), 3 deletions(-) diff --git a/api/src/db/deploymentProvider.ts b/api/src/db/deploymentProvider.ts index 19e2f7884..6d763e5e2 100644 --- a/api/src/db/deploymentProvider.ts +++ b/api/src/db/deploymentProvider.ts @@ -2,7 +2,7 @@ import * as v1 from "@src/proto/akash/v1beta1"; import * as v2 from "@src/proto/akash/v1beta2"; import { decodeMsg } from "@src/utils/protobuf"; import { Transaction } from "@shared/dbSchemas/base"; -import { Deployment } from "@shared/dbSchemas/akash"; +import { Deployment, Lease } from "@shared/dbSchemas/akash"; import { Op } from "sequelize"; import { Block, Message } from "@shared/dbSchemas"; @@ -69,3 +69,83 @@ export async function getDeploymentRelatedMessages(owner: string, dseq: string) type: msg.type })); } + +export async function getProviderDeployments(provider: string, skip: number, limit: number, status?: "active" | "closed") { + try { + let leaseFilter = { providerAddress: provider }; + + if (status) { + leaseFilter["closedHeight"] = status === "active" ? null : { [Op.ne]: null }; + } + + const deploymentDseqs = await Deployment.findAll({ + attributes: ["dseq"], + include: [{ model: Lease, required: true, where: leaseFilter }], + order: [["createdHeight", "DESC"]], + offset: skip, + limit: limit, + subQuery: false + }); + + const deployments = await Deployment.findAll({ + where: { + dseq: { [Op.in]: deploymentDseqs.map((d) => d.dseq) } + }, + include: [ + { + model: Lease, + required: true, + where: { providerAddress: provider }, + include: [ + { model: Block, required: true, as: "createdBlock" }, + { model: Block, required: false, as: "closedBlock" } + ] + }, + { model: Block, required: true, as: "createdBlock" }, + { model: Block, required: false, as: "closedBlock" } + ] + }); + + return deployments.map((d) => ({ + owner: d.owner, + dseq: d.dseq, + denom: d.denom, + createdHeight: d.createdHeight, + createdDate: d.createdBlock.datetime, + closedHeight: d.closedHeight, + closedDate: d.closedHeight ? d.closedBlock.datetime : null, + status: d.closedHeight ? "closed" : "active", + balance: d.balance, + transferred: d.withdrawnAmount, + settledAt: d.lastWithdrawHeight, + resources: { + cpu: d.leases.reduce((acc, l) => acc + l.cpuUnits, 0), + memory: d.leases.reduce((acc, l) => acc + l.memoryQuantity, 0), + gpu: d.leases.reduce((acc, l) => acc + l.gpuUnits, 0), + ephemeralStorage: d.leases.reduce((acc, l) => acc + l.ephemeralStorageQuantity, 0), + persistentStorage: d.leases.reduce((acc, l) => acc + l.persistentStorageQuantity, 0) + }, + leases: d.leases.map((l) => ({ + provider: l.providerAddress, + gseq: l.gseq, + oseq: l.oseq, + price: l.price, + createdHeight: l.createdHeight, + createdDate: l.createdBlock.datetime, + closedHeight: l.closedHeight, + closedDate: l.closedHeight ? l.closedBlock.datetime : null, + status: l.closedHeight ? "closed" : "active", + resources: { + cpu: l.cpuUnits, + memory: l.memoryQuantity, + gpu: l.gpuUnits, + ephemeralStorage: l.ephemeralStorageQuantity, + persistentStorage: l.persistentStorageQuantity + } + })) + })); + } catch (e) { + console.error(e); + throw e; + } +} diff --git a/api/src/routers/apiRouter.ts b/api/src/routers/apiRouter.ts index 2fe579dc1..8117ce5f3 100644 --- a/api/src/routers/apiRouter.ts +++ b/api/src/routers/apiRouter.ts @@ -24,6 +24,7 @@ import axios from "axios"; import { getMarketData } from "@src/providers/marketDataProvider"; import { getAuditors, getProviderAttributesSchema } from "@src/providers/githubProvider"; import { getProviderRegions } from "@src/db/providerDataProvider"; +import { getProviderDeployments } from "@src/db/deploymentProvider"; export const apiRouter = express.Router(); @@ -192,6 +193,24 @@ apiRouter.get( }) ); +apiRouter.get( + "/providers/:provider/deployments/:skip/:limit/:status?", + asyncHandler(async (req, res) => { + const skip = parseInt(req.params.skip); + const limit = Math.min(100, parseInt(req.params.limit)); + const statusParam = req.params.status as "active" | "closed" | undefined; + + if (statusParam && statusParam !== "active" && statusParam !== "closed") { + res.status(400).send(`Invalid status filter: "${statusParam}". Valid values are "active" and "closed".`); + return; + } + + const deployments = await getProviderDeployments(req.params.provider, skip, limit, statusParam); + + res.send(deployments); + }) +); + apiRouter.get( "/validators", asyncHandler(async (req, res) => { diff --git a/shared/dbSchemas/akash/deployment.ts b/shared/dbSchemas/akash/deployment.ts index a62d71161..89795c0b7 100644 --- a/shared/dbSchemas/akash/deployment.ts +++ b/shared/dbSchemas/akash/deployment.ts @@ -1,8 +1,8 @@ -import { Column, Default, HasMany, Model, PrimaryKey, Table } from "sequelize-typescript"; +import { BelongsTo, Column, Default, HasMany, Model, PrimaryKey, Table } from "sequelize-typescript"; import { DataTypes, UUIDV4 } from "sequelize"; import { DeploymentGroup } from "./deploymentGroup"; import { Lease } from "./lease"; -import { Message } from "../base/message"; +import { Message, Block } from "../base"; import { Required } from "../decorators/requiredDecorator"; @Table({ modelName: "deployment" }) @@ -18,6 +18,8 @@ export class Deployment extends Model { @Required @Column(DataTypes.DOUBLE) withdrawnAmount!: number; @Column closedHeight?: number; + @BelongsTo(() => Block, "createdHeight") createdBlock: Block; + @BelongsTo(() => Block, "closedHeight") closedBlock: Block; @HasMany(() => DeploymentGroup, "deploymentId") deploymentGroups: DeploymentGroup[]; @HasMany(() => Lease, "deploymentId") leases: Lease[]; @HasMany(() => Message, { foreignKey: "relatedDeploymentId", constraints: false }) relatedMessages: Message[]; diff --git a/shared/dbSchemas/akash/lease.ts b/shared/dbSchemas/akash/lease.ts index 2a00c4a21..b5c06887d 100644 --- a/shared/dbSchemas/akash/lease.ts +++ b/shared/dbSchemas/akash/lease.ts @@ -4,6 +4,7 @@ import { DeploymentGroup } from "./deploymentGroup"; import { Deployment } from "./deployment"; import { Provider } from "./provider"; import { Required } from "../decorators/requiredDecorator"; +import { Block } from "../base"; @Table({ modelName: "lease", @@ -37,6 +38,8 @@ export class Lease extends Model { @Required @Column(DataTypes.BIGINT) ephemeralStorageQuantity: number; @Required @Column(DataTypes.BIGINT) persistentStorageQuantity: number; + @BelongsTo(() => Block, "createdHeight") createdBlock: Block; + @BelongsTo(() => Block, "closedHeight") closedBlock: Block; @BelongsTo(() => DeploymentGroup, "deploymentGroupId") deploymentGroup: DeploymentGroup; @BelongsTo(() => Deployment, "deploymentId") deployment: Deployment; @BelongsTo(() => Provider, "providerAddress") provider: Provider; From 968542d80ee5b9fcca8b25b20591d86bda3cb73a Mon Sep 17 00:00:00 2001 From: Redm4x <2829180+Redm4x@users.noreply.github.com> Date: Fri, 8 Dec 2023 11:04:45 -0500 Subject: [PATCH 2/3] Remove try/catch --- api/src/db/deploymentProvider.ts | 137 +++++++++++++++---------------- 1 file changed, 66 insertions(+), 71 deletions(-) diff --git a/api/src/db/deploymentProvider.ts b/api/src/db/deploymentProvider.ts index 6d763e5e2..c36a12a7a 100644 --- a/api/src/db/deploymentProvider.ts +++ b/api/src/db/deploymentProvider.ts @@ -71,81 +71,76 @@ export async function getDeploymentRelatedMessages(owner: string, dseq: string) } export async function getProviderDeployments(provider: string, skip: number, limit: number, status?: "active" | "closed") { - try { - let leaseFilter = { providerAddress: provider }; + let leaseFilter = { providerAddress: provider }; - if (status) { - leaseFilter["closedHeight"] = status === "active" ? null : { [Op.ne]: null }; - } + if (status) { + leaseFilter["closedHeight"] = status === "active" ? null : { [Op.ne]: null }; + } - const deploymentDseqs = await Deployment.findAll({ - attributes: ["dseq"], - include: [{ model: Lease, required: true, where: leaseFilter }], - order: [["createdHeight", "DESC"]], - offset: skip, - limit: limit, - subQuery: false - }); + const deploymentDseqs = await Deployment.findAll({ + attributes: ["dseq"], + include: [{ model: Lease, required: true, where: leaseFilter }], + order: [["createdHeight", "DESC"]], + offset: skip, + limit: limit, + subQuery: false + }); - const deployments = await Deployment.findAll({ - where: { - dseq: { [Op.in]: deploymentDseqs.map((d) => d.dseq) } + const deployments = await Deployment.findAll({ + where: { + dseq: { [Op.in]: deploymentDseqs.map((d) => d.dseq) } + }, + include: [ + { + model: Lease, + required: true, + where: { providerAddress: provider }, + include: [ + { model: Block, required: true, as: "createdBlock" }, + { model: Block, required: false, as: "closedBlock" } + ] }, - include: [ - { - model: Lease, - required: true, - where: { providerAddress: provider }, - include: [ - { model: Block, required: true, as: "createdBlock" }, - { model: Block, required: false, as: "closedBlock" } - ] - }, - { model: Block, required: true, as: "createdBlock" }, - { model: Block, required: false, as: "closedBlock" } - ] - }); + { model: Block, required: true, as: "createdBlock" }, + { model: Block, required: false, as: "closedBlock" } + ] + }); - return deployments.map((d) => ({ - owner: d.owner, - dseq: d.dseq, - denom: d.denom, - createdHeight: d.createdHeight, - createdDate: d.createdBlock.datetime, - closedHeight: d.closedHeight, - closedDate: d.closedHeight ? d.closedBlock.datetime : null, - status: d.closedHeight ? "closed" : "active", - balance: d.balance, - transferred: d.withdrawnAmount, - settledAt: d.lastWithdrawHeight, + return deployments.map((d) => ({ + owner: d.owner, + dseq: d.dseq, + denom: d.denom, + createdHeight: d.createdHeight, + createdDate: d.createdBlock.datetime, + closedHeight: d.closedHeight, + closedDate: d.closedHeight ? d.closedBlock.datetime : null, + status: d.closedHeight ? "closed" : "active", + balance: d.balance, + transferred: d.withdrawnAmount, + settledAt: d.lastWithdrawHeight, + resources: { + cpu: d.leases.reduce((acc, l) => acc + l.cpuUnits, 0), + memory: d.leases.reduce((acc, l) => acc + l.memoryQuantity, 0), + gpu: d.leases.reduce((acc, l) => acc + l.gpuUnits, 0), + ephemeralStorage: d.leases.reduce((acc, l) => acc + l.ephemeralStorageQuantity, 0), + persistentStorage: d.leases.reduce((acc, l) => acc + l.persistentStorageQuantity, 0) + }, + leases: d.leases.map((l) => ({ + provider: l.providerAddress, + gseq: l.gseq, + oseq: l.oseq, + price: l.price, + createdHeight: l.createdHeight, + createdDate: l.createdBlock.datetime, + closedHeight: l.closedHeight, + closedDate: l.closedHeight ? l.closedBlock.datetime : null, + status: l.closedHeight ? "closed" : "active", resources: { - cpu: d.leases.reduce((acc, l) => acc + l.cpuUnits, 0), - memory: d.leases.reduce((acc, l) => acc + l.memoryQuantity, 0), - gpu: d.leases.reduce((acc, l) => acc + l.gpuUnits, 0), - ephemeralStorage: d.leases.reduce((acc, l) => acc + l.ephemeralStorageQuantity, 0), - persistentStorage: d.leases.reduce((acc, l) => acc + l.persistentStorageQuantity, 0) - }, - leases: d.leases.map((l) => ({ - provider: l.providerAddress, - gseq: l.gseq, - oseq: l.oseq, - price: l.price, - createdHeight: l.createdHeight, - createdDate: l.createdBlock.datetime, - closedHeight: l.closedHeight, - closedDate: l.closedHeight ? l.closedBlock.datetime : null, - status: l.closedHeight ? "closed" : "active", - resources: { - cpu: l.cpuUnits, - memory: l.memoryQuantity, - gpu: l.gpuUnits, - ephemeralStorage: l.ephemeralStorageQuantity, - persistentStorage: l.persistentStorageQuantity - } - })) - })); - } catch (e) { - console.error(e); - throw e; - } + cpu: l.cpuUnits, + memory: l.memoryQuantity, + gpu: l.gpuUnits, + ephemeralStorage: l.ephemeralStorageQuantity, + persistentStorage: l.persistentStorageQuantity + } + })) + })); } From bbfa6ab600bdfbff38b5b565e3fee0fb0cc5081b Mon Sep 17 00:00:00 2001 From: Redm4x <2829180+Redm4x@users.noreply.github.com> Date: Fri, 8 Dec 2023 12:04:35 -0500 Subject: [PATCH 3/3] Fix limit for multi-lease deployments --- api/src/db/deploymentProvider.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/api/src/db/deploymentProvider.ts b/api/src/db/deploymentProvider.ts index c36a12a7a..7fdb7f8bc 100644 --- a/api/src/db/deploymentProvider.ts +++ b/api/src/db/deploymentProvider.ts @@ -78,12 +78,11 @@ export async function getProviderDeployments(provider: string, skip: number, lim } const deploymentDseqs = await Deployment.findAll({ - attributes: ["dseq"], - include: [{ model: Lease, required: true, where: leaseFilter }], + attributes: ["dseq", "createdHeight"], + include: [{ model: Lease, attributes: [], required: true, where: leaseFilter }], order: [["createdHeight", "DESC"]], offset: skip, - limit: limit, - subQuery: false + limit: limit }); const deployments = await Deployment.findAll({