Skip to content

Commit

Permalink
feat: support data centers (#1091)
Browse files Browse the repository at this point in the history
* feat: support data centers

* improve offer info

* improve cc epochs display

* gen manifest if it doesn't exist

* fix data center is optional

* Apply automatic changes

* fix init

* add peerId comment

* use peerId base58

* rename to cityIndex

* use latest snapshot

---------

Co-authored-by: shamsartem <[email protected]>
  • Loading branch information
shamsartem and shamsartem authored Jan 13, 2025
1 parent 26dd8b7 commit 651f830
Show file tree
Hide file tree
Showing 11 changed files with 282 additions and 36 deletions.
14 changes: 13 additions & 1 deletion packages/cli/package/docs/configs/provider.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Defines provider configuration
|-----------------------|--------------------------------|----------|----------------------------------------------------------------------------|
| `capacityCommitments` | [object](#capacitycommitments) | **Yes** | A map with computePeer names as keys and capacity commitments as values |
| `computePeers` | [object](#computepeers) | **Yes** | A map with compute peer names as keys and compute peer configs as values |
| `dataCenters` | [object](#datacenters) | **Yes** | A map with data center names as keys and data center IDs as values |
| `offers` | [object](#offers) | **Yes** | A map with offer names as keys and offer configs as values |
| `providerName` | string | **Yes** | Provider name. Must not be empty |
| `version` | integer | **Yes** | Config version |
Expand Down Expand Up @@ -170,6 +171,16 @@ Override or extend Storage details not related to matching but visible to the us
| `model` | string | No | |
| `sequentialWriteSpeed` | integer | No | |

## dataCenters

A map with data center names as keys and data center IDs as values

### Properties

| Property | Type | Required | Description |
|--------------------|--------|----------|-------------|
| `<dataCenterName>` | string | No | |

## offers

A map with offer names as keys and offer configs as values
Expand All @@ -189,9 +200,10 @@ Defines a provider offer
| Property | Type | Required | Description |
|----------------------|---------------------------|----------|------------------------------------------------------------------------------------|
| `computePeers` | string[] | **Yes** | Compute peers participating in this offer |
| `dataCenterName` | string | **Yes** | Data center name from top-level dataCenters property |
| `resourcePrices` | [object](#resourceprices) | **Yes** | Resource prices for the offer |
| `maxProtocolVersion` | integer | No | Max protocol version. Must be more then or equal to minProtocolVersion. Default: 1 |
| `minProtocolVersion` | integer | No | Min protocol version. Must be less then or equal to maxProtocolVersion. Default: 1 |
| `resourcePrices` | [object](#resourceprices) | No | Resource prices for the offer |

#### resourcePrices

Expand Down
2 changes: 1 addition & 1 deletion packages/cli/package/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
"whatwg-url": "^14.0.0"
},
"dependencies": {
"@fluencelabs/deal-ts-clients": "0.23.2-feat-marketplace-v2-resources-03f7996-7429-1.0",
"@fluencelabs/deal-ts-clients": "0.23.2-add-dc-to-subgraph-afdd94a-7473-1.0",
"@kubernetes/client-node": "github:fluencelabs/kubernetes-client-javascript#e72ee00a52fec4eb4a8327632895d888ee504f4d",
"@libp2p/crypto": "4.0.1",
"@libp2p/peer-id-factory": "4.0.5",
Expand Down
11 changes: 7 additions & 4 deletions packages/cli/package/src/lib/chain/commitment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1027,9 +1027,10 @@ async function getDetailedCommitmentInfo({
"@fluencelabs/deal-ts-clients/dist/dealExplorerClient/utils.js"
);

const isCCNotStarted = ccFromChain.startEpoch === 0n;

function getStartOrExpirationDate(epoch: bigint) {
// if startEpoch is 0, then it's not yet started - no need to show anything
return ccFromChain.startEpoch === 0n
return isCCNotStarted
? "-"
: secondsToDate(
calculateTimestamp(
Expand Down Expand Up @@ -1077,8 +1078,9 @@ async function getDetailedCommitmentInfo({
ccFromChain.rewardDelegatorRate,
precision,
),
startEpoch: bigintToStr(ccFromChain.startEpoch),
endEpoch: bigintToStr(ccFromChain.endEpoch),
durationEpochs: bigintToStr(ccFromChain.endEpoch - ccFromChain.startEpoch),
startEpoch: isCCNotStarted ? "-" : bigintToStr(ccFromChain.startEpoch),
endEpoch: isCCNotStarted ? "-" : bigintToStr(ccFromChain.endEpoch),
currentEpoch: bigintToStr(currentEpoch),
startDate: getStartOrExpirationDate(ccFromChain.startEpoch),
expirationDate: getStartOrExpirationDate(ccFromChain.endEpoch),
Expand Down Expand Up @@ -1125,6 +1127,7 @@ function getDetailedCommitmentInfoString(
Status: detailedCommitmentInfo.status,
Staker: detailedCommitmentInfo.staker,
"Staker reward": detailedCommitmentInfo.stakerReward,
"Duration (epochs)": detailedCommitmentInfo.durationEpochs,
"Start / End / Current epoch": [
detailedCommitmentInfo.startEpoch,
detailedCommitmentInfo.endEpoch,
Expand Down
36 changes: 35 additions & 1 deletion packages/cli/package/src/lib/chain/offer/offer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ export async function createOffers(flags: OffersArgs) {
computePeersFromProviderConfig: allCPs,
offerName,
resourcePricesWithIds,
dataCenter,
} = offer;

const resourcePricesArray = Object.values({
Expand Down Expand Up @@ -168,6 +169,7 @@ export async function createOffers(flags: OffersArgs) {
contracts.deployment.usdc,
resourcePricesArray,
setCPUSupplyForCP(computePeersToRegister),
dataCenter.id,
];
},
getTitle() {
Expand Down Expand Up @@ -361,6 +363,7 @@ async function confirmOffer(offer: EnsureOfferConfig) {
"",
{},
{
"Data Center": offer.dataCenter,
"Resource Prices": {
CPU: await formatOfferResourcePrice("cpu", offer),
RAM: await formatOfferResourcePrice("ram", offer),
Expand Down Expand Up @@ -456,6 +459,7 @@ export async function addRemainingCPs({
}) {
const { contracts } = await getContracts();
let totalAddedCPs = addedCPs.length;
const addedCPsNames = [];

while (totalAddedCPs < allCPs.length) {
const remainingCPs = allCPs.slice(totalAddedCPs);
Expand Down Expand Up @@ -487,8 +491,16 @@ export async function addRemainingCPs({
offerName,
});

addedCPsNames.push(
...addedCPs.map(({ name }) => {
return name;
}),
);

totalAddedCPs = totalAddedCPs + addedCPs.length;
}

return { addedCPsNames };
}

async function addRemainingCUs({
Expand Down Expand Up @@ -617,6 +629,7 @@ async function formatOfferInfo(
{
"Provider ID": offerIndexerInfo.providerId,
"Offer ID": offerIndexerInfo.id,
"Data Center": offerIndexerInfo.dataCenter,
"Created At": offerIndexerInfo.createdAt,
"Last Updated At": offerIndexerInfo.updatedAt,
"Resource Prices": offerIndexerInfo.resources?.map(
Expand Down Expand Up @@ -828,10 +841,21 @@ export async function resolveOffersFromProviderConfig(
),
);

const { dataCenter } = offerIndexerInfo;

assert(
dataCenter !== null && dataCenter !== undefined,
"Data center is always saved for offer on-chain when offer is created. Try waiting for indexer to index the data center",
);

const { id: dataCenterId } = dataCenter;
assertIsHex(dataCenterId, "Data center ID must be a hex string");

return {
offerName: `Offer ${offerId}`,
computePeersFromProviderConfig,
offerId,
dataCenter: { id: dataCenterId, name: dataCenterId },
minProtocolVersion: Number(
protocolVersionsFromChain.minProtocolVersion,
),
Expand Down Expand Up @@ -954,6 +978,7 @@ async function ensureOfferConfigs() {
minProtocolVersion,
maxProtocolVersion,
resourcePrices,
dataCenterName,
},
]) => {
const computePeerConfigs = await ensureComputerPeerConfigs({
Expand Down Expand Up @@ -1073,14 +1098,22 @@ async function ensureOfferConfigs() {
bandwidth: await getResourcePricesWithIds("bandwidth"),
};

const dataCenterId = providerConfig.dataCenters[dataCenterName];

assert(
dataCenterId !== undefined,
`Unreachable. Data center ${dataCenterName} is not found in provider config. This must be validated during config validation`,
);

return {
offerName,
computePeersFromProviderConfig,
offerId,
minProtocolVersion,
maxProtocolVersion,
resourcePricesWithIds,
};
dataCenter: { name: dataCenterName, id: `0x${dataCenterId}` },
} as const;
},
),
);
Expand Down Expand Up @@ -1362,6 +1395,7 @@ function serializeOfferInfo(offerIndexerInfo: OfferIndexerInfo) {

return {
id: offerIndexerInfo.id,
dataCenter: offerIndexerInfo.datacenter,
createdAt: new Date(
Number(offerIndexerInfo.createdAt) * 1000,
).toISOString(),
Expand Down
68 changes: 61 additions & 7 deletions packages/cli/package/src/lib/chain/offer/updateOffers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import { color } from "@oclif/color";
import omit from "lodash-es/omit.js";
import { stringify } from "yaml";

import { commandObj } from "../../commandObj.js";
import type { ResourceType } from "../../configs/project/provider/provider4.js";
Expand All @@ -31,6 +32,7 @@ import { numToStr } from "../../helpers/typesafeStringify.js";
import { splitErrorsAndResults } from "../../helpers/utils.js";
import { confirm } from "../../prompt.js";
import { ensureFluenceEnv } from "../../resolveFluenceEnv.js";
import type { Required } from "../../typeHelpers.js";
import { uint8ArrayToPeerIdHexString } from "../conversions.js";
import {
peerIdHexStringToBase58String,
Expand Down Expand Up @@ -58,7 +60,9 @@ type PeersOnChain = {
hexPeerId: string;
}[];

type Txs = { description?: string; tx: ReturnType<typeof populateTx> }[];
type Tx = { description?: string; tx: ReturnType<typeof populateTx> };
type Txs = Tx[];
type TxsWithDescription = Required<Tx>[];

export async function updateOffers(flags: OffersArgs) {
const offers = await resolveOffersFromProviderConfig(flags);
Expand All @@ -79,7 +83,25 @@ export async function updateOffers(flags: OffersArgs) {
].flat();

if (firstUpdateOffersTx === undefined) {
commandObj.logToStderr("No changes found for selected offers");
const addedCPs = populatedTxs.reduce<Record<string, string[]>>(
(acc, { addedCPsNames, offerName }) => {
if (addedCPsNames.length > 0) {
acc[offerName] = addedCPsNames;
}

return acc;
},
{},
);

if (Object.values(addedCPs).length === 0) {
commandObj.logToStderr("No changes found for selected offers");
} else {
commandObj.logToStderr(
`Added the compute peers to the following offers:\n${stringify(addedCPs)}`,
);
}

return;
}

Expand Down Expand Up @@ -229,10 +251,14 @@ function populateUpdateOffersTxs(offersFoundOnChain: OnChainOffer[]) {
peersOnChain,
)) satisfies Txs;

await addMissingComputePeers(offer, peersOnChain);
const { addedCPsNames } = await addMissingComputePeers(
offer,
peersOnChain,
);

const txs = (
await Promise.all([
populateDataCenterTx(offer),
populateChangeResourceSupplyAndDetailsTx(offer),
populateCUToRemoveTxs(offer, peersOnChain),
populateCUToAddTxs(offer, peersOnChain),
Expand All @@ -244,7 +270,13 @@ function populateUpdateOffersTxs(offersFoundOnChain: OnChainOffer[]) {
])
).flat() satisfies Txs;

return { offerName, offerId, removePeersFromOffersTxs, txs };
return {
offerName,
offerId,
removePeersFromOffersTxs,
txs,
addedCPsNames,
};
}),
);
}
Expand Down Expand Up @@ -344,6 +376,28 @@ async function populatePaymentTokenTx({
];
}

async function populateDataCenterTx({
offerIndexerInfo,
offerId,
dataCenter,
}: OnChainOffer) {
const { contracts } = await getContracts();
return offerIndexerInfo.dataCenter?.id === dataCenter.id
? []
: [
{
description: `\nchanging data center from ${color.yellow(
offerIndexerInfo.dataCenter?.id,
)} to ${color.yellow(dataCenter.id)}`,
tx: populateTx(
contracts.diamond.setOfferDatacenter,
offerId,
dataCenter.id,
),
},
];
}

async function populateCUToRemoveTxs(
{ computePeersFromProviderConfig }: OnChainOffer,
peersOnChain: PeersOnChain,
Expand Down Expand Up @@ -492,7 +546,7 @@ async function createResourceSupplyAndDetailsUpdateTx(
peerId: string,
{ resourceType, onChainResource, configuredResource }: ResourceSupplyUpdate,
) {
const txs: { description: string; tx: ReturnType<typeof populateTx> }[] = [];
const txs: TxsWithDescription = [];

if (onChainResource.resourceId !== configuredResource.resourceId) {
return txs;
Expand Down Expand Up @@ -548,7 +602,7 @@ async function populateChangeResourceSupplyAndDetailsTx({
computePeersFromProviderConfig,
offerIndexerInfo,
}: OnChainOffer) {
const txs: { description?: string; tx: ReturnType<typeof populateTx> }[] = [];
const txs: Txs = [];

for (const peer of offerIndexerInfo.peers) {
const peerIdBase58 = await peerIdHexStringToBase58String(peer.id);
Expand Down Expand Up @@ -638,7 +692,7 @@ async function createResourceUpdateTx(
peerId: string,
{ resourceType, onChainResource, configuredResource }: ResourceUpdate,
) {
const txs: { description: string; tx: ReturnType<typeof populateTx> }[] = [];
const txs: TxsWithDescription = [];
const { contracts } = await getContracts();

function removeResource() {
Expand Down
Loading

0 comments on commit 651f830

Please sign in to comment.