create-tezos-smart-contract
Version:
Node.js toolset to write, test and deploy Tezos smart contracts
199 lines (198 loc) • 7.64 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.isFlextesaRunning = exports.stopFlextesa = exports.startFlextesa = exports.POD_NAME = void 0;
const child_process_1 = require("child_process");
const console_1 = require("../../console");
const config_1 = require("../config");
const docker_1 = require("../docker");
const tezos_1 = require("../tezos");
const parameters_1 = require("./parameters");
// Flextesa image
const FLEXTESA_IMAGE = "oxheadalpha/flextesa:20220321";
// Name for the running Docker image
exports.POD_NAME = 'flextesa-sandbox';
const defaultProtocol = tezos_1.TezosProtocols.GRANADA;
const defaultOptions = config_1.defaultConfig.sandbox;
// This is to avoid printing flextesa full-console in output
const FLEXTESA_INPUT_COMMAND = "Flextesa: Please enter command:";
const FLEXTESA_MESSAGE_HEADER = /Flextesa:\n/igm;
const FLEXTESA_WARNING = /.+(?<=warning:( )*(\n)*).+/igm;
const FLEXTESA_ERROR = /.+(?<=(fatal-error:|error:)( )*(\n)*).+/igm;
const FLEXTESA_EXIT = "Last pause before the application will Kill 'Em All and Quit.";
const hasFlextesaMessage = (message) => {
const hasHeader = message.match(FLEXTESA_MESSAGE_HEADER);
return !!hasHeader && hasHeader.length > 0;
};
const handleFlextesaMessages = (str) => {
const message = str.replace(FLEXTESA_MESSAGE_HEADER, '');
if (message.includes(FLEXTESA_EXIT)) {
(0, console_1.error)("Flextesa failed to start all the needed services, now forcing shutdown...");
// stopFlextesa();
return true;
}
const lines = message.split('\n');
const output = [];
const l = (msg, fn) => ({ fn, msg });
let globalRenderer = console_1.debug;
for (const line of lines) {
const warnings = line.match(FLEXTESA_WARNING);
const errors = line.match(FLEXTESA_ERROR);
if (errors?.length) {
for (const err of errors) {
output.push(l(err, console_1.error));
}
globalRenderer = console_1.error;
}
if (warnings?.length) {
for (const warning of warnings) {
output.push(l(warning, console_1.warn));
}
if (globalRenderer !== console_1.error) {
globalRenderer = console_1.warn;
}
}
if (!warnings?.length && !errors?.length) {
output.push(l(line));
}
}
for (const log of output) {
const msg = log.msg.replace('\t', '');
if (log.fn) {
log.fn(msg);
}
else {
globalRenderer(msg);
}
}
return false;
};
const startFlextesa = async (_options, readyCallback) => {
(0, console_1.log)(`Preparing Flextesa sandbox...`);
const image = await (0, docker_1.ensureImageIsPresent)(FLEXTESA_IMAGE);
if (!image) {
(0, console_1.error)('Unable to find Flextesa image, compilation failed.');
return;
}
// Merge with defaults
const options = Object.assign({}, defaultOptions, _options);
// Localhost is not a valid host for Docker
const host = options.host === "localhost" ? "0.0.0.0" : options.host;
const port = options.port;
// Protocol "validity" checks
const protocol = (!options.protocol || !parameters_1.flextesaProtocols[options.protocol])
? defaultProtocol
: options.protocol;
const accountsParams = (0, parameters_1.createAccountsParams)(options.accounts || {});
const tezosNodeParams = (0, parameters_1.createProtocolParams)(protocol);
const args = [
"run",
"-i",
"--rm",
"--name",
exports.POD_NAME,
"-p",
host + ":" + port + ":20000",
"--env", "flextesa_node_cors_origin=*",
FLEXTESA_IMAGE,
"flextesa",
"mini-net",
"--genesis-block-hash", options.genesisBlockHash,
// "--remove-default-bootstrap-accounts"
/**
* Please don't use --remove-default-bootstrap-accounts in conjunction with
* --no-daemons-for on every added account. This would have Flextesa not baking
* anything, so the header block would be empty and Taquito does not really like it!
*/
"--time-between-blocks", "2",
// "--minimal-block-delay", "1",
"--pause-on-error=true",
...accountsParams,
...tezosNodeParams
];
const opts = {};
(0, console_1.debug)(`Starting Flextesa with these arguments:`);
(0, console_1.debug)("docker " + args.join(' '));
const flextesa = (0, child_process_1.spawn)("docker", args, opts);
let shouldStopLogging = false;
// Setup listeners for errors and close listeners to handle crashed during Flextesa boot
let stderr = "";
function onErrored(err) {
(0, console_1.error)("Flextesa running failed with:", err.message);
flextesa.removeListener("close", onClosed);
(0, exports.stopFlextesa)();
throw err;
}
async function onClosed(code) {
flextesa.removeListener("error", onErrored);
if (await (0, exports.isFlextesaRunning)()) {
(0, exports.stopFlextesa)();
}
if (code !== 0) {
(0, console_1.error)(`Flextesa exited with code ${code}.`);
}
}
flextesa.on("error", onErrored);
flextesa.on("close", onClosed);
flextesa.stderr.on("data", function fn(data) {
const str = data.toString();
stderr += str;
if (shouldStopLogging) {
stderr = "";
return;
}
// Print every message as it is, apart from flextesa warnings, errors and input command
if (hasFlextesaMessage(str)) {
shouldStopLogging = handleFlextesaMessages(str);
}
else if (str.indexOf(FLEXTESA_INPUT_COMMAND) == -1) {
// Let docker lib handle warnings
const hasWarnings = (0, docker_1.handleDockerWarnings)(str);
// if warnings weren't there, just print the messages
if (!hasWarnings) {
(0, console_1.debug)(str);
}
}
else { // But when we reach it, Flextsa is ready
// eslint-disable-next-line @typescript-eslint/no-unused-vars
stderr = "";
// unbind the now unused listeners for boot problems...
flextesa.removeListener("close", onClosed);
flextesa.removeListener("error", onErrored);
flextesa.stderr.removeListener("data", fn);
// Print general output
flextesa.stdout.on("data", (data) => {
(0, console_1.debug)(data.toString());
});
// Print standard flextesa output
flextesa.stderr.on("data", (data) => {
const str = data.toString();
(0, console_1.error)(str.replace(FLEXTESA_INPUT_COMMAND, ""));
});
(0, console_1.em)(`Tezos sandbox is ready!`);
if (readyCallback) {
readyCallback();
}
}
});
};
exports.startFlextesa = startFlextesa;
const stopFlextesa = (callback) => {
try {
(0, child_process_1.execSync)(`docker rm -f ${exports.POD_NAME}`);
}
catch (e) {
(0, console_1.error)('Stopping Flextesa thrown:', e);
}
callback && callback();
};
exports.stopFlextesa = stopFlextesa;
const isFlextesaRunning = async () => {
try {
const buffer = (0, child_process_1.execSync)(`docker ps -f name=${exports.POD_NAME} -q`);
return buffer.length !== 0;
}
catch (e) {
return false;
}
};
exports.isFlextesaRunning = isFlextesaRunning;