diff --git a/package-lock.json b/package-lock.json index 95e3265..f8104a1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -49,6 +49,19 @@ "integrity": "sha512-7qvf9F9tMTzo0akeswHPGqgUx/gIaJqrOEET/FCD8CFRkSUHlygQiM5yB6OvjrtdxBVLSyw7COJubsFYs0683g==", "dev": true }, + "@types/chalk": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@types/chalk/-/chalk-2.2.0.tgz", + "integrity": "sha512-1zzPV9FDe1I/WHhRkf9SNgqtRJWZqrBWgu7JGveuHmmyR9CnAPCie2N/x+iHrgnpYBIcCJWHBoMRv2TRWktsvw==", + "requires": { + "chalk": "*" + } + }, + "@types/color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==" + }, "@types/events": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz", @@ -406,21 +419,47 @@ } }, "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "dependencies": { + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "^4.0.0" } } } @@ -1113,6 +1152,26 @@ "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", "requires": { "chalk": "^2.0.1" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + } } }, "long": { @@ -1365,6 +1424,16 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, "log-symbols": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", @@ -1380,6 +1449,14 @@ "requires": { "ansi-regex": "^4.1.0" } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } } } }, diff --git a/package.json b/package.json index dccd2c2..8f3d0c3 100644 --- a/package.json +++ b/package.json @@ -5,10 +5,11 @@ "main": "lib/index.js", "types": "lib/index.d.ts", "scripts": { - "build": "npm run clean && tsc && npm run copy:scripts", + "build": "npm run clean && tsc && npm run copy:scripts && npm run copy:configs", "changelog": "auto-changelog --commit-limit false", "check:types": "tsc --noEmit", "copy:scripts": "cp -r ./src/scripts/ ./lib/scripts/", + "copy:configs": "cp -R ./src/eosio-config ./lib/eosio-config", "clean": "rm -rf ./lib", "docs": "typedoc --out api-docs ./src", "format": "prettier --write \"src/**/*.ts\" \"src/**/*.js\"", @@ -66,8 +67,10 @@ "typescript": "3.7.3" }, "dependencies": { + "@types/chalk": "^2.2.0", "axios": "0.19.0", "chai": "4.2.0", + "chalk": "^3.0.0", "clarify": "2.1.0", "colors": "1.4.0", "commander": "4.0.1", diff --git a/src/accounts/accountManager.ts b/src/accounts/accountManager.ts index f7e4d91..87b8141 100644 --- a/src/accounts/accountManager.ts +++ b/src/accounts/accountManager.ts @@ -149,7 +149,9 @@ export class AccountManager { }); } // Execute the transaction - return await EOSManager.transact({ actions }, eos); + return await EOSManager.transact({ actions }, eos, { + logMessage: `Creating account: ${account.name}}`, + }); }; /** diff --git a/src/cli/utils.ts b/src/cli/utils.ts index 43c7bf0..0d645b5 100644 --- a/src/cli/utils.ts +++ b/src/cli/utils.ts @@ -32,6 +32,8 @@ import * as spinner from './logIndicator'; /** @hidden Current working directory reference */ const WORKING_DIRECTORY = process.cwd(); +/** @hidden Config directory for running EOSIO */ +const CONFIG_DIRECTORY = path.join(__dirname, '../eosio-config'); /** @hidden Temporary docker resource directory */ const TEMP_DOCKER_DIRECTORY = path.join(__dirname, '.temp-docker'); /** @hidden Slowest Expected test duration */ @@ -134,6 +136,7 @@ export const startContainer = async () => { -p 9876:9876 --mount type=bind,src="${WORKING_DIRECTORY}",dst=/opt/eosio/bin/project --mount type=bind,src="${__dirname}/../scripts",dst=/opt/eosio/bin/scripts + --mount type=bind,src="${CONFIG_DIRECTORY}",dst=/mnt/dev/config -w "/opt/eosio/bin/" ${await dockerImageName()} /bin/bash -c "./scripts/init_blockchain.sh"` @@ -286,7 +289,7 @@ export const runTests = async () => { mocha.slow(TEST_EXPECTED_DURATION); mocha.timeout(TEST_TIMEOUT_DURATION); mocha.reporter(ConfigManager.testReporter); - mocha.bail(true); + mocha.bail(ConfigManager.bailOnFailure); // Run the tests. await new Promise((resolve, reject) => diff --git a/src/configManager.ts b/src/configManager.ts index 12fc1f9..87c9e87 100644 --- a/src/configManager.ts +++ b/src/configManager.ts @@ -33,13 +33,30 @@ export interface LamingtonConfig { debug: LamingtonDebugLevel; reporter?: string; reporterOptions?: any; + bailOnFailure: boolean; } -/** Level of debug output */ +/** + * Level of debug output + */ export enum LamingtonDebugLevel { - NONE = 0, - TRANSACTIONS, - ALL, + NONE = 0, // No debug logging + MINIMAL, // Brief summary of actions as executed + VERBOSE, // Verbose output from actions including all transaction output +} + +export namespace LamingtonDebugLevel { + export function isNone(debugLevel: LamingtonDebugLevel) { + return debugLevel == LamingtonDebugLevel.NONE; + } + + export function isMin(debugLevel: LamingtonDebugLevel) { + return debugLevel == LamingtonDebugLevel.MINIMAL; + } + + export function isVerbose(debugLevel: LamingtonDebugLevel) { + return debugLevel == LamingtonDebugLevel.VERBOSE; + } } /** @@ -56,6 +73,7 @@ const DEFAULT_CONFIG = { keepAlive: false, outDir: CACHE_DIRECTORY, exclude: [], + bailOnFailure: false, }; /** @@ -216,6 +234,31 @@ export class ConfigManager { ); } + /** + * Returns the container's debugLevel output setting + * @author Dallas Johnson + */ + static get debugLevel() { + return (ConfigManager.config && ConfigManager.config.debug) || DEFAULT_CONFIG.debug; + } + + /** + * Returns the container's debugLevel output setting + * @author Dallas Johnson + */ + + static get debugLevelNone() { + return LamingtonDebugLevel.isNone(this.debugLevel); + } + + static get debugLevelMin() { + return LamingtonDebugLevel.isMin(this.debugLevel); + } + + static get debugLevelVerbose() { + return LamingtonDebugLevel.isVerbose(this.debugLevel); + } + /** * Returns the output build directory or [[CACHE_DIRECTORY]] * @author Mitch Pierias @@ -239,4 +282,14 @@ export class ConfigManager { static get testReporter() { return (ConfigManager.config && ConfigManager.config.reporter) || Mocha.reporters.Min; } + + /** + * Returns the array of excluded strings or patterns + * @author Dallas Johnson + */ + static get bailOnFailure() { + return ( + (ConfigManager.config && ConfigManager.config.bailOnFailure) || DEFAULT_CONFIG.bailOnFailure + ); + } } diff --git a/src/eosManager.ts b/src/eosManager.ts index cf094bb..a7c8766 100644 --- a/src/eosManager.ts +++ b/src/eosManager.ts @@ -3,8 +3,10 @@ import { TextEncoder, TextDecoder } from 'util'; import { Api, JsonRpc } from 'eosjs'; import { JsSignatureProvider } from 'eosjs/dist/eosjs-jssig'; import { Account } from './accounts'; -import { ConfigManager } from './configManager'; +import { ConfigManager, LamingtonDebugLevel } from './configManager'; import { convertLegacyPublicKey } from 'eosjs/dist/eosjs-numeric'; +import { timer } from './utils'; +import * as chalk from 'chalk'; interface InitArgs { adminAccount: Account; @@ -95,18 +97,42 @@ export class EOSManager { static transact = async ( transaction: any, eos = EOSManager.api, - options?: { debug?: boolean; blocksBehind?: number; expireSeconds?: number } + options?: { + debug?: boolean; + debugLevel?: LamingtonDebugLevel; + blocksBehind?: number; + expireSeconds?: number; + logMessage?: string; + } ) => { const flattenedOptions = Object.assign({ blocksBehind: 1, expireSeconds: 30 }, options); - if (ConfigManager.debugTransactions || flattenedOptions.debug) { - const calls = transaction.actions.map((action: any) => `${action.account}.${action.name}`); - console.log(`========== Calling ${calls.join(', ')} ==========`); - console.log('Transaction: ', JSON.stringify(transaction, null, 4)); - console.log('Options: ', options); - console.log(); + const transactionTimer = timer(); + + async function logOutput(verboseOutput: string) { + const legacyDebugOption = ConfigManager.debugTransactions || flattenedOptions.debug; + + if (ConfigManager.debugLevelMin || ConfigManager.debugLevelVerbose || legacyDebugOption) { + let consoleHeader = ''; + const calls = transaction.actions.map((action: any) => `${action.account}.${action.name}`); + consoleHeader += `========== Calling ${calls.join(', ')} ==========`; + console.log(chalk.cyan(consoleHeader) + chalk.blue(' (%s)'), transactionTimer.ms); + } + if (ConfigManager.debugLevelVerbose) { + console.log(verboseOutput); + console.log('Options: ', options); + } } - return await eos.transact(transaction, flattenedOptions); + return await eos + .transact(transaction, flattenedOptions) + .then(value => { + logOutput(chalk.green('Succeeded: ') + JSON.stringify(value, null, 4)); + return value; + }) + .catch(error => { + logOutput(chalk.red('Threw error: ') + error); + throw error; + }); }; } diff --git a/src/eosio-config/genesis.json b/src/eosio-config/genesis.json new file mode 100644 index 0000000..82167b8 --- /dev/null +++ b/src/eosio-config/genesis.json @@ -0,0 +1,23 @@ +{ + "initial_timestamp": "2018-06-08T08:08:08.888", + "initial_key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", + "initial_configuration": { + "max_block_net_usage": 1048576, + "target_block_net_usage_pct": 1000, + "max_transaction_net_usage": 524288, + "base_per_transaction_net_usage": 12, + "net_usage_leeway": 500, + "context_free_discount_net_usage_num": 20, + "context_free_discount_net_usage_den": 100, + "max_block_cpu_usage": 200000, + "target_block_cpu_usage_pct": 1000, + "max_transaction_cpu_usage": 150000, + "min_transaction_cpu_usage": 100, + "max_transaction_lifetime": 3600, + "deferred_trx_expiration_window": 600, + "max_transaction_delay": 3888000, + "max_inline_action_size": 4096, + "max_inline_action_depth": 4, + "max_authority_depth": 6 + } +} diff --git a/src/scripts/init_blockchain.sh b/src/scripts/init_blockchain.sh index 06f0807..f923dc8 100755 --- a/src/scripts/init_blockchain.sh +++ b/src/scripts/init_blockchain.sh @@ -15,8 +15,10 @@ rm -rf /mnt/dev/data # run it in a background job such that docker run could continue nodeos -e -p eosio -d /mnt/dev/data \ --config-dir /mnt/dev/config \ - --max-transaction-time=40 \ + --genesis-json /mnt/dev/config/genesis.json \ + --max-transaction-time=60 \ --http-validate-host=false \ + --http-max-response-time-ms=500 \ --plugin eosio::producer_plugin \ --plugin eosio::producer_api_plugin \ --plugin eosio::chain_api_plugin \ diff --git a/src/utils.ts b/src/utils.ts index ff5ff04..9c97415 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -6,6 +6,8 @@ import * as deepEqualInAnyOrder from 'deep-equal-in-any-order'; import { EOSManager } from './eosManager'; import { verbose_logging } from './cli/lamington-test'; import { TableRowsResult } from './contracts'; +import { ConfigManager } from './configManager'; +import * as chalk from 'chalk'; // Extend Chai's expect methods chai.use(deepEqualInAnyOrder); @@ -87,7 +89,6 @@ export const assertRowsEqual = async ( // @ts-ignore - Not sure how to add this extended method `equalInAnyOrder`? chai.expect(result).to.deep.equalInAnyOrder({ rows: expected, - next_key: '', more: false, }); }; @@ -107,7 +108,6 @@ export const assertRowsEqualStrict = async ( assert.deepStrictEqual(result, { rows: expected, - next_key: '', more: false, }); }; @@ -246,3 +246,49 @@ export const assertEOSException = async (operation: Promise) => */ export const assertMissingAuthority = async (operation: Promise) => assertEOSErrorIncludesMessage(operation, '', 'missing_auth_exception'); + +export async function debugPromise( + promise: Promise, + successMessage: string, + errorMessage?: string +) { + let debugPrefix = 'DebugPromise: '; + let successString = debugPrefix + successMessage; + + let errorString = errorMessage + ? debugPrefix + errorMessage + ': ' + : debugPrefix + 'error - ' + successMessage + ': '; + const promiseTimer = timer(); + return promise + .then(value => { + if (ConfigManager.debugLevelVerbose || ConfigManager.debugLevelMin) { + console.log(chalk.green(successString) + chalk.blue(' (%s)'), promiseTimer.ms); + } + if (ConfigManager.debugLevelVerbose) { + console.log(`Promise result: ${JSON.stringify(value, null, 4)}`); + } + return value; + }) + .catch(err => { + assert.fail(errorString + err); + }); +} + +/** + * Simple timer + */ +export function timer() { + let timeStart = new Date().getTime(); + return { + /** s e.g 2s etc. */ + get seconds() { + const seconds = Math.ceil((new Date().getTime() - timeStart) / 1000) + 's'; + return seconds; + }, + /** Milliseconds e.g. 2000ms etc. */ + get ms() { + const ms = new Date().getTime() - timeStart + 'ms'; + return ms; + }, + }; +}