UNPKG

@massalabs/massa-sc-utils

Version:
187 lines (185 loc) 9.88 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.deployWebsite = void 0; const tslib_1 = require("tslib"); const massa_web3_1 = require("@massalabs/massa-web3"); const SmartContractDeployer_1 = require("./SmartContractDeployer"); const path = require("path"); const fs = require("fs"); const chalk = require("chalk"); const Handlebars = require("handlebars"); const INIT_SC = `import { generate_event, create_sc, Storage } from 'massa-sc-std'; function initWebsite(): string { const bytes = '{{bytes}}'; const sc_address = create_sc(bytes); return sc_address; } export function main(_args: string): i32 { const sc_address = initWebsite(); const eventMsg = "Address:" + sc_address; generate_event(eventMsg); return 0; } `; const CHUNK_SC = `import { generate_event, Storage } from 'massa-sc-std'; function appendBytesToWebsite(): void { const bytes = '{{bytes}}'; Storage.append_data_for('{{scAddress}}', 'massa_web', bytes); } export function main(_args: string): i32 { appendBytesToWebsite(); generate_event('Appended bytes chunk {{chunkIndex}} for contract@address: {{scAddress}}'); return 0; } `; const DEFAULT_MAX_BLOCK_BYTES = 50000; const initScTemplate = Handlebars.compile(INIT_SC); const appendChunksToScTemplate = Handlebars.compile(CHUNK_SC); const deployInitialScChunk = (websiteZipFile, chunkBase64Bytes, chunkIndex, tempASFiles, contractData, web3Client, deployerAccount, max_block_bytes) => tslib_1.__awaiter(void 0, void 0, void 0, function* () { const batchBytes = chunkBase64Bytes.substring(0, max_block_bytes); const scToCompile = initScTemplate({ bytes: batchBytes }); const tempFileName = `temp-${path.basename(websiteZipFile)}-${chunkIndex}.ts`; const scDeployFileTemp = `${path.dirname(websiteZipFile)}/${tempFileName}`; tempASFiles.push(scDeployFileTemp); fs.writeFileSync(scDeployFileTemp, scToCompile, { flag: "w+" }); const opId = yield (0, SmartContractDeployer_1.deploySmartContract)(scDeployFileTemp, contractData, web3Client, true, deployerAccount); return opId; }); const deploySuccessiveScChunk = (websiteZipFile, chunkBase64Bytes, chunkIndex, tempASFiles, contractData, web3Client, deployerAccount, scAddress, max_block_bytes) => tslib_1.__awaiter(void 0, void 0, void 0, function* () { const batchBytes = chunkBase64Bytes.substring(0, max_block_bytes); const scToCompile = appendChunksToScTemplate({ bytes: batchBytes, chunkIndex: chunkIndex, scAddress: scAddress }); const tempFileName = `temp-${path.basename(websiteZipFile)}-${chunkIndex}.ts`; const scDeployFileTemp = `${path.dirname(websiteZipFile)}/${tempFileName}`; tempASFiles.push(scDeployFileTemp); fs.writeFileSync(scDeployFileTemp, scToCompile, { flag: "w+" }); const opId = yield (0, SmartContractDeployer_1.deploySmartContract)(scDeployFileTemp, contractData, web3Client, true, deployerAccount); return opId; }); const deployWebsite = (websiteZipFile, contractData, web3Client, awaitFinalization, deployerAccount) => tslib_1.__awaiter(void 0, void 0, void 0, function* () { const header = "=".repeat(process.stdout.columns - 1); console.log(header); console.log(`Deploying website...`); console.log(header); const tempASFiles = []; const deploymentTxOpIds = []; try { // do checks if (!deployerAccount.address) { const msg = chalk.red(`Missing deployer account. Maybe you forgot to add one ?`); console.error(msg); throw new Error(msg); } // set default values in case of missing ones contractData.maxGas = contractData.maxGas || 200000; contractData.fee = contractData.fee || 0; contractData.datastore = new Map(); // compute current max block size and take max 50% of its capacity let max_block_bytes = DEFAULT_MAX_BLOCK_BYTES; try { const max_block_size_massa = (yield web3Client.publicApi().getNodeStatus()).config.max_block_size; console.log(`Massa max. block size = ${chalk.yellow(max_block_size_massa)}`); max_block_bytes = Math.floor(max_block_size_massa * 0.45); console.log(`Using max. block size = ${chalk.yellow(max_block_bytes)}`); } catch (ex) { const msg = chalk.red(`Could not determine the max block size. Using a default block size of ${DEFAULT_MAX_BLOCK_BYTES}`); console.warn(msg); } // read wasm file contents in base 64 const contents = fs.readFileSync(websiteZipFile, "base64"); const bytes = Buffer.byteLength(contents, "utf-8"); // split data into smaller batches if necessary const nBatches = Math.floor(bytes / max_block_bytes); console.log(`Wasm File will be split into ${nBatches} files`); const lastBatchPortion = bytes % max_block_bytes; if (nBatches > 0) { // deploy the very first chunk to get the new sc address let deploymentOperationId = null; try { deploymentOperationId = yield deployInitialScChunk(websiteZipFile, contents.substring(0, max_block_bytes), 0, tempASFiles, contractData, web3Client, deployerAccount, max_block_bytes); deploymentTxOpIds.push(deploymentOperationId); } catch (ex) { const msg = chalk.red(`Error deploying first sc chunk`); console.error(msg); throw new Error(ex); } // await final state console.log(`Awaiting ${chalk.green("FINAL")} transaction status....`); let status; try { status = yield web3Client.smartContracts().awaitRequiredOperationStatus(deploymentOperationId, massa_web3_1.EOperationStatus.FINAL); console.log(`Transaction with Operation ID ${chalk.yellow(deploymentOperationId)} has reached finality!`); } catch (ex) { const msg = chalk.red(`Error getting finality of transaction ${chalk.yellow(deploymentOperationId)}`); console.error(msg); throw new Error(ex); } if (status !== massa_web3_1.EOperationStatus.FINAL) { const msg = chalk.red(`Transaction ${chalk.yellow(deploymentOperationId)} did not reach finality after considerable amount of time. Try redeploying anew`); console.error(msg); throw new Error(msg); } // poll smart contract events for the opId and find an event that contains the emitted sc address console.log(`Getting smart contract address...`); let scAddress; try { const eventsFilter = { start: null, end: null, original_caller_address: null, original_operation_id: deploymentOperationId, emitter_address: null, }; const events = yield massa_web3_1.EventPoller.getEventsOnce(eventsFilter, web3Client); const addressEvent = events.find(event => event.data.includes("Address:")); if (!addressEvent) { throw new Error("No events were emitted from contract containing a message `Address:...`. Please make sure to include such a message in order to fetch the sc address"); } scAddress = addressEvent.data.split(":")[1]; console.log(`Smart Contract Address = ${chalk.yellow(scAddress)}`); } catch (ex) { const msg = chalk.red(`Error getting smart contract address. Maybe you forgot to emit an event of the type "Address:xyz" ?`); console.error(msg); throw new Error(msg); } // loop over the remaining chunks and deploy them by appending let startBatch = max_block_bytes; let endBatch = 0; for (let chunkIndex = 1; chunkIndex < nBatches - 1; chunkIndex++) { endBatch = startBatch + max_block_bytes; const batchBytes = contents.substring(startBatch, endBatch); console.log(`Next Bytes Batch ${chunkIndex} - length ${batchBytes.length} bytes`); deploymentTxOpIds.push(yield deploySuccessiveScChunk(websiteZipFile, batchBytes, chunkIndex, tempASFiles, contractData, web3Client, deployerAccount, scAddress, max_block_bytes)); startBatch = endBatch; } console.log(`Final Batch ${nBatches} - length ${contents.substring(endBatch).length} bytes`); deploymentTxOpIds.push(yield deploySuccessiveScChunk(websiteZipFile, contents.substring(endBatch), nBatches, tempASFiles, contractData, web3Client, deployerAccount, scAddress, max_block_bytes)); } else { console.log(`Single Batch ${0} - length ${lastBatchPortion} bytes`); deploymentTxOpIds.push(yield deployInitialScChunk(websiteZipFile, contents, 0, tempASFiles, contractData, web3Client, deployerAccount, max_block_bytes)); } } catch (ex) { const msg = chalk.red(`Error deploying website zip file ${chalk.yellow(websiteZipFile)} to Massa Network`); console.error(msg); throw new Error(ex); } finally { // delete temp .ts files for (let tempFileIndex = 0; tempFileIndex < tempASFiles.length; tempFileIndex++) { if (fs.existsSync(tempASFiles[tempFileIndex])) { //fs.unlinkSync(tempASFiles[tempFileIndex]); } } } console.log(header); console.log(`Website Deployment finished!`); console.log(header); return deploymentTxOpIds; }); exports.deployWebsite = deployWebsite; //# sourceMappingURL=WebsiteDeployer.js.map