diff --git a/.eslintignore b/.eslintignore index 7b9a68880f3504729c7ca57ea18d5c580e3cc457..bd009ef6ce226d0529c19cb1147ec7649a069d67 100644 --- a/.eslintignore +++ b/.eslintignore @@ -14,6 +14,8 @@ app/service/*.js app/lib/rules/*.js app/lib/system/*.js app/lib/streams/*.js +app/lib/helpers/*.js +app/lib/*.js app/modules/wizard.js app/modules/router.js app/modules/revert.js diff --git a/.gitignore b/.gitignore index ac726b307dd5eee23eefb6db0904c99eb61e82fa..444e37d3adda720316397f3fb0316ce66d91ce38 100644 --- a/.gitignore +++ b/.gitignore @@ -32,27 +32,25 @@ test/blockchain/*.js test/blockchain/*.js.map test/blockchain/lib/*.js test/blockchain/lib/*.js.map +app/lib/*.js* app/lib/blockchain/*.js app/lib/blockchain/*.js.map app/lib/blockchain/interfaces/*.js app/lib/blockchain/interfaces/*.js.map app/lib/computation/*.js app/lib/computation/*.js.map -app/lib/common.js* app/lib/db/*.js* app/lib/dto/*.js* -app/lib/indexer.js* app/lib/dal/drivers/*.js* app/lib/dal/sqliteDAL/*.js* app/lib/dal/sqliteDAL/index/*.js* app/lib/dal/fileDALs/*.js* app/lib/dal/fileDAL.js* app/lib/rules/*.js* -app/lib/logger*js* app/lib/system/directory.js* app/lib/streams/*.js* +app/lib/helpers/*.js* app/service/*.js* -app/lib/wot.js* app/modules/prover/*.js* app/modules/prover/lib/*.js* app/modules/router*.js* diff --git a/app/lib/constants.js b/app/lib/constants.js index 0e8e784f760cdf63cd7aacf54edd5680e815f8ce..43a17790aca2c597364abcdf1a6afde6d0a78fb1 100644 --- a/app/lib/constants.js +++ b/app/lib/constants.js @@ -1,176 +1,148 @@ "use strict"; - -const common = require('duniter-common') - -const UDID2 = "udid2;c;([A-Z-]*);([A-Z-]*);(\\d{4}-\\d{2}-\\d{2});(e\\+\\d{2}\\.\\d{2}(\\+|-)\\d{3}\\.\\d{2});(\\d+)(;?)"; -const PUBKEY = common.constants.FORMATS.PUBKEY -const TIMESTAMP = common.constants.FORMATS.TIMESTAMP - +const common = require('duniter-common'); +const UDID2 = "udid2;c;([A-Z-]*);([A-Z-]*);(\\d{4}-\\d{2}-\\d{2});(e\\+\\d{2}\\.\\d{2}(\\+|-)\\d{3}\\.\\d{2});(\\d+)(;?)"; +const PUBKEY = common.constants.FORMATS.PUBKEY; +const TIMESTAMP = common.constants.FORMATS.TIMESTAMP; const IPV4_REGEXP = /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/; const IPV6_REGEXP = /^((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((b((25[0-5])|(1d{2})|(2[0-4]d)|(d{1,2}))b).){3}(b((25[0-5])|(1d{2})|(2[0-4]d)|(d{1,2}))b))|(([0-9A-Fa-f]{1,4}:){0,5}:((b((25[0-5])|(1d{2})|(2[0-4]d)|(d{1,2}))b).){3}(b((25[0-5])|(1d{2})|(2[0-4]d)|(d{1,2}))b))|(::([0-9A-Fa-f]{1,4}:){0,5}((b((25[0-5])|(1d{2})|(2[0-4]d)|(d{1,2}))b).){3}(b((25[0-5])|(1d{2})|(2[0-4]d)|(d{1,2}))b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))$/; - module.exports = { - - TIME_TO_TURN_ON_BRG_107: 1498860000, - - ERROR: { - - PEER: { - UNKNOWN_REFERENCE_BLOCK: 'Unknown reference block of peer' + TIME_TO_TURN_ON_BRG_107: 1498860000, + ERROR: { + PEER: { + UNKNOWN_REFERENCE_BLOCK: 'Unknown reference block of peer' + }, + BLOCK: { + NO_CURRENT_BLOCK: 'No current block' + } }, - - BLOCK: { - NO_CURRENT_BLOCK: 'No current block' - } - }, - - ERRORS: { - - // Technical errors - UNKNOWN: { httpCode: 500, uerr: { ucode: 1001, message: "An unknown error occured" }}, - UNHANDLED: { httpCode: 500, uerr: { ucode: 1002, message: "An unhandled error occured" }}, - SIGNATURE_DOES_NOT_MATCH: { httpCode: 400, uerr: { ucode: 1003, message: "Signature does not match" }}, - ALREADY_UP_TO_DATE: { httpCode: 400, uerr: { ucode: 1004, message: "Already up-to-date" }}, - WRONG_DOCUMENT: common.constants.ERRORS.WRONG_DOCUMENT, - SANDBOX_FOR_IDENTITY_IS_FULL: { httpCode: 503, uerr: { ucode: 1007, message: "The identities' sandbox is full. Please retry with another document or retry later." }}, - SANDBOX_FOR_CERT_IS_FULL: { httpCode: 503, uerr: { ucode: 1008, message: "The certifications' sandbox is full. Please retry with another document or retry later." }}, - SANDBOX_FOR_MEMERSHIP_IS_FULL: { httpCode: 503, uerr: { ucode: 1009, message: "The memberships' sandbox is full. Please retry with another document or retry later." }}, - SANDBOX_FOR_TRANSACTION_IS_FULL: { httpCode: 503, uerr: { ucode: 1010, message: "The transactions' sandbox is full. Please retry with another document or retry later." }}, - NO_POTENTIAL_FORK_AS_NEXT: { httpCode: 503, uerr: { ucode: 1011, message: "No fork block exists in the database as a potential next block." }}, - INCONSISTENT_DB_MULTI_TXS_SAME_HASH: { httpCode: 503, uerr: { ucode: 1012, message: "Several transactions written with the same hash." }}, - CLI_CALLERR_RESET: { httpCode: 503, uerr: { ucode: 1013, message: "Bad command: usage is `reset config`, `reset data`, `reset peers`, `reset stats` or `reset all`" }}, - CLI_CALLERR_CONFIG: { httpCode: 503, uerr: { ucode: 1014, message: "Bad command: usage is `config`." }}, - - // Business errors - NO_MATCHING_IDENTITY: { httpCode: 404, uerr: { ucode: 2001, message: "No matching identity" }}, - UID_ALREADY_USED: { httpCode: 400, uerr: { ucode: 2002, message: "UID already used in the blockchain" }}, - PUBKEY_ALREADY_USED: { httpCode: 400, uerr: { ucode: 2003, message: "Pubkey already used in the blockchain" }}, - NO_MEMBER_MATCHING_PUB_OR_UID: { httpCode: 404, uerr: { ucode: 2004, message: "No member matching this pubkey or uid" }}, - WRONG_SIGNATURE_MEMBERSHIP: { httpCode: 400, uerr: { ucode: 2006, message: "wrong signature for membership" }}, - ALREADY_RECEIVED_MEMBERSHIP: { httpCode: 400, uerr: { ucode: 2007, message: "Already received membership" }}, - MEMBERSHIP_A_NON_MEMBER_CANNOT_LEAVE: { httpCode: 400, uerr: { ucode: 2008, message: "A non-member cannot leave" }}, - NOT_A_MEMBER: { httpCode: 400, uerr: { ucode: 2009, message: "Not a member" }}, - BLOCK_NOT_FOUND: { httpCode: 404, uerr: { ucode: 2011, message: "Block not found" }}, - WRONG_UNLOCKER: common.constants.ERRORS.WRONG_UNLOCKER, - LOCKTIME_PREVENT: common.constants.ERRORS.LOCKTIME_PREVENT, - SOURCE_ALREADY_CONSUMED: common.constants.ERRORS.SOURCE_ALREADY_CONSUMED, - WRONG_AMOUNTS: common.constants.ERRORS.WRONG_AMOUNTS, - WRONG_OUTPUT_BASE: common.constants.ERRORS.WRONG_OUTPUT_BASE, - CANNOT_ROOT_BLOCK_NO_MEMBERS: common.constants.ERRORS.CANNOT_ROOT_BLOCK_NO_MEMBERS, - IDENTITY_WRONGLY_SIGNED: common.constants.ERRORS.IDENTITY_WRONGLY_SIGNED, - TOO_OLD_IDENTITY: common.constants.ERRORS.TOO_OLD_IDENTITY, - NO_IDTY_MATCHING_PUB_OR_UID: { httpCode: 404, uerr: { ucode: 2021, message: "No identity matching this pubkey or uid" }}, - NEWER_PEER_DOCUMENT_AVAILABLE: { httpCode: 409, uerr: { ucode: 2022, message: "A newer peer document is available" }}, - PEER_DOCUMENT_ALREADY_KNOWN: { httpCode: 400, uerr: { ucode: 2023, message: "Peer document already known" }}, - TX_INPUTS_OUTPUTS_NOT_EQUAL: common.constants.ERRORS.TX_INPUTS_OUTPUTS_NOT_EQUAL, - TX_OUTPUT_SUM_NOT_EQUALS_PREV_DELTAS: common.constants.ERRORS.TX_OUTPUT_SUM_NOT_EQUALS_PREV_DELTAS, - BLOCKSTAMP_DOES_NOT_MATCH_A_BLOCK: common.constants.ERRORS.BLOCKSTAMP_DOES_NOT_MATCH_A_BLOCK, - A_TRANSACTION_HAS_A_MAX_SIZE: common.constants.ERRORS.A_TRANSACTION_HAS_A_MAX_SIZE, - BLOCK_ALREADY_PROCESSED: { httpCode: 400, uerr: { ucode: 2028, message: 'Already processed' }}, - TOO_OLD_MEMBERSHIP: common.constants.ERRORS.TOO_OLD_MEMBERSHIP, - TX_ALREADY_PROCESSED: { httpCode: 400, uerr: { ucode: 2030, message: "Transaction already processed" }}, - A_MORE_RECENT_MEMBERSHIP_EXISTS: { httpCode: 400, uerr: { ucode: 2031, message: "A more recent membership already exists" }}, - MAXIMUM_LEN_OF_OUTPUT: common.constants.ERRORS.MAXIMUM_LEN_OF_OUTPUT, - MAXIMUM_LEN_OF_UNLOCK: common.constants.ERRORS.MAXIMUM_LEN_OF_UNLOCK - }, - - DEBUG: { - LONG_DAL_PROCESS: 50 - }, - - BMA_REGEXP: common.constants.BMA_REGEXP, - IPV4_REGEXP: IPV4_REGEXP, - IPV6_REGEXP: IPV6_REGEXP, - - TIMESTAMP: exact(TIMESTAMP), - UDID2_FORMAT: exact(UDID2), - PUBLIC_KEY: exact(PUBKEY), - - DOCUMENTS_VERSION: common.constants.DOCUMENTS_VERSION, - BLOCK_GENERATED_VERSION: common.constants.BLOCK_GENERATED_VERSION, - LAST_VERSION_FOR_TX: 10, - TRANSACTION_VERSION: common.constants.TRANSACTION_VERSION, - - REVOCATION_FACTOR: common.constants.REVOCATION_FACTOR, // This is protocol fixed value - FIRST_UNIT_BASE: 0, - - PEER: common.constants.PEER, - NETWORK: { - MAX_MEMBERS_TO_FORWARD_TO_FOR_SELF_DOCUMENTS: 10, - MAX_NON_MEMBERS_TO_FORWARD_TO_FOR_SELF_DOCUMENTS: 6, - MAX_NON_MEMBERS_TO_FORWARD_TO: 4, - MAX_MEMBERS_TO_FORWARD_TO: 6, - MAX_CONCURRENT_POST: 3, - DEFAULT_TIMEOUT: 10 * 1000, // 10 seconds - SYNC: { - MAX: 20 + ERRORS: { + // Technical errors + UNKNOWN: { httpCode: 500, uerr: { ucode: 1001, message: "An unknown error occured" } }, + UNHANDLED: { httpCode: 500, uerr: { ucode: 1002, message: "An unhandled error occured" } }, + SIGNATURE_DOES_NOT_MATCH: { httpCode: 400, uerr: { ucode: 1003, message: "Signature does not match" } }, + ALREADY_UP_TO_DATE: { httpCode: 400, uerr: { ucode: 1004, message: "Already up-to-date" } }, + WRONG_DOCUMENT: common.constants.ERRORS.WRONG_DOCUMENT, + SANDBOX_FOR_IDENTITY_IS_FULL: { httpCode: 503, uerr: { ucode: 1007, message: "The identities' sandbox is full. Please retry with another document or retry later." } }, + SANDBOX_FOR_CERT_IS_FULL: { httpCode: 503, uerr: { ucode: 1008, message: "The certifications' sandbox is full. Please retry with another document or retry later." } }, + SANDBOX_FOR_MEMERSHIP_IS_FULL: { httpCode: 503, uerr: { ucode: 1009, message: "The memberships' sandbox is full. Please retry with another document or retry later." } }, + SANDBOX_FOR_TRANSACTION_IS_FULL: { httpCode: 503, uerr: { ucode: 1010, message: "The transactions' sandbox is full. Please retry with another document or retry later." } }, + NO_POTENTIAL_FORK_AS_NEXT: { httpCode: 503, uerr: { ucode: 1011, message: "No fork block exists in the database as a potential next block." } }, + INCONSISTENT_DB_MULTI_TXS_SAME_HASH: { httpCode: 503, uerr: { ucode: 1012, message: "Several transactions written with the same hash." } }, + CLI_CALLERR_RESET: { httpCode: 503, uerr: { ucode: 1013, message: "Bad command: usage is `reset config`, `reset data`, `reset peers`, `reset stats` or `reset all`" } }, + CLI_CALLERR_CONFIG: { httpCode: 503, uerr: { ucode: 1014, message: "Bad command: usage is `config`." } }, + // Business errors + NO_MATCHING_IDENTITY: { httpCode: 404, uerr: { ucode: 2001, message: "No matching identity" } }, + UID_ALREADY_USED: { httpCode: 400, uerr: { ucode: 2002, message: "UID already used in the blockchain" } }, + PUBKEY_ALREADY_USED: { httpCode: 400, uerr: { ucode: 2003, message: "Pubkey already used in the blockchain" } }, + NO_MEMBER_MATCHING_PUB_OR_UID: { httpCode: 404, uerr: { ucode: 2004, message: "No member matching this pubkey or uid" } }, + WRONG_SIGNATURE_MEMBERSHIP: { httpCode: 400, uerr: { ucode: 2006, message: "wrong signature for membership" } }, + ALREADY_RECEIVED_MEMBERSHIP: { httpCode: 400, uerr: { ucode: 2007, message: "Already received membership" } }, + MEMBERSHIP_A_NON_MEMBER_CANNOT_LEAVE: { httpCode: 400, uerr: { ucode: 2008, message: "A non-member cannot leave" } }, + NOT_A_MEMBER: { httpCode: 400, uerr: { ucode: 2009, message: "Not a member" } }, + BLOCK_NOT_FOUND: { httpCode: 404, uerr: { ucode: 2011, message: "Block not found" } }, + WRONG_UNLOCKER: common.constants.ERRORS.WRONG_UNLOCKER, + LOCKTIME_PREVENT: common.constants.ERRORS.LOCKTIME_PREVENT, + SOURCE_ALREADY_CONSUMED: common.constants.ERRORS.SOURCE_ALREADY_CONSUMED, + WRONG_AMOUNTS: common.constants.ERRORS.WRONG_AMOUNTS, + WRONG_OUTPUT_BASE: common.constants.ERRORS.WRONG_OUTPUT_BASE, + CANNOT_ROOT_BLOCK_NO_MEMBERS: common.constants.ERRORS.CANNOT_ROOT_BLOCK_NO_MEMBERS, + IDENTITY_WRONGLY_SIGNED: common.constants.ERRORS.IDENTITY_WRONGLY_SIGNED, + TOO_OLD_IDENTITY: common.constants.ERRORS.TOO_OLD_IDENTITY, + NO_IDTY_MATCHING_PUB_OR_UID: { httpCode: 404, uerr: { ucode: 2021, message: "No identity matching this pubkey or uid" } }, + NEWER_PEER_DOCUMENT_AVAILABLE: { httpCode: 409, uerr: { ucode: 2022, message: "A newer peer document is available" } }, + PEER_DOCUMENT_ALREADY_KNOWN: { httpCode: 400, uerr: { ucode: 2023, message: "Peer document already known" } }, + TX_INPUTS_OUTPUTS_NOT_EQUAL: common.constants.ERRORS.TX_INPUTS_OUTPUTS_NOT_EQUAL, + TX_OUTPUT_SUM_NOT_EQUALS_PREV_DELTAS: common.constants.ERRORS.TX_OUTPUT_SUM_NOT_EQUALS_PREV_DELTAS, + BLOCKSTAMP_DOES_NOT_MATCH_A_BLOCK: common.constants.ERRORS.BLOCKSTAMP_DOES_NOT_MATCH_A_BLOCK, + A_TRANSACTION_HAS_A_MAX_SIZE: common.constants.ERRORS.A_TRANSACTION_HAS_A_MAX_SIZE, + BLOCK_ALREADY_PROCESSED: { httpCode: 400, uerr: { ucode: 2028, message: 'Already processed' } }, + TOO_OLD_MEMBERSHIP: common.constants.ERRORS.TOO_OLD_MEMBERSHIP, + TX_ALREADY_PROCESSED: { httpCode: 400, uerr: { ucode: 2030, message: "Transaction already processed" } }, + A_MORE_RECENT_MEMBERSHIP_EXISTS: { httpCode: 400, uerr: { ucode: 2031, message: "A more recent membership already exists" } }, + MAXIMUM_LEN_OF_OUTPUT: common.constants.ERRORS.MAXIMUM_LEN_OF_OUTPUT, + MAXIMUM_LEN_OF_UNLOCK: common.constants.ERRORS.MAXIMUM_LEN_OF_UNLOCK }, - STATUS_INTERVAL: { - UPDATE: 2, // Every X blocks - MAX: 20 // MAX Y blocks - } - }, - PROOF_OF_WORK: { - EVALUATION: 1000, - UPPER_BOUND: common.constants.PROOF_OF_WORK.UPPER_BOUND.slice() - }, - - DEFAULT_CURRENCY_NAME: "no_currency", - - CONTRACT: { - DEFAULT: { - C: 0.007376575, - DT: 30.4375 * 24 * 3600, - DT_REEVAL: 30.4375 * 24 * 3600, - UD0: 100, - STEPMAX: 3, - SIGDELAY: 3600 * 24 * 365 * 5, - SIGPERIOD: 0, // Instant - MSPERIOD: 0, // Instant - SIGSTOCK: 40, - SIGWINDOW: 3600 * 24 * 7, // a week - SIGVALIDITY: 3600 * 24 * 365, - MSVALIDITY: 3600 * 24 * 365, - SIGQTY: 5, - X_PERCENT: 0.9, - PERCENTROT: 2 / 3, - BLOCKSROT: 20, - POWDELAY: 0, - AVGGENTIME: 16 * 60, - DTDIFFEVAL: 10, - MEDIANTIMEBLOCKS: 20, - IDTYWINDOW: 3600 * 24 * 7, // a week - MSWINDOW: 3600 * 24 * 7 // a week + DEBUG: { + LONG_DAL_PROCESS: 50 }, - - DSEN_P: 1.2 // dSen proportional factor - }, - - BRANCHES: { - DEFAULT_WINDOW_SIZE: 100 - }, - - INVALIDATE_CORE_CACHE: true, - WITH_SIGNATURES_AND_POW: true, - - NO_FORK_ALLOWED: false, - - SAFE_FACTOR: 3, - BLOCKS_COLLECT_THRESHOLD: 30, // Blocks to collect from memory and persist - - MUTE_LOGS_DURING_UNIT_TESTS: true, - - SANDBOX_SIZE_TRANSACTIONS: 200, - SANDBOX_SIZE_IDENTITIES: 5000, - SANDBOX_SIZE_CERTIFICATIONS: 12, - SANDBOX_SIZE_MEMBERSHIPS: 5000, - - CURRENT_BLOCK_CACHE_DURATION: 10 * 1000, // 30 seconds - - // With `logs` command, the number of tail lines to show - NB_INITIAL_LINES_TO_SHOW: 100 + BMA_REGEXP: common.constants.BMA_REGEXP, + IPV4_REGEXP: IPV4_REGEXP, + IPV6_REGEXP: IPV6_REGEXP, + TIMESTAMP: exact(TIMESTAMP), + UDID2_FORMAT: exact(UDID2), + PUBLIC_KEY: exact(PUBKEY), + DOCUMENTS_VERSION: common.constants.DOCUMENTS_VERSION, + BLOCK_GENERATED_VERSION: common.constants.BLOCK_GENERATED_VERSION, + LAST_VERSION_FOR_TX: 10, + TRANSACTION_VERSION: common.constants.TRANSACTION_VERSION, + REVOCATION_FACTOR: common.constants.REVOCATION_FACTOR, + FIRST_UNIT_BASE: 0, + PEER: common.constants.PEER, + NETWORK: { + MAX_MEMBERS_TO_FORWARD_TO_FOR_SELF_DOCUMENTS: 10, + MAX_NON_MEMBERS_TO_FORWARD_TO_FOR_SELF_DOCUMENTS: 6, + MAX_NON_MEMBERS_TO_FORWARD_TO: 4, + MAX_MEMBERS_TO_FORWARD_TO: 6, + MAX_CONCURRENT_POST: 3, + DEFAULT_TIMEOUT: 10 * 1000, + SYNC: { + MAX: 20 + }, + STATUS_INTERVAL: { + UPDATE: 2, + MAX: 20 // MAX Y blocks + } + }, + PROOF_OF_WORK: { + EVALUATION: 1000, + UPPER_BOUND: common.constants.PROOF_OF_WORK.UPPER_BOUND.slice() + }, + DEFAULT_CURRENCY_NAME: "no_currency", + CONTRACT: { + DEFAULT: { + C: 0.007376575, + DT: 30.4375 * 24 * 3600, + DT_REEVAL: 30.4375 * 24 * 3600, + UD0: 100, + STEPMAX: 3, + SIGDELAY: 3600 * 24 * 365 * 5, + SIGPERIOD: 0, + MSPERIOD: 0, + SIGSTOCK: 40, + SIGWINDOW: 3600 * 24 * 7, + SIGVALIDITY: 3600 * 24 * 365, + MSVALIDITY: 3600 * 24 * 365, + SIGQTY: 5, + X_PERCENT: 0.9, + PERCENTROT: 2 / 3, + BLOCKSROT: 20, + POWDELAY: 0, + AVGGENTIME: 16 * 60, + DTDIFFEVAL: 10, + MEDIANTIMEBLOCKS: 20, + IDTYWINDOW: 3600 * 24 * 7, + MSWINDOW: 3600 * 24 * 7 // a week + }, + DSEN_P: 1.2 // dSen proportional factor + }, + BRANCHES: { + DEFAULT_WINDOW_SIZE: 100 + }, + INVALIDATE_CORE_CACHE: true, + WITH_SIGNATURES_AND_POW: true, + NO_FORK_ALLOWED: false, + SAFE_FACTOR: 3, + BLOCKS_COLLECT_THRESHOLD: 30, + MUTE_LOGS_DURING_UNIT_TESTS: true, + SANDBOX_SIZE_TRANSACTIONS: 200, + SANDBOX_SIZE_IDENTITIES: 5000, + SANDBOX_SIZE_CERTIFICATIONS: 12, + SANDBOX_SIZE_MEMBERSHIPS: 5000, + CURRENT_BLOCK_CACHE_DURATION: 10 * 1000, + // With `logs` command, the number of tail lines to show + NB_INITIAL_LINES_TO_SHOW: 100 }; - -function exact (regexpContent) { - return new RegExp("^" + regexpContent + "$"); +function exact(regexpContent) { + return new RegExp("^" + regexpContent + "$"); } +//# sourceMappingURL=constants.js.map \ No newline at end of file diff --git a/app/lib/constants.ts b/app/lib/constants.ts new file mode 100644 index 0000000000000000000000000000000000000000..92fef4c10be683516d61e2e66fa102113ec7a569 --- /dev/null +++ b/app/lib/constants.ts @@ -0,0 +1,176 @@ +"use strict"; + +const common = require('duniter-common') + +const UDID2 = "udid2;c;([A-Z-]*);([A-Z-]*);(\\d{4}-\\d{2}-\\d{2});(e\\+\\d{2}\\.\\d{2}(\\+|-)\\d{3}\\.\\d{2});(\\d+)(;?)"; +const PUBKEY = common.constants.FORMATS.PUBKEY +const TIMESTAMP = common.constants.FORMATS.TIMESTAMP + +const IPV4_REGEXP = /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/; +const IPV6_REGEXP = /^((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((b((25[0-5])|(1d{2})|(2[0-4]d)|(d{1,2}))b).){3}(b((25[0-5])|(1d{2})|(2[0-4]d)|(d{1,2}))b))|(([0-9A-Fa-f]{1,4}:){0,5}:((b((25[0-5])|(1d{2})|(2[0-4]d)|(d{1,2}))b).){3}(b((25[0-5])|(1d{2})|(2[0-4]d)|(d{1,2}))b))|(::([0-9A-Fa-f]{1,4}:){0,5}((b((25[0-5])|(1d{2})|(2[0-4]d)|(d{1,2}))b).){3}(b((25[0-5])|(1d{2})|(2[0-4]d)|(d{1,2}))b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))$/; + +module.exports = { + + TIME_TO_TURN_ON_BRG_107: 1498860000, + + ERROR: { + + PEER: { + UNKNOWN_REFERENCE_BLOCK: 'Unknown reference block of peer' + }, + + BLOCK: { + NO_CURRENT_BLOCK: 'No current block' + } + }, + + ERRORS: { + + // Technical errors + UNKNOWN: { httpCode: 500, uerr: { ucode: 1001, message: "An unknown error occured" }}, + UNHANDLED: { httpCode: 500, uerr: { ucode: 1002, message: "An unhandled error occured" }}, + SIGNATURE_DOES_NOT_MATCH: { httpCode: 400, uerr: { ucode: 1003, message: "Signature does not match" }}, + ALREADY_UP_TO_DATE: { httpCode: 400, uerr: { ucode: 1004, message: "Already up-to-date" }}, + WRONG_DOCUMENT: common.constants.ERRORS.WRONG_DOCUMENT, + SANDBOX_FOR_IDENTITY_IS_FULL: { httpCode: 503, uerr: { ucode: 1007, message: "The identities' sandbox is full. Please retry with another document or retry later." }}, + SANDBOX_FOR_CERT_IS_FULL: { httpCode: 503, uerr: { ucode: 1008, message: "The certifications' sandbox is full. Please retry with another document or retry later." }}, + SANDBOX_FOR_MEMERSHIP_IS_FULL: { httpCode: 503, uerr: { ucode: 1009, message: "The memberships' sandbox is full. Please retry with another document or retry later." }}, + SANDBOX_FOR_TRANSACTION_IS_FULL: { httpCode: 503, uerr: { ucode: 1010, message: "The transactions' sandbox is full. Please retry with another document or retry later." }}, + NO_POTENTIAL_FORK_AS_NEXT: { httpCode: 503, uerr: { ucode: 1011, message: "No fork block exists in the database as a potential next block." }}, + INCONSISTENT_DB_MULTI_TXS_SAME_HASH: { httpCode: 503, uerr: { ucode: 1012, message: "Several transactions written with the same hash." }}, + CLI_CALLERR_RESET: { httpCode: 503, uerr: { ucode: 1013, message: "Bad command: usage is `reset config`, `reset data`, `reset peers`, `reset stats` or `reset all`" }}, + CLI_CALLERR_CONFIG: { httpCode: 503, uerr: { ucode: 1014, message: "Bad command: usage is `config`." }}, + + // Business errors + NO_MATCHING_IDENTITY: { httpCode: 404, uerr: { ucode: 2001, message: "No matching identity" }}, + UID_ALREADY_USED: { httpCode: 400, uerr: { ucode: 2002, message: "UID already used in the blockchain" }}, + PUBKEY_ALREADY_USED: { httpCode: 400, uerr: { ucode: 2003, message: "Pubkey already used in the blockchain" }}, + NO_MEMBER_MATCHING_PUB_OR_UID: { httpCode: 404, uerr: { ucode: 2004, message: "No member matching this pubkey or uid" }}, + WRONG_SIGNATURE_MEMBERSHIP: { httpCode: 400, uerr: { ucode: 2006, message: "wrong signature for membership" }}, + ALREADY_RECEIVED_MEMBERSHIP: { httpCode: 400, uerr: { ucode: 2007, message: "Already received membership" }}, + MEMBERSHIP_A_NON_MEMBER_CANNOT_LEAVE: { httpCode: 400, uerr: { ucode: 2008, message: "A non-member cannot leave" }}, + NOT_A_MEMBER: { httpCode: 400, uerr: { ucode: 2009, message: "Not a member" }}, + BLOCK_NOT_FOUND: { httpCode: 404, uerr: { ucode: 2011, message: "Block not found" }}, + WRONG_UNLOCKER: common.constants.ERRORS.WRONG_UNLOCKER, + LOCKTIME_PREVENT: common.constants.ERRORS.LOCKTIME_PREVENT, + SOURCE_ALREADY_CONSUMED: common.constants.ERRORS.SOURCE_ALREADY_CONSUMED, + WRONG_AMOUNTS: common.constants.ERRORS.WRONG_AMOUNTS, + WRONG_OUTPUT_BASE: common.constants.ERRORS.WRONG_OUTPUT_BASE, + CANNOT_ROOT_BLOCK_NO_MEMBERS: common.constants.ERRORS.CANNOT_ROOT_BLOCK_NO_MEMBERS, + IDENTITY_WRONGLY_SIGNED: common.constants.ERRORS.IDENTITY_WRONGLY_SIGNED, + TOO_OLD_IDENTITY: common.constants.ERRORS.TOO_OLD_IDENTITY, + NO_IDTY_MATCHING_PUB_OR_UID: { httpCode: 404, uerr: { ucode: 2021, message: "No identity matching this pubkey or uid" }}, + NEWER_PEER_DOCUMENT_AVAILABLE: { httpCode: 409, uerr: { ucode: 2022, message: "A newer peer document is available" }}, + PEER_DOCUMENT_ALREADY_KNOWN: { httpCode: 400, uerr: { ucode: 2023, message: "Peer document already known" }}, + TX_INPUTS_OUTPUTS_NOT_EQUAL: common.constants.ERRORS.TX_INPUTS_OUTPUTS_NOT_EQUAL, + TX_OUTPUT_SUM_NOT_EQUALS_PREV_DELTAS: common.constants.ERRORS.TX_OUTPUT_SUM_NOT_EQUALS_PREV_DELTAS, + BLOCKSTAMP_DOES_NOT_MATCH_A_BLOCK: common.constants.ERRORS.BLOCKSTAMP_DOES_NOT_MATCH_A_BLOCK, + A_TRANSACTION_HAS_A_MAX_SIZE: common.constants.ERRORS.A_TRANSACTION_HAS_A_MAX_SIZE, + BLOCK_ALREADY_PROCESSED: { httpCode: 400, uerr: { ucode: 2028, message: 'Already processed' }}, + TOO_OLD_MEMBERSHIP: common.constants.ERRORS.TOO_OLD_MEMBERSHIP, + TX_ALREADY_PROCESSED: { httpCode: 400, uerr: { ucode: 2030, message: "Transaction already processed" }}, + A_MORE_RECENT_MEMBERSHIP_EXISTS: { httpCode: 400, uerr: { ucode: 2031, message: "A more recent membership already exists" }}, + MAXIMUM_LEN_OF_OUTPUT: common.constants.ERRORS.MAXIMUM_LEN_OF_OUTPUT, + MAXIMUM_LEN_OF_UNLOCK: common.constants.ERRORS.MAXIMUM_LEN_OF_UNLOCK + }, + + DEBUG: { + LONG_DAL_PROCESS: 50 + }, + + BMA_REGEXP: common.constants.BMA_REGEXP, + IPV4_REGEXP: IPV4_REGEXP, + IPV6_REGEXP: IPV6_REGEXP, + + TIMESTAMP: exact(TIMESTAMP), + UDID2_FORMAT: exact(UDID2), + PUBLIC_KEY: exact(PUBKEY), + + DOCUMENTS_VERSION: common.constants.DOCUMENTS_VERSION, + BLOCK_GENERATED_VERSION: common.constants.BLOCK_GENERATED_VERSION, + LAST_VERSION_FOR_TX: 10, + TRANSACTION_VERSION: common.constants.TRANSACTION_VERSION, + + REVOCATION_FACTOR: common.constants.REVOCATION_FACTOR, // This is protocol fixed value + FIRST_UNIT_BASE: 0, + + PEER: common.constants.PEER, + NETWORK: { + MAX_MEMBERS_TO_FORWARD_TO_FOR_SELF_DOCUMENTS: 10, + MAX_NON_MEMBERS_TO_FORWARD_TO_FOR_SELF_DOCUMENTS: 6, + MAX_NON_MEMBERS_TO_FORWARD_TO: 4, + MAX_MEMBERS_TO_FORWARD_TO: 6, + MAX_CONCURRENT_POST: 3, + DEFAULT_TIMEOUT: 10 * 1000, // 10 seconds + SYNC: { + MAX: 20 + }, + STATUS_INTERVAL: { + UPDATE: 2, // Every X blocks + MAX: 20 // MAX Y blocks + } + }, + PROOF_OF_WORK: { + EVALUATION: 1000, + UPPER_BOUND: common.constants.PROOF_OF_WORK.UPPER_BOUND.slice() + }, + + DEFAULT_CURRENCY_NAME: "no_currency", + + CONTRACT: { + DEFAULT: { + C: 0.007376575, + DT: 30.4375 * 24 * 3600, + DT_REEVAL: 30.4375 * 24 * 3600, + UD0: 100, + STEPMAX: 3, + SIGDELAY: 3600 * 24 * 365 * 5, + SIGPERIOD: 0, // Instant + MSPERIOD: 0, // Instant + SIGSTOCK: 40, + SIGWINDOW: 3600 * 24 * 7, // a week + SIGVALIDITY: 3600 * 24 * 365, + MSVALIDITY: 3600 * 24 * 365, + SIGQTY: 5, + X_PERCENT: 0.9, + PERCENTROT: 2 / 3, + BLOCKSROT: 20, + POWDELAY: 0, + AVGGENTIME: 16 * 60, + DTDIFFEVAL: 10, + MEDIANTIMEBLOCKS: 20, + IDTYWINDOW: 3600 * 24 * 7, // a week + MSWINDOW: 3600 * 24 * 7 // a week + }, + + DSEN_P: 1.2 // dSen proportional factor + }, + + BRANCHES: { + DEFAULT_WINDOW_SIZE: 100 + }, + + INVALIDATE_CORE_CACHE: true, + WITH_SIGNATURES_AND_POW: true, + + NO_FORK_ALLOWED: false, + + SAFE_FACTOR: 3, + BLOCKS_COLLECT_THRESHOLD: 30, // Blocks to collect from memory and persist + + MUTE_LOGS_DURING_UNIT_TESTS: true, + + SANDBOX_SIZE_TRANSACTIONS: 200, + SANDBOX_SIZE_IDENTITIES: 5000, + SANDBOX_SIZE_CERTIFICATIONS: 12, + SANDBOX_SIZE_MEMBERSHIPS: 5000, + + CURRENT_BLOCK_CACHE_DURATION: 10 * 1000, // 30 seconds + + // With `logs` command, the number of tail lines to show + NB_INITIAL_LINES_TO_SHOW: 100 +}; + +function exact (regexpContent:string) { + return new RegExp("^" + regexpContent + "$"); +} diff --git a/app/lib/helpers/merkle.js b/app/lib/helpers/merkle.js index 8a0da89e9fccd0b16aa314288208761c9ece2485..b887a0e941caf79be77aba0fa38fda052f583080 100644 --- a/app/lib/helpers/merkle.js +++ b/app/lib/helpers/merkle.js @@ -1,35 +1,42 @@ "use strict"; -const co = require('co'); - -module.exports = { - - processForURL: (req, merkle, valueCoroutine) => co(function*() { +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.processForURL = (req, merkle, valueCoroutine) => __awaiter(this, void 0, void 0, function* () { // Result const json = { - "depth": merkle.depth, - "nodesCount": merkle.nodes, - "leavesCount": merkle.levels[merkle.depth].length, - "root": merkle.levels[0][0] || "" + "depth": merkle.depth, + "nodesCount": merkle.nodes, + "leavesCount": merkle.levels[merkle.depth].length, + "root": merkle.levels[0][0] || "" }; if (req.query.leaves) { - // Leaves - json.leaves = merkle.leaves(); - return json; - } else if (req.query.leaf) { - // Extract of a leaf - json.leaves = {}; - const hashes = [req.query.leaf]; - // This code is in a loop for historic reasons. Should be set to non-loop style. - const values = yield valueCoroutine(hashes); - hashes.forEach((hash) => { - json.leaf = { - "hash": hash, - "value": values[hash] || "" - }; - }); - return json; - } else { - return json; + // Leaves + json.leaves = merkle.leaves(); + return json; } - }) -} + else if (req.query.leaf) { + // Extract of a leaf + json.leaves = {}; + const hashes = [req.query.leaf]; + // This code is in a loop for historic reasons. Should be set to non-loop style. + const values = yield valueCoroutine(hashes); + hashes.forEach((hash) => { + json.leaf = { + "hash": hash, + "value": values[hash] || "" + }; + }); + return json; + } + else { + return json; + } +}); +//# sourceMappingURL=merkle.js.map \ No newline at end of file diff --git a/app/lib/helpers/merkle.ts b/app/lib/helpers/merkle.ts new file mode 100644 index 0000000000000000000000000000000000000000..2c5edd38a7ecad8a342890541033e2c8ad293765 --- /dev/null +++ b/app/lib/helpers/merkle.ts @@ -0,0 +1,29 @@ +export const processForURL = async (req:any, merkle:any, valueCoroutine:any) => { + // Result + const json:any = { + "depth": merkle.depth, + "nodesCount": merkle.nodes, + "leavesCount": merkle.levels[merkle.depth].length, + "root": merkle.levels[0][0] || "" + }; + if (req.query.leaves) { + // Leaves + json.leaves = merkle.leaves(); + return json; + } else if (req.query.leaf) { + // Extract of a leaf + json.leaves = {}; + const hashes = [req.query.leaf]; + // This code is in a loop for historic reasons. Should be set to non-loop style. + const values = await valueCoroutine(hashes); + hashes.forEach((hash) => { + json.leaf = { + "hash": hash, + "value": values[hash] || "" + }; + }); + return json; + } else { + return json; + } +} diff --git a/app/lib/wizard.js b/app/lib/wizard.js index eb0e115dd814e2745a43873d94a6772c47d573f7..e7e9e8974730e95ea8b6a7c912ce2e56405392e7 100644 --- a/app/lib/wizard.js +++ b/app/lib/wizard.js @@ -1,110 +1,105 @@ "use strict"; -const co = require('co'); -const constants = require('./constants'); -const async = require('async'); -const inquirer = require('inquirer'); -const logger = require('./logger').NewLogger('wizard'); - -module.exports = function () { - return new Wizard(); +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); }; - -function Wizard () { - - this.configPoW = function (conf) { - return doTasks(['pow'], conf) - } - - this.configCurrency = function (conf) { - return doTasks(['currency'], conf) - } - - this.configUCP = function (conf) { - return doTasks(['parameters'], conf) - } +Object.defineProperty(exports, "__esModule", { value: true }); +const constants = require('./constants'); +const async = require('async'); +const inquirer = require('inquirer'); +const logger = require('./logger').NewLogger('wizard'); +class Wizard { + static configPoW(conf) { + return doTasks(['pow'], conf); + } + static configCurrency(conf) { + return doTasks(['currency'], conf); + } + static configUCP(conf) { + return doTasks(['parameters'], conf); + } } - -function doTasks (todos, conf) { - return new Promise((res, rej) => { - async.forEachSeries(todos, function(task, callback){ - tasks[task] && tasks[task](conf, callback); - }, (err) => { - if (err) return rej(err) - return res() +exports.Wizard = Wizard; +function doTasks(todos, conf) { + return new Promise((res, rej) => { + async.forEachSeries(todos, function (task, callback) { + tasks[task] && tasks[task](conf, callback); + }, (err) => { + if (err) + return rej(err); + return res(); + }); }); - }) } - const tasks = { - - currency: function (conf, done) { - return co(function*() { - const answers = yield inquirer.prompt([{ - type: "input", - name: "currency", - message: "Currency name", - default: conf.currency, - validate: function (input) { - return input.match(/^[a-zA-Z0-9-_ ]+$/) ? true : false; - } - }]) - conf.currency = answers.currency - done() - }) - }, - - parameters: function (conf, done) { - async.waterfall([ - async.apply(simpleFloat, "Universal Dividend %growth", "c", conf), - async.apply(simpleInteger, "Universal Dividend period (in seconds)", "dt", conf), - async.apply(simpleInteger, "First Universal Dividend (UD[0]) amount", "ud0", conf), - async.apply(simpleInteger, "Delay between 2 certifications of a same issuer", "sigPeriod", conf), - async.apply(simpleInteger, "Maximum stock of valid certifications per member", "sigStock", conf), - async.apply(simpleInteger, "Maximum age of a non-written certification", "sigWindow", conf), - async.apply(simpleInteger, "Certification validity duration", "sigValidity", conf), - async.apply(simpleInteger, "Number of valid certifications required to be a member", "sigQty", conf), - async.apply(simpleInteger, "Maximum age of a non-written identity", "idtyWindow", conf), - async.apply(simpleInteger, "Maximum age of a non-written membership", "msWindow", conf), - async.apply(simpleFloat, "Percentage of sentries to be reached to match WoT distance rule", "xpercent", conf), - async.apply(simpleInteger, "Membership validity duration", "msValidity", conf), - async.apply(simpleInteger, "Number of blocks on which is computed median time", "medianTimeBlocks", conf), - async.apply(simpleInteger, "The average time for writing 1 block (wished time)", "avgGenTime", conf), - async.apply(simpleInteger, "Frequency, in number of blocks, to wait for changing common difficulty", "dtDiffEval", conf), - async.apply(simpleFloat, "Weight in percent for previous issuers", "percentRot", conf) - ], done); - }, - - pow: function (conf, done) { - async.waterfall([ - function (next){ - simpleInteger("Start computation of a new block if none received since (seconds)", "powDelay", conf, next); - } - ], done); - } + currency: function (conf, done) { + return __awaiter(this, void 0, void 0, function* () { + const answers = yield inquirer.prompt([{ + type: "input", + name: "currency", + message: "Currency name", + default: conf.currency, + validate: function (input) { + return input.match(/^[a-zA-Z0-9-_ ]+$/) ? true : false; + } + }]); + conf.currency = answers.currency; + done(); + }); + }, + parameters: function (conf, done) { + async.waterfall([ + async.apply(simpleFloat, "Universal Dividend %growth", "c", conf), + async.apply(simpleInteger, "Universal Dividend period (in seconds)", "dt", conf), + async.apply(simpleInteger, "First Universal Dividend (UD[0]) amount", "ud0", conf), + async.apply(simpleInteger, "Delay between 2 certifications of a same issuer", "sigPeriod", conf), + async.apply(simpleInteger, "Maximum stock of valid certifications per member", "sigStock", conf), + async.apply(simpleInteger, "Maximum age of a non-written certification", "sigWindow", conf), + async.apply(simpleInteger, "Certification validity duration", "sigValidity", conf), + async.apply(simpleInteger, "Number of valid certifications required to be a member", "sigQty", conf), + async.apply(simpleInteger, "Maximum age of a non-written identity", "idtyWindow", conf), + async.apply(simpleInteger, "Maximum age of a non-written membership", "msWindow", conf), + async.apply(simpleFloat, "Percentage of sentries to be reached to match WoT distance rule", "xpercent", conf), + async.apply(simpleInteger, "Membership validity duration", "msValidity", conf), + async.apply(simpleInteger, "Number of blocks on which is computed median time", "medianTimeBlocks", conf), + async.apply(simpleInteger, "The average time for writing 1 block (wished time)", "avgGenTime", conf), + async.apply(simpleInteger, "Frequency, in number of blocks, to wait for changing common difficulty", "dtDiffEval", conf), + async.apply(simpleFloat, "Weight in percent for previous issuers", "percentRot", conf) + ], done); + }, + pow: function (conf, done) { + async.waterfall([ + function (next) { + simpleInteger("Start computation of a new block if none received since (seconds)", "powDelay", conf, next); + } + ], done); + } }; - -function simpleValue (question, property, defaultValue, conf, validation, done) { - return co(function*() { - const answers = yield inquirer.prompt([{ - type: "input", - name: property, - message: question, - default: conf[property], - validate: validation - }]) - conf[property] = answers[property] - done() - }) +function simpleValue(question, property, defaultValue, conf, validation, done) { + return __awaiter(this, void 0, void 0, function* () { + const answers = yield inquirer.prompt([{ + type: "input", + name: property, + message: question, + default: conf[property], + validate: validation + }]); + conf[property] = answers[property]; + done(); + }); } - -function simpleInteger (question, property, conf, done) { - simpleValue(question, property, conf[property], conf, function (input) { - return input && input.toString().match(/^[0-9]+$/) ? true : false; - }, done); +function simpleInteger(question, property, conf, done) { + simpleValue(question, property, conf[property], conf, function (input) { + return input && input.toString().match(/^[0-9]+$/) ? true : false; + }, done); } - -function simpleFloat (question, property, conf, done) { - simpleValue(question, property, conf[property], conf, function (input) { - return input && input.toString().match(/^[0-9]+(\.[0-9]+)?$/) ? true : false; - }, done); +function simpleFloat(question, property, conf, done) { + simpleValue(question, property, conf[property], conf, function (input) { + return input && input.toString().match(/^[0-9]+(\.[0-9]+)?$/) ? true : false; + }, done); } +//# sourceMappingURL=wizard.js.map \ No newline at end of file diff --git a/app/lib/wizard.ts b/app/lib/wizard.ts new file mode 100644 index 0000000000000000000000000000000000000000..249358d4fba11e979cb4889751c8b3fe4028cf31 --- /dev/null +++ b/app/lib/wizard.ts @@ -0,0 +1,102 @@ +import {ConfDTO} from "./dto/ConfDTO" + +const constants = require('./constants'); +const async = require('async'); +const inquirer = require('inquirer'); +const logger = require('./logger').NewLogger('wizard'); + +export class Wizard { + + static configPoW(conf:ConfDTO) { + return doTasks(['pow'], conf) + } + + static configCurrency(conf:ConfDTO) { + return doTasks(['currency'], conf) + } + + static configUCP(conf:ConfDTO) { + return doTasks(['parameters'], conf) + } +} + +function doTasks (todos:string[], conf:ConfDTO) { + return new Promise((res, rej) => { + async.forEachSeries(todos, function(task:any, callback:any){ + tasks[task] && tasks[task](conf, callback); + }, (err:any) => { + if (err) return rej(err) + return res() + }); + }) +} + +const tasks:any = { + + currency: async function (conf:ConfDTO, done:any) { + const answers = await inquirer.prompt([{ + type: "input", + name: "currency", + message: "Currency name", + default: conf.currency, + validate: function (input:string) { + return input.match(/^[a-zA-Z0-9-_ ]+$/) ? true : false; + } + }]) + conf.currency = answers.currency + done() + }, + + parameters: function (conf:ConfDTO, done:any) { + async.waterfall([ + async.apply(simpleFloat, "Universal Dividend %growth", "c", conf), + async.apply(simpleInteger, "Universal Dividend period (in seconds)", "dt", conf), + async.apply(simpleInteger, "First Universal Dividend (UD[0]) amount", "ud0", conf), + async.apply(simpleInteger, "Delay between 2 certifications of a same issuer", "sigPeriod", conf), + async.apply(simpleInteger, "Maximum stock of valid certifications per member", "sigStock", conf), + async.apply(simpleInteger, "Maximum age of a non-written certification", "sigWindow", conf), + async.apply(simpleInteger, "Certification validity duration", "sigValidity", conf), + async.apply(simpleInteger, "Number of valid certifications required to be a member", "sigQty", conf), + async.apply(simpleInteger, "Maximum age of a non-written identity", "idtyWindow", conf), + async.apply(simpleInteger, "Maximum age of a non-written membership", "msWindow", conf), + async.apply(simpleFloat, "Percentage of sentries to be reached to match WoT distance rule", "xpercent", conf), + async.apply(simpleInteger, "Membership validity duration", "msValidity", conf), + async.apply(simpleInteger, "Number of blocks on which is computed median time", "medianTimeBlocks", conf), + async.apply(simpleInteger, "The average time for writing 1 block (wished time)", "avgGenTime", conf), + async.apply(simpleInteger, "Frequency, in number of blocks, to wait for changing common difficulty", "dtDiffEval", conf), + async.apply(simpleFloat, "Weight in percent for previous issuers", "percentRot", conf) + ], done); + }, + + pow: function (conf:ConfDTO, done:any) { + async.waterfall([ + function (next:any){ + simpleInteger("Start computation of a new block if none received since (seconds)", "powDelay", conf, next); + } + ], done); + } +}; + +async function simpleValue (question:string, property:string, defaultValue:any, conf:any, validation:any, done:any) { + const answers = await inquirer.prompt([{ + type: "input", + name: property, + message: question, + default: conf[property], + validate: validation + }]) + conf[property] = answers[property] + done() +} + +function simpleInteger (question:string, property:string, conf:any, done:any) { + simpleValue(question, property, conf[property], conf, function (input:string) { + return input && input.toString().match(/^[0-9]+$/) ? true : false; + }, done); +} + +function simpleFloat (question:string, property:string, conf:any, done:any) { + simpleValue(question, property, conf[property], conf, function (input:string) { + return input && input.toString().match(/^[0-9]+(\.[0-9]+)?$/) ? true : false; + }, done); +} diff --git a/app/modules/wizard.ts b/app/modules/wizard.ts index 943f227419f118c6d80385339992a62ed76f96c4..938b8f4030f21e3c8ce51ae5770100ef2251e057 100644 --- a/app/modules/wizard.ts +++ b/app/modules/wizard.ts @@ -1,7 +1,7 @@ import {ConfDTO} from "../lib/dto/ConfDTO" +import {Wizard} from "../lib/wizard" const _ = require('underscore') -const wizard = require('../lib/wizard'); const logger = require('../lib/logger').NewLogger('wizard'); module.exports = { @@ -9,9 +9,9 @@ module.exports = { wizard: { // The wizard itself also defines its personal tasks - 'currency': (conf:ConfDTO) => wizard().configCurrency(conf), - 'pow': (conf:ConfDTO) => wizard().configPoW(conf), - 'parameters': (conf:ConfDTO) => wizard().configUCP(conf) + 'currency': (conf:ConfDTO) => Wizard.configCurrency(conf), + 'pow': (conf:ConfDTO) => Wizard.configPoW(conf), + 'parameters': (conf:ConfDTO) => Wizard.configUCP(conf) }, cli: [{ diff --git a/index.js b/index.js index 07bc3b3454dc725b19ddd7fb3c9e061986c1c5ca..25d669f2334a4672b9ce724523c2d3f52890fc97 100644 --- a/index.js +++ b/index.js @@ -8,7 +8,6 @@ const _ = require('underscore'); const Server = require('./server'); const directory = require('./app/lib/system/directory'); const constants = require('./app/lib/constants'); -const wizard = require('./app/lib/wizard'); const logger = require('./app/lib/logger').NewLogger('duniter'); const configDependency = require('./app/modules/config');