diff --git a/cli/docs/commands/README.md b/cli/docs/commands/README.md index 806257cf0..6fe83b553 100644 --- a/cli/docs/commands/README.md +++ b/cli/docs/commands/README.md @@ -43,8 +43,8 @@ * [`fluence module pack [PATH]`](#fluence-module-pack-path) * [`fluence module remove [NAME | PATH | URL]`](#fluence-module-remove-name--path--url) * [`fluence provider cc-activate`](#fluence-provider-cc-activate) -* [`fluence provider cc-collateral-withdraw`](#fluence-provider-cc-collateral-withdraw) * [`fluence provider cc-create`](#fluence-provider-cc-create) +* [`fluence provider cc-finish`](#fluence-provider-cc-finish) * [`fluence provider cc-info`](#fluence-provider-cc-info) * [`fluence provider cc-remove`](#fluence-provider-cc-remove) * [`fluence provider cc-rewards-withdraw`](#fluence-provider-cc-rewards-withdraw) @@ -1257,20 +1257,17 @@ ALIASES _See code: [src/commands/provider/cc-activate.ts](https://github.com/fluencelabs/cli/blob/fluence-cli-v0.20.2/src/commands/provider/cc-activate.ts)_ -## `fluence provider cc-collateral-withdraw` +## `fluence provider cc-create` -Withdraw FLT collateral from capacity commitments +Create Capacity commitment ``` USAGE - $ fluence provider cc-collateral-withdraw [--no-input] [--nox-names | --cc-ids ] [--offers ] - [--env ] [--priv-key ] [--max-cus ] + $ fluence provider cc-create [--no-input] [--env ] [--priv-key + ] [--nox-names ] [--offers ] FLAGS - --cc-ids= Comma separated capacity commitment IDs --env= Fluence Environment to use when running the command - --max-cus= [default: 32] Maximum number of compute units to put in a batch - when signing a transaction --no-input Don't interactively ask for any input from the user --nox-names= Comma-separated names of noxes from provider.yaml. To use all of your noxes: --nox-names all @@ -1282,25 +1279,28 @@ FLAGS is used by default when CLI is used in non-interactive mode DESCRIPTION - Withdraw FLT collateral from capacity commitments + Create Capacity commitment ALIASES - $ fluence provider ccw + $ fluence provider cc ``` -_See code: [src/commands/provider/cc-collateral-withdraw.ts](https://github.com/fluencelabs/cli/blob/fluence-cli-v0.20.2/src/commands/provider/cc-collateral-withdraw.ts)_ +_See code: [src/commands/provider/cc-create.ts](https://github.com/fluencelabs/cli/blob/fluence-cli-v0.20.2/src/commands/provider/cc-create.ts)_ -## `fluence provider cc-create` +## `fluence provider cc-finish` -Create Capacity commitment +Move resources from deals, withdraw FLT collateral from capacity commitments, remove compute units from capacity commitments and finish capacity commitments ``` USAGE - $ fluence provider cc-create [--no-input] [--env ] [--priv-key - ] [--nox-names ] [--offers ] + $ fluence provider cc-finish [--no-input] [--nox-names | --cc-ids ] [--offers ] + [--env ] [--priv-key ] [--max-cus ] FLAGS + --cc-ids= Comma separated capacity commitment IDs --env= Fluence Environment to use when running the command + --max-cus= [default: 32] Maximum number of compute units to put in a batch + when signing a transaction --no-input Don't interactively ask for any input from the user --nox-names= Comma-separated names of noxes from provider.yaml. To use all of your noxes: --nox-names all @@ -1312,13 +1312,14 @@ FLAGS is used by default when CLI is used in non-interactive mode DESCRIPTION - Create Capacity commitment + Move resources from deals, withdraw FLT collateral from capacity commitments, remove compute units from capacity + commitments and finish capacity commitments ALIASES - $ fluence provider cc + $ fluence provider ccf ``` -_See code: [src/commands/provider/cc-create.ts](https://github.com/fluencelabs/cli/blob/fluence-cli-v0.20.2/src/commands/provider/cc-create.ts)_ +_See code: [src/commands/provider/cc-finish.ts](https://github.com/fluencelabs/cli/blob/fluence-cli-v0.20.2/src/commands/provider/cc-finish.ts)_ ## `fluence provider cc-info` @@ -1589,11 +1590,12 @@ Init provider config. Creates a provider.yaml file ``` USAGE $ fluence provider init [--no-input] [--noxes ] [--env ] - [--priv-key ] + [--priv-key ] [--no-vm] FLAGS --env= Fluence Environment to use when running the command --no-input Don't interactively ask for any input from the user + --no-vm Generate provider.yaml without vm configuration --noxes= Number of Compute Peers to generate when a new provider.yaml is created --priv-key= !WARNING! for debug purposes only. Passing private keys through diff --git a/cli/docs/configs/fluence.md b/cli/docs/configs/fluence.md index 6e56cee74..d9af60f7b 100644 --- a/cli/docs/configs/fluence.md +++ b/cli/docs/configs/fluence.md @@ -97,21 +97,21 @@ Deployment config #### Properties -| Property | Type | Required | Description | -|-------------------------|----------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `blacklist` | string[] | No | Blacklist of providers to deploy to. Can't be used together with whitelist | -| `computeUnits` | integer | No | Number of compute units you require. 1 compute unit = 2GB. Currently the only allowed value is 1. This will change in the future. Default: 1 | -| `cuCountPerWorker` | integer | No | Number of compute units per worker. Default: 1 | -| `effectors` | string[] | No | Effector CIDs to be used in the deal. Must be a valid CID | -| `initialBalance` | string | No | Initial balance after deploy in USDC. Default: targetWorkers * pricePerCuPerEpoch * minDealDepositedEpochs. For local environment: enough for deal to be active for 1 day | -| `maxWorkersPerProvider` | integer | No | Max workers per provider. Matches target workers by default | -| `minWorkers` | integer | No | Required workers to activate the deal. Matches target workers by default | -| `pricePerCuPerEpoch` | string | No | Price per compute unit per epoch in USDC | -| `protocolVersion` | integer | No | Protocol version. Default: 1 | -| `services` | string[] | No | An array of service names to include in this worker. Service names must be listed in fluence.yaml | -| `spells` | string[] | No | An array of spell names to include in this worker. Spell names must be listed in fluence.yaml | -| `targetWorkers` | integer | No | Max workers in the deal | -| `whitelist` | string[] | No | Whitelist of providers to deploy to. Can't be used together with blacklist | +| Property | Type | Required | Description | +|-------------------------|----------|----------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `blacklist` | string[] | No | Blacklist of providers to deploy to. Can't be used together with whitelist | +| `computeUnits` | integer | No | DEPRECATED. USE cuCountPerWorker INSTEAD. Number of compute units you require. 1 compute unit = 2GB. Currently the only allowed value is 1. This will change in the future. Default: 1 | +| `cuCountPerWorker` | integer | No | Number of compute units per worker. Default: 1 | +| `effectors` | string[] | No | Effector CIDs to be used in the deal. Must be a valid CID | +| `initialBalance` | string | No | Initial balance after deploy in USDC. Default: targetWorkers * pricePerCuPerEpoch * minDealDepositedEpochs. For local environment: enough for deal to be active for 1 day | +| `maxWorkersPerProvider` | integer | No | Max workers per provider. Matches target workers by default | +| `minWorkers` | integer | No | Required workers to activate the deal. Matches target workers by default | +| `pricePerCuPerEpoch` | string | No | Price per compute unit per epoch in USDC | +| `protocolVersion` | integer | No | Protocol version. Default: 1 | +| `services` | string[] | No | An array of service names to include in this worker. Service names must be listed in fluence.yaml | +| `spells` | string[] | No | An array of spell names to include in this worker. Spell names must be listed in fluence.yaml | +| `targetWorkers` | integer | No | Max workers in the deal | +| `whitelist` | string[] | No | Whitelist of providers to deploy to. Can't be used together with blacklist | ## hosts diff --git a/cli/docs/configs/provider.md b/cli/docs/configs/provider.md index cdd65adb5..88f525532 100644 --- a/cli/docs/configs/provider.md +++ b/cli/docs/configs/provider.md @@ -249,8 +249,8 @@ Effector configuration | Property | Type | Required | Description | |-------------------|----------------------------|----------|--------------------------| -| `allowedBinaries` | [object](#allowedbinaries) | **Yes** | Allowed binaries | | `wasmCID` | string | **Yes** | Wasm CID of the effector | +| `allowedBinaries` | [object](#allowedbinaries) | No | Allowed binaries | **allowedBinaries** @@ -440,8 +440,8 @@ Effector configuration | Property | Type | Required | Description | |-------------------|----------------------------|----------|--------------------------| -| `allowedBinaries` | [object](#allowedbinaries) | **Yes** | Allowed binaries | | `wasmCID` | string | **Yes** | Wasm CID of the effector | +| `allowedBinaries` | [object](#allowedbinaries) | No | Allowed binaries | ##### allowedBinaries diff --git a/cli/package.json b/cli/package.json index 3f8481f12..770c0bd0d 100644 --- a/cli/package.json +++ b/cli/package.json @@ -74,6 +74,7 @@ "@oclif/plugin-update": "4.2.11", "@total-typescript/ts-reset": "0.5.1", "ajv": "8.13.0", + "ajv-formats": "^3.0.1", "chokidar": "3.6.0", "countly-sdk-nodejs": "22.6.0", "debug": "4.3.4", diff --git a/cli/src/commands/provider/cc-collateral-withdraw.ts b/cli/src/commands/provider/cc-collateral-withdraw.ts index 5815e2812..142dafdcb 100644 --- a/cli/src/commands/provider/cc-collateral-withdraw.ts +++ b/cli/src/commands/provider/cc-collateral-withdraw.ts @@ -25,11 +25,13 @@ import { } from "../../lib/const.js"; import { initCli } from "../../lib/lifeCycle.js"; +// Deprecated alias for provider cc-finish export default class CCCollateralWithdraw extends BaseCommand< typeof CCCollateralWithdraw > { + static override hidden = true; static override aliases = ["provider:ccw"]; - static override description = `Withdraw ${FLT_SYMBOL} collateral from capacity commitments`; + static override description = `Move resources from deals, withdraw ${FLT_SYMBOL} collateral from capacity commitments, remove compute units from capacity commitments and finish capacity commitments`; static override flags = { ...baseFlags, ...CC_FLAGS, diff --git a/cli/src/commands/provider/cc-finish.ts b/cli/src/commands/provider/cc-finish.ts new file mode 100644 index 000000000..1095f6ff8 --- /dev/null +++ b/cli/src/commands/provider/cc-finish.ts @@ -0,0 +1,42 @@ +/** + * Fluence CLI + * Copyright (C) 2024 Fluence DAO + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import { BaseCommand, baseFlags } from "../../baseCommand.js"; +import { collateralWithdraw } from "../../lib/chain/commitment.js"; +import { + CHAIN_FLAGS, + FLT_SYMBOL, + CC_FLAGS, + MAX_CUS_FLAG, +} from "../../lib/const.js"; +import { initCli } from "../../lib/lifeCycle.js"; + +export default class CCFinish extends BaseCommand { + static override aliases = ["provider:ccf"]; + static override description = `Move resources from deals, withdraw ${FLT_SYMBOL} collateral from capacity commitments, remove compute units from capacity commitments and finish capacity commitments`; + static override flags = { + ...baseFlags, + ...CC_FLAGS, + ...CHAIN_FLAGS, + ...MAX_CUS_FLAG, + }; + + async run(): Promise { + const { flags } = await initCli(this, await this.parse(CCFinish)); + await collateralWithdraw(flags); + } +} diff --git a/cli/src/commands/provider/init.ts b/cli/src/commands/provider/init.ts index aeb8549f4..0a792a617 100644 --- a/cli/src/commands/provider/init.ts +++ b/cli/src/commands/provider/init.ts @@ -16,6 +16,7 @@ */ import { color } from "@oclif/color"; +import { Flags } from "@oclif/core"; import { BaseCommand, baseFlags } from "../../baseCommand.js"; import { commandObj } from "../../lib/commandObj.js"; @@ -36,6 +37,10 @@ export default class Init extends BaseCommand { ...baseFlags, ...NOXES_FLAG, ...CHAIN_FLAGS, + "no-vm": Flags.boolean({ + description: `Generate ${PROVIDER_CONFIG_FULL_FILE_NAME} without vm configuration`, + default: false, + }), }; async run(): Promise { diff --git a/cli/src/lib/ajvInstance.ts b/cli/src/lib/ajvInstance.ts index 6e161076c..8554efaa2 100644 --- a/cli/src/lib/ajvInstance.ts +++ b/cli/src/lib/ajvInstance.ts @@ -17,6 +17,7 @@ import { color } from "@oclif/color"; import Ajv from "ajv"; +import addFormats from "ajv-formats"; import { jsonStringify } from "../common.js"; @@ -27,6 +28,8 @@ export const ajv = new Ajv.default({ code: { esm: true }, }); +addFormats.default(ajv); + type AjvErrors = | Ajv.ErrorObject>[] | null diff --git a/cli/src/lib/configs/initConfig.ts b/cli/src/lib/configs/initConfig.ts index aa3cd8cf6..acad15fde 100644 --- a/cli/src/lib/configs/initConfig.ts +++ b/cli/src/lib/configs/initConfig.ts @@ -306,16 +306,21 @@ export function getReadonlyConfigInitFunction< let { configPath } = getConfigPathResult; const Ajv = (await import("ajv")).default; + const addFormats = (await import("ajv-formats")).default.default; - const validateAllConfigVersions = new Ajv.default({ - allowUnionTypes: true, - }).compile({ + const validateAllConfigVersions = addFormats( + new Ajv.default({ + allowUnionTypes: true, + }), + ).compile({ oneOf: allSchemas, }); - const validateLatestConfig = new Ajv.default({ - allowUnionTypes: true, - }).compile(latestSchema); + const validateLatestConfig = addFormats( + new Ajv.default({ + allowUnionTypes: true, + }), + ).compile(latestSchema); const schemaPathCommentStart = "# yaml-language-server: $schema="; diff --git a/cli/src/lib/configs/project/fluence.ts b/cli/src/lib/configs/project/fluence.ts index 576950080..0b6734834 100644 --- a/cli/src/lib/configs/project/fluence.ts +++ b/cli/src/lib/configs/project/fluence.ts @@ -35,6 +35,7 @@ import CLIPackageJSON from "../../../versions/cli.package.json" assert { type: " import { versions } from "../../../versions.js"; import { ajv, validationErrorToString } from "../../ajvInstance.js"; import { validateProtocolVersion } from "../../chain/chainValidators.js"; +import { commandObj } from "../../commandObj.js"; import { COMPUTE_UNIT_MEMORY_STR, MAX_HEAP_SIZE_DESCRIPTION, @@ -286,7 +287,7 @@ const dealSchemaObj = { minimum: 1, maximum: 1, default: 1, - description: `Number of compute units you require. 1 compute unit = ${COMPUTE_UNIT_MEMORY_STR}. Currently the only allowed value is 1. This will change in the future. Default: 1`, + description: `DEPRECATED. USE cuCountPerWorker INSTEAD. Number of compute units you require. 1 compute unit = ${COMPUTE_UNIT_MEMORY_STR}. Currently the only allowed value is 1. This will change in the future. Default: 1`, nullable: true, }, targetWorkers: { @@ -1733,6 +1734,26 @@ async function validateProtocolVersions(config: LatestConfig) { return true; } +function warnComputeUnitsIsDeprecated(config: LatestConfig): true { + const deploymentsWithWarning = Object.entries( + config.deployments ?? {}, + ).filter(([, deployment]) => { + return "computeUnits" in deployment; + }); + + if (deploymentsWithWarning.length > 0) { + commandObj.warn( + `'computeUnits' property is deprecated. Use 'cuCountPerWorker' instead. Deployment(s): ${deploymentsWithWarning + .map(([deploymentName]) => { + return deploymentName; + }) + .join(", ")}`, + ); + } + + return true; +} + const validate: ConfigValidateFunction = async (config) => { return validateBatchAsync( validateNotBothBlacklistAndWhitelist(config), @@ -1754,6 +1775,7 @@ const validate: ConfigValidateFunction = async (config) => { validateVersionsIsExact("marineVersion", config.marineVersion), validateVersionsIsExact("mreplVersion", config.mreplVersion), validateProtocolVersions(config), + warnComputeUnitsIsDeprecated(config), ); }; diff --git a/cli/src/lib/configs/project/provider.ts b/cli/src/lib/configs/project/provider.ts index a68a02ae8..d0c57e6a8 100644 --- a/cli/src/lib/configs/project/provider.ts +++ b/cli/src/lib/configs/project/provider.ts @@ -39,7 +39,7 @@ import { validateAddress, validateProtocolVersion, } from "../../chain/chainValidators.js"; -import { commandObj } from "../../commandObj.js"; +import { commandObj, isInteractive } from "../../commandObj.js"; import { COMPUTE_UNIT_MEMORY_STR, DEFAULT_OFFER_NAME, @@ -66,6 +66,7 @@ import { CHAIN_URLS_FOR_CONTAINERS, CLI_NAME, DEFAULT_NUMBER_OF_LOCAL_NET_NOXES, + DEFAULT_VM_EFFECTOR_CID, } from "../../const.js"; import { ensureChainEnv } from "../../ensureChainNetwork.js"; import { type ProviderConfigArgs } from "../../generateUserProviderConfig.js"; @@ -86,7 +87,7 @@ import { ensureFluenceSecretsFilePath, ensureFluenceCCPConfigsDir, } from "../../paths.js"; -import { list } from "../../prompt.js"; +import { input, list } from "../../prompt.js"; import { setEnvConfig } from "../globalConfigs.js"; import { getReadonlyConfigInitFunction, @@ -175,7 +176,7 @@ export type OfferV0 = { type Effector = { wasmCID: string; - allowedBinaries: Record; + allowedBinaries?: Record; }; type NoxConfigYAMLV0 = { @@ -231,9 +232,10 @@ const effectorSchema = { curl: { type: "string" }, }, required: [], + nullable: true, }, }, - required: ["wasmCID", "allowedBinaries"], + required: ["wasmCID"], } as const satisfies JSONSchemaType; const noxConfigYAMLSchemaV0 = { @@ -721,6 +723,7 @@ const noxConfigYAMLSchemaV1 = { listenIp: { nullable: true, type: "string", + format: "ipv4", description: `IP to listen on`, }, externalMultiaddresses: { @@ -804,11 +807,13 @@ const noxConfigYAMLSchemaV1 = { publicIp: { nullable: false, type: "string", + format: "ipv4", description: `Public IP address to assign the VM. Must be publicly accessible.`, }, vmIp: { nullable: true, type: "string", + format: "ipv4", description: `Internal IP address to assign the VM`, }, portRange: { @@ -1317,11 +1322,22 @@ const latestConfigSchema: JSONSchemaType = { ...latestConfigSchemaObj, }; -function getDefault(args: Omit) { +const ipValidator = ajv.compile({ + type: "string", + format: "ipv4", +}); + +function validateIp(value: string) { + return ipValidator(value) ? true : "Must be a valid IPv4 address"; +} + +function getDefault(args: ProviderConfigArgs) { return async () => { const { yamlDiffPatch } = await import("yaml-diff-patch"); const chainEnv = await ensureChainEnv(); setEnvConfig(await initNewEnvConfig(chainEnv)); + const isLocal = chainEnv === "local"; + const hasVM = !isLocal && args["no-vm"] !== true; const userProvidedConfig: UserProvidedConfig = { providerName: "defaultProvider", @@ -1329,10 +1345,9 @@ function getDefault(args: Omit) { effectors: { curl: { wasmCID: DEFAULT_CURL_EFFECTOR_CID, - allowedBinaries: { - curl: "/usr/bin/curl", - }, + allowedBinaries: { curl: "/usr/bin/curl" }, }, + ...(hasVM ? { vm: { wasmCID: DEFAULT_VM_EFFECTOR_CID } } : {}), }, }, computePeers: {}, @@ -1340,17 +1355,51 @@ function getDefault(args: Omit) { capacityCommitments: {}, }; - // For now we remove interactive mode cause it's too complex and unnecessary - // if (envConfig?.fluenceEnv === "local") { + const numberOfNoxes = + args.noxes ?? + (isInteractive && !isLocal + ? Number( + await input({ + message: `Enter number of compute peers you want to set up`, + validate(value) { + return Number.isInteger(Number(value)) && Number(value) > 0 + ? true + : "Must be a positive integer"; + }, + }), + ) + : DEFAULT_NUMBER_OF_LOCAL_NET_NOXES); + + const computePeerEntries: [string, LatestComputePeer][] = []; + + for (const i of times(numberOfNoxes)) { + const peerConfig = hasVM + ? { + nox: { + vm: { + network: { + publicIp: isInteractive + ? await input({ + message: `Enter public IP address for nox-${numToStr(i)}`, + validate: validateIp, + }) + : "", + }, + }, + }, + } + : {}; + + computePeerEntries.push([ + `nox-${numToStr(i)}`, + { + computeUnits: DEFAULT_NUMBER_OF_COMPUTE_UNITS_ON_NOX, + ...peerConfig, + }, + ] as const); + } - userProvidedConfig.computePeers = Object.fromEntries( - times(args.noxes ?? DEFAULT_NUMBER_OF_LOCAL_NET_NOXES).map((i) => { - return [ - `nox-${numToStr(i)}`, - { computeUnits: DEFAULT_NUMBER_OF_COMPUTE_UNITS_ON_NOX }, - ] as const; - }), - ); + userProvidedConfig.computePeers = Object.fromEntries(computePeerEntries); userProvidedConfig.capacityCommitments = Object.fromEntries( Object.keys(userProvidedConfig.computePeers).map((noxName) => { @@ -1368,15 +1417,13 @@ function getDefault(args: Omit) { [DEFAULT_OFFER_NAME]: { ...defaultNumberProperties, computePeers: Object.keys(userProvidedConfig.computePeers), - effectors: [DEFAULT_CURL_EFFECTOR_CID], + effectors: [ + DEFAULT_CURL_EFFECTOR_CID, + ...(hasVM ? [DEFAULT_VM_EFFECTOR_CID] : []), + ], }, }; - // } else { - // await addComputePeers(args.noxes, userProvidedConfig); - // await addOffers(userProvidedConfig); - // } - return `# Defines Provider configuration # You can use \`fluence provider init\` command to generate this config template @@ -1504,6 +1551,7 @@ function migrateChainConfigV0ToV1( ); } +type LatestComputePeer = ComputePeerV1; type Config = ConfigV0 | ConfigV1 | ConfigV2 | ConfigV3; type LatestConfig = ConfigV3; type LatestCCPConfigYAML = CCPConfigYAMLV1; @@ -1631,16 +1679,37 @@ export async function validateEffectors( computePeer.nox, ); - const computePeerEffectorsString = jsonStringify( - [ - ...Object.values(noxConfig.effectors ?? {}).map( - ({ wasmCID }) => { - return wasmCID; - }, - ), - ].sort(), + const computePeerEffectors = [ + ...Object.values(noxConfig.effectors ?? {}).map(({ wasmCID }) => { + return wasmCID; + }), + ].sort(); + + const hasDefaultVmEffector = computePeerEffectors.includes( + DEFAULT_VM_EFFECTOR_CID, ); + if ( + noxConfig.vm?.network.publicIp !== undefined && + !hasDefaultVmEffector + ) { + return `Compute peer ${color.yellow( + computePeerName, + )} has a defined publicIp property:\n\nvm:\n network:\n publicIp: ${noxConfig.vm.network.publicIp}\n\nso it is expected to also have a vm effector:\n\neffectors:\n vm:\n wasmCID: ${DEFAULT_VM_EFFECTOR_CID}`; + } + + if ( + noxConfig.vm?.network.publicIp === undefined && + hasDefaultVmEffector + ) { + return `Compute peer ${color.yellow( + computePeerName, + )} has a vm effector:\n\neffectors:\n vm:\n wasmCID: ${DEFAULT_VM_EFFECTOR_CID}\n\nso it is expected to also have a defined publicIp property:\n\nvm:\n network:\n publicIp: `; + } + + const computePeerEffectorsString = + jsonStringify(computePeerEffectors); + if (computePeerEffectorsString !== offerEffectorsString) { return `Offer ${color.yellow( offerName, @@ -1662,13 +1731,7 @@ export async function validateEffectors( return typeof result === "string"; }); - if (errors.length > 0) { - return `Each offer must contain computePeers with matching effectors. Found not matching ones:\n\n${errors.join( - "\n\n", - )}`; - } - - return true; + return errors.length > 0 ? errors.join("\n\n") : true; } function validateNoDuplicateNoxNamesInOffers( @@ -1950,6 +2013,7 @@ function noxConfigYAMLToConfigToml( ccp, listenIp, metrics, + effectors, ...config }: LatestNoxConfigYAML, ccpConfig: LatestCCPConfigYAML, @@ -1989,10 +2053,20 @@ function noxConfigYAMLToConfigToml( tokioDetailedMetricsEnabled: metrics?.tokioDetailedMetricsEnabled, metricsEnabled: metrics?.enabled, metricsTimerResolution: metrics?.timerResolution, - - // TODO: set up properly in the schema - // systemCpuCount: 1, - // cpusRange: ranges[((config.tcpPort ?? 1) - 1) % ranges.length], + ...(effectors === undefined + ? {} + : { + effectors: Object.fromEntries( + Object.entries(effectors).map( + ([name, { wasmCID, allowedBinaries }]) => { + return [ + name, + { wasmCID, allowedBinaries: allowedBinaries ?? {} }, + ] as const; + }, + ), + ), + }), }) as JsonMap; } diff --git a/cli/src/lib/const.ts b/cli/src/lib/const.ts index 515592626..bd0551e84 100644 --- a/cli/src/lib/const.ts +++ b/cli/src/lib/const.ts @@ -78,6 +78,9 @@ export const COMPUTE_UNIT_MEMORY = xbytes.parseSize(COMPUTE_UNIT_MEMORY_STR); export const DEFAULT_CURL_EFFECTOR_CID = "bafybeicorj3sl6fhqpuubmt5r2n7plkjkmto6jxqckgte2624dj5zvzufm"; +export const DEFAULT_VM_EFFECTOR_CID = + "bafkreidfw2so3evkkkky7bodnamzg32zweunfkthna362r7e6a63cnqxiy"; + const byteUnits = [ "kB", "KB", diff --git a/cli/src/lib/deal.ts b/cli/src/lib/deal.ts index d5a7c2611..ce1b636ba 100644 --- a/cli/src/lib/deal.ts +++ b/cli/src/lib/deal.ts @@ -217,13 +217,23 @@ export async function createAndMatchDealsForPeerIds({ } try { - const dealAddress = await dealCreate(dealCreateArgs); + const dealAddress = await dealCreate({ + ...dealCreateArgs, + targetWorkers: 1, + minWorkers: 1, + }); + + commandObj.logToStderr(`Deal ${color.yellow(dealAddress)} created`); await sign({ title: `Match deal ${dealAddress} with compute units:\n\n${CUs.join("\n")}\n\nfrom offer ${offerId}`, method: market.matchDeal, args: [dealAddress, [offerId], [[CUs]]], }); + + commandObj.logToStderr( + `Deal ${color.yellow(dealAddress)} matched with peer ${color.yellow(peerId)}. Offer: ${color.yellow(offerId)} (${color.yellow(CUs.length)} compute units)`, + ); } catch (e) { commandObj.error( `Couldn't create or match deal for peer ${color.yellow(peerId)}: ${stringifyUnknown(e)}`, diff --git a/cli/src/lib/deployWorkers.ts b/cli/src/lib/deployWorkers.ts index cde942980..fa4a07cf1 100644 --- a/cli/src/lib/deployWorkers.ts +++ b/cli/src/lib/deployWorkers.ts @@ -945,8 +945,9 @@ async function resolveDeployment({ ); const workerMemory = - ("computeUnits" in deploymentConfig ? deploymentConfig.computeUnits : 1) * - COMPUTE_UNIT_MEMORY; + ("cuCountPerWorker" in deploymentConfig + ? deploymentConfig.cuCountPerWorker + : 1) * COMPUTE_UNIT_MEMORY; if (specifiedServicesMemoryLimit > workerMemory) { throwMemoryExceedsError( diff --git a/cli/src/lib/generateUserProviderConfig.ts b/cli/src/lib/generateUserProviderConfig.ts index 00a3636ae..8573d834c 100644 --- a/cli/src/lib/generateUserProviderConfig.ts +++ b/cli/src/lib/generateUserProviderConfig.ts @@ -59,6 +59,7 @@ const DEFAULT_NUMBER_OF_NOXES = 3; export type ProviderConfigArgs = { noxes?: number | undefined; + "no-vm"?: boolean | undefined; }; export async function addComputePeers( diff --git a/cli/src/lib/helpers/validations.ts b/cli/src/lib/helpers/validations.ts index 418c42643..39f71a801 100644 --- a/cli/src/lib/helpers/validations.ts +++ b/cli/src/lib/helpers/validations.ts @@ -149,7 +149,7 @@ export async function validateCIDs( ); if (errors.length > 0) { - return `Invalid CIDs:\n\n${errors.join("\n\n")}`; + return `\nInvalid CIDs:\n\n${errors.join("\n\n")}`; } return true; diff --git a/cli/yarn.lock b/cli/yarn.lock index 57ef3a1fc..e9cac136c 100644 --- a/cli/yarn.lock +++ b/cli/yarn.lock @@ -462,6 +462,7 @@ __metadata: "@types/semver": "npm:7.5.8" "@types/tar": "npm:6.1.13" ajv: "npm:8.13.0" + ajv-formats: "npm:^3.0.1" chokidar: "npm:3.6.0" countly-sdk-nodejs: "npm:22.6.0" debug: "npm:4.3.4" @@ -3494,6 +3495,20 @@ __metadata: languageName: node linkType: hard +"ajv-formats@npm:^3.0.1": + version: 3.0.1 + resolution: "ajv-formats@npm:3.0.1" + dependencies: + ajv: "npm:^8.0.0" + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + checksum: 10c0/168d6bca1ea9f163b41c8147bae537e67bd963357a5488a1eaf3abe8baa8eec806d4e45f15b10767e6020679315c7e1e5e6803088dfb84efa2b4e9353b83dd0a + languageName: node + linkType: hard + "ajv@npm:8.13.0": version: 8.13.0 resolution: "ajv@npm:8.13.0" @@ -3518,6 +3533,18 @@ __metadata: languageName: node linkType: hard +"ajv@npm:^8.0.0": + version: 8.17.1 + resolution: "ajv@npm:8.17.1" + dependencies: + fast-deep-equal: "npm:^3.1.3" + fast-uri: "npm:^3.0.1" + json-schema-traverse: "npm:^1.0.0" + require-from-string: "npm:^2.0.2" + checksum: 10c0/ec3ba10a573c6b60f94639ffc53526275917a2df6810e4ab5a6b959d87459f9ef3f00d5e7865b82677cb7d21590355b34da14d1d0b9c32d75f95a187e76fff35 + languageName: node + linkType: hard + "ansi-align@npm:^3.0.1": version: 3.0.1 resolution: "ansi-align@npm:3.0.1" @@ -6208,6 +6235,13 @@ __metadata: languageName: node linkType: hard +"fast-uri@npm:^3.0.1": + version: 3.0.1 + resolution: "fast-uri@npm:3.0.1" + checksum: 10c0/3cd46d6006083b14ca61ffe9a05b8eef75ef87e9574b6f68f2e17ecf4daa7aaadeff44e3f0f7a0ef4e0f7e7c20fc07beec49ff14dc72d0b500f00386592f2d10 + languageName: node + linkType: hard + "fastest-levenshtein@npm:^1.0.16, fastest-levenshtein@npm:^1.0.7": version: 1.0.16 resolution: "fastest-levenshtein@npm:1.0.16"