UNPKG

@iexec/iapp

Version:

A CLI to guide you through the process of building an iExec iApp

175 lines (157 loc) 6.07 kB
import { dockerBuild, pushDockerImage, checkDockerDaemon, } from '../execDocker/docker.js'; import { sconify } from '../utils/sconify.js'; import { askForDockerhubUsername } from '../cli-helpers/askForDockerhubUsername.js'; import { getChainConfig, projectNameToImageName, readIAppConfig, } from '../utils/iAppConfigFile.js'; import { askForDockerhubAccessToken } from '../cli-helpers/askForDockerhubAccessToken.js'; import { handleCliError } from '../cli-helpers/handleCliError.js'; import { getSpinner } from '../cli-helpers/spinner.js'; import { askForAppSecret } from '../cli-helpers/askForAppSecret.js'; import { askForWallet } from '../cli-helpers/askForWallet.js'; import { getIExecDebug } from '../utils/iexec.js'; import { goToProjectRoot } from '../cli-helpers/goToProjectRoot.js'; import * as color from '../cli-helpers/color.js'; import { hintBox } from '../cli-helpers/box.js'; import { addDeploymentData } from '../utils/cacheExecutions.js'; import { deployTdxApp, getIExecTdx } from '../utils/tdx-poc.js'; import { useTdx } from '../utils/featureFlags.js'; import { ensureBalances } from '../cli-helpers/ensureBalances.js'; import { warnBeforeTxFees } from '../cli-helpers/warnBeforeTxFees.js'; export async function deploy({ chain }: { chain?: string }) { const spinner = getSpinner(); try { await goToProjectRoot({ spinner }); const { projectName, template, defaultChain } = await readIAppConfig(); const chainName = chain || defaultChain; const chainConfig = getChainConfig(chainName); spinner.info(`Using chain ${chainName}`); await warnBeforeTxFees({ spinner, chain: chainConfig.name }); const signer = await askForWallet({ spinner }); const userAddress = await signer.getAddress(); // initialize iExec let iexec; if (useTdx) { iexec = getIExecTdx({ ...chainConfig, signer }); } else { iexec = getIExecDebug({ ...chainConfig, signer }); } await ensureBalances({ spinner, iexec }); const dockerhubUsername = await askForDockerhubUsername({ spinner }); const dockerhubAccessToken = await askForDockerhubAccessToken({ spinner }); const { iAppVersion } = await spinner.prompt([ { type: 'text', name: 'iAppVersion', message: 'What is the version of your iApp?', initial: '0.0.1', }, ]); // validate image tag https://docs.docker.com/reference/cli/docker/image/tag/ if (!iAppVersion.match(/[\w][\w.-]{0,127}/)) { throw Error('Invalid version'); } const imageTag = `${dockerhubUsername}/${projectNameToImageName(projectName)}:${iAppVersion}`; const appSecret = await askForAppSecret({ spinner }); // just start the spinner, no need to persist success in terminal spinner.start('Checking docker daemon is running...'); await checkDockerDaemon(); spinner.start('Building docker image...\n'); const buildLogs = []; const imageId = await dockerBuild({ tag: imageTag, progressCallback: (msg) => { buildLogs.push(msg); // do we want to show build logs after build is successful? spinner.text = spinner.text + color.comment(msg); }, }); spinner.succeed(`Docker image built (${imageId}) and tagged ${imageTag}`); spinner.start('Pushing docker image...\n'); await pushDockerImage({ tag: imageTag, dockerhubAccessToken, dockerhubUsername, progressCallback: (msg) => { spinner.text = spinner.text + color.comment(msg); }, }); spinner.succeed(`Pushed image ${imageTag} on dockerhub`); let appDockerImage: string; let appContractAddress: string; if (useTdx && iexec) { spinner.start('Deploying your TDX TEE app on iExec...'); ({ tdxImage: appDockerImage, appContractAddress } = await deployTdxApp({ iexec, image: imageTag, dockerhubAccessToken, dockerhubUsername, })); } else { spinner.start( 'Transforming your image into a TEE image, this may take a few minutes...' ); const { dockerImage, dockerImageDigest, sconeVersion, fingerprint, entrypoint, } = await sconify({ iAppNameToSconify: imageTag, template, walletAddress: userAddress, dockerhubAccessToken, dockerhubUsername, }); appDockerImage = dockerImage; spinner.succeed(`Pushed TEE image ${appDockerImage} on dockerhub`); spinner.start('Deploying your TEE app on iExec...'); ({ address: appContractAddress } = await iexec.app.deployApp({ owner: userAddress, name: `${projectNameToImageName(projectName)}-${iAppVersion}`, type: 'DOCKER', multiaddr: dockerImage, checksum: `0x${dockerImageDigest}`, // Some code sample here: https://github.com/iExecBlockchainComputing/dataprotector-sdk/blob/v2/packages/protected-data-delivery-dapp/deployment/src/singleFunction/deployApp.ts mrenclave: { framework: 'SCONE', version: sconeVersion, entrypoint: entrypoint, heapSize: 1073741824, fingerprint, }, })); } // Add deployment data to deployments.json await addDeploymentData({ sconifiedImage: appDockerImage, appContractAddress: appContractAddress, owner: userAddress, chainName, }); spinner.succeed('TEE app deployed'); if (appSecret !== null && iexec) { spinner.start('Attaching app secret to the deployed app'); await iexec.app.pushAppSecret(appContractAddress, appSecret); spinner.succeed('App secret attached to the app'); } spinner.succeed( `Deployment of your iApp completed successfully: - Docker image: ${appDockerImage} - iApp address: ${appContractAddress}` ); spinner.log( hintBox( `Run ${color.command(`iapp run ${appContractAddress}`)} to execute your iApp on an iExec TEE worker` ) ); } catch (error) { handleCliError({ spinner, error }); } }