diff --git a/.eslintignore b/.eslintignore index e7d0d019..888e8d44 100644 --- a/.eslintignore +++ b/.eslintignore @@ -10,5 +10,5 @@ tmp public/node_modules public/bower_components public/static -test/lisk-js helpers/bignum.js +docs/jsdoc/scripts/prettify/prettify.js diff --git a/.eslintrc.json b/.eslintrc.json index 5105b53a..3ecd48f8 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,32 +1,52 @@ { + "env": { + "commonjs": true, + "es2021": true, + "browser": true, + "node": true + }, + "extends": [ + "google" + ], "parserOptions": { - "ecmaVersion": 5, - "sourceType": "module" + "ecmaVersion": 12 }, "rules": { - "semi": "error", - "no-eq-null": "off", - "indent": ["off", 4], - "eqeqeq": "off", - "curly": "error", - "no-undef": "error", - "quotes": ["error", "single"], + "max-len": ["error", + { "code": 200, + "ignoreTrailingComments": true, + "ignoreUrls": true, + "ignoreStrings": true, + "ignoreTemplateLiterals": true, + "ignoreRegExpLiterals": true + }], + "require-jsdoc": ["off"], + "no-var": ["off"], + "comma-dangle": ["error", "never"], + "brace-style": ["error", "1tbs", { "allowSingleLine": true }], + "block-spacing": ["error", "always"], + "new-cap": ["off"], + "prefer-rest-params": ["off"], + "no-unused-vars": ["off"], + "no-invalid-this": ["off"], + "camelcase": ["off"], + "one-var": ["off"], + "no-throw-literal": ["off"], + "object-curly-spacing": ["error", "always"], + "prefer-const": ["off"], + "quote-props": ["off"], + "guard-for-in": ["off"], + "valid-jsdoc": ["off"], + "prefer-spread": ["off"], "space-before-function-paren": ["error", { "anonymous": "always", "named": "always", "asyncArrow": "ignore" }], - "callback-return": "off", - "global-require": "off", - "handle-callback-err": "off", - "no-mixed-requires": "off", - "no-new-require": "off" - }, - "env": { - "browser": true, - "node": true + "space-infix-ops": ["error", { "int32Hint": true }] }, "globals": { + "PR": true, "it": true, "describe": true, "before": true, @@ -35,5 +55,4 @@ "afterEach": true }, "plugins": [] - } diff --git a/.gitignore b/.gitignore index 5b17847e..75753f6d 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ .ed25519-node .idea/ .project +.vscode/ __MACOSX/ dapps/ docs/jsdoc/ @@ -13,7 +14,11 @@ release ssl/ stacktrace* test/.coverage-unit +test/.coverage +test/.nyc_output tmp sftp-config.json *.swp *.swo +package-lock.json + diff --git a/.mocharc.js b/.mocharc.js new file mode 100644 index 00000000..55da57ce --- /dev/null +++ b/.mocharc.js @@ -0,0 +1,5 @@ +'use strict' + +module.exports = { + timeout: '1200s' +} \ No newline at end of file diff --git a/Gruntfile.js b/Gruntfile.js index 5ec5030f..9fab42df 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -4,140 +4,135 @@ var moment = require('moment'); var util = require('util'); module.exports = function (grunt) { - var files = [ - 'logger.js', - 'api/**/*.js', - 'helpers/**/*.js', - 'modules/**/*.js', - 'logic/*.js', - 'schema/**/*.js', - 'sql/**/*.js', - 'app.js' - ]; - - var today = moment().format('HH:mm:ss DD/MM/YYYY'); - - var config = require('./config.json'); - - var release_dir = __dirname + '/release/'; - var version_dir = release_dir + config.version; - - var maxBufferSize = require('buffer').kMaxLength - 1; - - grunt.initConfig({ - obfuscator: { - files: files, - entry: 'app.js', - out: 'release/app.js', - strings: true, - root: __dirname - }, - - exec: { - package: { - command: function () { - return [ - util.format('mkdir -p %s', version_dir), - util.format('mkdir -p %s/logs', version_dir), - util.format('mkdir -p %s/pids', version_dir), - util.format('mkdir -p %s/public', version_dir), - util.format('cp %s/app.js %s', release_dir, version_dir), - util.format('cp %s/config.json %s', __dirname, version_dir), - util.format('cp %s/package.json %s', __dirname, version_dir), - util.format('cp %s/genesisBlock.json %s', __dirname, version_dir), - util.format('cp %s/LICENSE %s', __dirname, version_dir), - util.format('mkdir -p %s/sql/migrations', version_dir), - util.format('cp %s/sql/*.sql %s/sql/', __dirname, version_dir), - util.format('cp %s/sql/migrations/*.sql %s/sql/migrations/', __dirname, version_dir), - util.format('cd %s/public && mkdir -p ./static', __dirname), - 'npm install && bower install && grunt release && cd ../', - util.format('cp %s/public/wallet.html %s/public/', __dirname, version_dir), - util.format('cp %s/public/loading.html %s/public/', __dirname, version_dir), - util.format('cp -Rf %s/public/images %s/public/', __dirname, version_dir), - util.format('cp -Rf %s/public/partials %s/public/', __dirname, version_dir), - util.format('cp -RfL %s/public/static %s/public/', __dirname, version_dir), - util.format('mkdir -p %s/public/node_modules', version_dir), - util.format('cp -Rf %s/public/node_modules/chart.js %s/public/node_modules', __dirname, version_dir), - util.format('mkdir -p %s/public/bower_components', version_dir), - util.format('mkdir -p %s/public/socket.io', version_dir), - util.format('cp -Rf %s/public/bower_components/jquery %s/public/bower_components', __dirname, version_dir), - util.format('cp -Rf %s/public/bower_components/materialize %s/public/bower_components', __dirname, version_dir), - util.format('cp -Rf %s/public/bower_components/blob %s/public/bower_components', __dirname, version_dir), - util.format('cp -Rf %s/public/bower_components/file-saver %s/public/bower_components', __dirname, version_dir) - ].join(' && '); - } - }, - - folder: { - command: 'mkdir -p ' + release_dir - }, - - build: { - command: 'cd ' + version_dir + '/ && touch build && echo "v' + today + '" > build' - }, - - coverage: { - command: 'export NODE_ENV=TEST && node_modules/.bin/istanbul cover --dir test/.coverage-unit ./node_modules/.bin/_mocha', - maxBuffer: maxBufferSize - }, - - coverageSingle: { - command: 'export NODE_ENV=TEST && node_modules/.bin/istanbul cover --dir test/.coverage-unit ./node_modules/.bin/_mocha $TEST', - maxBuffer: maxBufferSize - }, - - fetchCoverage: { - command: 'rm -rf ./test/.coverage-func.zip; curl -o ./test/.coverage-func.zip $HOST/coverage/download', - maxBuffer: maxBufferSize - } - }, - - compress: { - main: { - options: { - archive: version_dir + '.tar.gz', - mode: 'tgz', - level: 6 - }, - files: [ - { expand: true, cwd: release_dir, src: [config.version + '/**'], dest: './' } - ] - } - }, - - eslint: { - options: { - configFile: '.eslintrc.json', - format: 'codeframe', - fix: false - }, - target: [ - 'api', - 'helpers', - 'modules', - 'logic', - 'schema', - 'tasks', - 'test' - ] - } - }); - - grunt.loadTasks('tasks'); - - grunt.loadNpmTasks('grunt-obfuscator'); - grunt.loadNpmTasks('grunt-exec'); - grunt.loadNpmTasks('grunt-contrib-compress'); - grunt.loadNpmTasks('grunt-eslint'); - - grunt.registerTask('default', ['release']); - grunt.registerTask('release', ['exec:folder', 'obfuscator', 'exec:package', 'exec:build', 'compress']); - grunt.registerTask('jenkins', ['exec:coverageSingle']); - grunt.registerTask('eslint-nofix', ['eslint']); - grunt.registerTask('test', ['eslint', 'exec:coverage']); - - grunt.registerTask('eslint-fix', 'Run eslint and fix formatting', function () { - grunt.config.set('eslint.options.fix', true); - grunt.task.run('eslint'); - }); + var files = [ + 'logger.js', + 'api/**/*.js', + 'helpers/**/*.js', + 'modules/**/*.js', + 'logic/*.js', + 'schema/**/*.js', + 'sql/**/*.js', + 'app.js' + ]; + + var today = moment().format('YYYY-MM-DD HH:mm:ss'); + + var config = require('./config.json'); + + var release_dir = __dirname + '/release/'; + var version_dir = release_dir + 'current'; + + var maxBufferSize = require('buffer').kMaxLength - 1; + + grunt.initConfig({ + obfuscator: { + files: files, + entry: 'app.js', + out: 'release/app.js', + strings: true, + root: __dirname + }, + + exec: { + package: { + command: function () { + return [ + util.format('mkdir -p %s', version_dir), + util.format('mkdir -p %s/logs', version_dir), + util.format('mkdir -p %s/pids', version_dir), + util.format('mkdir -p %s/public', version_dir), + util.format('cp %s/app.js %s', release_dir, version_dir), + util.format('cp %s/config.json %s', __dirname, version_dir), + util.format('cp %s/package.json %s', __dirname, version_dir), + util.format('cp %s/genesisBlock.json %s', __dirname, version_dir), + util.format('cp %s/LICENSE %s', __dirname, version_dir), + util.format('mkdir -p %s/sql/migrations', version_dir), + util.format('cp %s/sql/*.sql %s/sql/', __dirname, version_dir), + util.format('cp %s/sql/migrations/*.sql %s/sql/migrations/', __dirname, version_dir), + util.format('cd %s/public && mkdir -p ./static', __dirname), + 'npm install && bower install && grunt release && cd ../', + util.format('cp %s/public/wallet.html %s/public/', __dirname, version_dir), + util.format('cp %s/public/loading.html %s/public/', __dirname, version_dir), + util.format('cp -Rf %s/public/images %s/public/', __dirname, version_dir), + util.format('cp -Rf %s/public/partials %s/public/', __dirname, version_dir), + util.format('cp -RfL %s/public/static %s/public/', __dirname, version_dir), + util.format('mkdir -p %s/public/node_modules', version_dir), + util.format('cp -Rf %s/public/node_modules/chart.js %s/public/node_modules', __dirname, version_dir), + util.format('mkdir -p %s/public/bower_components', version_dir), + util.format('mkdir -p %s/public/socket.io', version_dir), + util.format('cp -Rf %s/public/bower_components/jquery %s/public/bower_components', __dirname, version_dir), + util.format('cp -Rf %s/public/bower_components/materialize %s/public/bower_components', __dirname, version_dir), + util.format('cp -Rf %s/public/bower_components/blob %s/public/bower_components', __dirname, version_dir), + util.format('cp -Rf %s/public/bower_components/file-saver %s/public/bower_components', __dirname, version_dir) + ].join(' && '); + } + }, + + folder: { + command: 'mkdir -p ' + release_dir + }, + + build: { + command: 'cd ' + version_dir + '/ && touch build && echo "v' + today + '" > build' + }, + + coverage: { + command: 'export NODE_ENV=TEST && npx nyc --reporter html --temp-dir test/.nyc_output --report-dir test/.coverage npm run test:all', + maxBuffer: maxBufferSize + }, + + coverageSingle: { + command: 'export NODE_ENV=TEST && npx nyc --reporter html --temp-dir test/.nyc_output --report-dir test/.coverage mocha $TEST', + maxBuffer: maxBufferSize + }, + + fetchCoverage: { + command: 'rm -rf ./test/.coverage-func.zip; curl -o ./test/.coverage-func.zip $HOST/coverage/download', + maxBuffer: maxBufferSize + } + }, + + compress: { + main: { + options: { + archive: version_dir + '.tar.gz', + mode: 'tgz', + level: 6 + }, + files: [ + { expand: true, cwd: release_dir, src: ['current' + '/**'], dest: './' } + ] + } + }, + + eslint: { + options: { + configFile: '.eslintrc.json', + format: 'codeframe', + fix: false + }, + target: [ + 'api', + 'helpers', + 'modules', + 'logic', + 'schema', + 'tasks', + 'test' + ] + } + }); + + grunt.loadTasks('tasks'); + + grunt.loadNpmTasks('grunt-contrib-obfuscator'); + grunt.loadNpmTasks('grunt-exec'); + grunt.loadNpmTasks('grunt-contrib-compress'); + grunt.loadNpmTasks('grunt-eslint'); + + grunt.registerTask('default', ['release']); + grunt.registerTask('release', ['exec:folder', 'obfuscator', 'exec:package', 'exec:build', 'compress']); + grunt.registerTask('test-single', ['exec:coverageSingle']); + grunt.registerTask('eslint-nofix', ['eslint']); + grunt.registerTask('test', ['eslint', 'exec:coverage']); }; diff --git a/Jenkinsfile b/Jenkinsfile deleted file mode 100644 index c2608049..00000000 --- a/Jenkinsfile +++ /dev/null @@ -1,439 +0,0 @@ -def initBuild() { - sh '''#!/bin/bash - pkill -f app.js -9 || true - sudo service postgresql restart - dropdb lisk_test || true - createdb lisk_test - ''' - deleteDir() - checkout scm -} - -def buildDependency() { - try { - sh '''#!/bin/bash - - # Install Deps - npm install - - # Install Nodejs - tar -zxf ~/lisk-node-Linux-x86_64.tar.gz - - # Build submodules - git submodule init - git submodule update - cd public/ - npm install - bower install - grunt release - ''' - } catch (err) { - currentBuild.result = 'FAILURE' - error('Stopping build, installation failed') - } -} - -def startLisk() { - try { - sh '''#!/bin/bash - cd test/lisk-js/; npm install; cd ../.. - cp test/config.json test/genesisBlock.json . - export NODE_ENV=test - JENKINS_NODE_COOKIE=dontKillMe ~/start_lisk.sh - ''' - } catch (err) { - currentBuild.result = 'FAILURE' - error('Stopping build, Lisk failed') - } -} - -lock(resource: "Lisk-Core-Nodes", inversePrecedence: true) { - stage ('Prepare Workspace') { - parallel( - "Build Node-01" : { - node('node-01'){ - initBuild() - } - }, - "Build Node-02" : { - node('node-02'){ - initBuild() - } - }, - "Build Node-03" : { - node('node-03'){ - initBuild() - } - }, - "Initialize Master Workspace" : { - node('master-01'){ - sh ''' - cd /var/lib/jenkins/coverage/ - rm -rf node-0* - rm -rf *.zip - rm -rf coverage-unit/* - rm -rf lisk/* - rm -f merged-lcov.info - ''' - deleteDir() - checkout scm - } - } - ) - } - - stage ('Build Dependencies') { - parallel( - "Build Dependencies Node-01" : { - node('node-01'){ - buildDependency() - } - }, - "Build Dependencies Node-02" : { - node('node-02'){ - buildDependency() - } - }, - "Build Dependencies Node-03" : { - node('node-03'){ - buildDependency() - } - } - ) - } - - stage ('Start Lisk') { - parallel( - "Start Lisk Node-01" : { - node('node-01'){ - startLisk() - } - }, - "Start Lisk Node-02" : { - node('node-02'){ - startLisk() - } - }, - "Start Lisk Node-03" : { - node('node-03'){ - startLisk() - } - } - ) - } - - stage ('Parallel Tests') { - parallel( - "ESLint" : { - node('node-01'){ - sh ''' - cd "$(echo $WORKSPACE | cut -f 1 -d '@')" - npm run eslint - ''' - } - }, - "Functional Accounts" : { - node('node-01'){ - sh ''' - export TEST=test/api/accounts.js TEST_TYPE='FUNC' - cd "$(echo $WORKSPACE | cut -f 1 -d '@')" - npm run jenkins - ''' - } - }, - "Functional Blocks" : { - node('node-01'){ - sh ''' - export TEST=test/api/blocks.js TEST_TYPE='FUNC' - cd "$(echo $WORKSPACE | cut -f 1 -d '@')" - npm run jenkins - ''' - } - }, - "Functional Delegates" : { - node('node-01'){ - sh ''' - export TEST=test/api/delegates.js TEST_TYPE='FUNC' - cd "$(echo $WORKSPACE | cut -f 1 -d '@')" - npm run jenkins - ''' - } - }, - "Functional Dapps" : { - node('node-01'){ - sh ''' - export TEST=test/api/dapps.js TEST_TYPE='FUNC' - cd "$(echo $WORKSPACE | cut -f 1 -d '@')" - npm run jenkins - ''' - } - }, - "Functional Loader" : { - node('node-01'){ - sh ''' - export TEST=test/api/loader.js TEST_TYPE='FUNC' - cd "$(echo $WORKSPACE | cut -f 1 -d '@')" - npm run jenkins - ''' - } - }, - "Functional Multisignatures" : { - node('node-01'){ - sh ''' - export TEST=test/api/multisignatures.js TEST_TYPE='FUNC' - cd "$(echo $WORKSPACE | cut -f 1 -d '@')" - npm run jenkins - ''' - } - }, - "Functional Signatures" : { - node('node-01'){ - sh ''' - export TEST=test/api/signatures.js TEST_TYPE='FUNC' - cd "$(echo $WORKSPACE | cut -f 1 -d '@')" - npm run jenkins - ''' - } - }, - "Functional Transactions" : { - node('node-01'){ - sh ''' - export TEST=test/api/transactions.js TEST_TYPE='FUNC' - cd "$(echo $WORKSPACE | cut -f 1 -d '@')" - npm run jenkins - ''' - } - }, //End node-01 tests - "Functional Peer - Peer" : { - node('node-02'){ - sh ''' - export TEST=test/api/peer.js TEST_TYPE='FUNC' - cd "$(echo $WORKSPACE | cut -f 1 -d '@')" - npm run jenkins - ''' - } - }, - "Functional Peer - Dapp" : { - node('node-02'){ - sh ''' - export TEST=test/api/peer.dapp.js TEST_TYPE='FUNC' - cd "$(echo $WORKSPACE | cut -f 1 -d '@')" - npm run jenkins - ''' - } - }, - "Functional Peer - Blocks" : { - node('node-02'){ - sh ''' - export TEST=test/api/peer.blocks.js TEST_TYPE='FUNC' - cd "$(echo $WORKSPACE | cut -f 1 -d '@')" - npm run jenkins - ''' - } - }, - "Functional Peer - Signatures" : { - node('node-02'){ - sh ''' - export TEST=test/api/peer.signatures.js TEST_TYPE='FUNC' - cd "$(echo $WORKSPACE | cut -f 1 -d '@')" - npm run jenkins - ''' - } - }, - "Functional Peer - Transactions Collision" : { - node('node-02'){ - sh ''' - export TEST=test/api/peer.transactions.collision.js TEST_TYPE='FUNC' - cd "$(echo $WORKSPACE | cut -f 1 -d '@')" - npm run jenkins - ''' - } - }, - "Functional Peer - Transactions Delegates" : { - node('node-02'){ - sh ''' - export TEST=test/api/peer.transactions.delegates.js TEST_TYPE='FUNC' - cd "$(echo $WORKSPACE | cut -f 1 -d '@')" - npm run jenkins - ''' - } - }, - "Functional Peer - Transactions Main" : { - node('node-02'){ - sh ''' - export TEST=test/api/peer.transactions.main.js TEST_TYPE='FUNC' - cd "$(echo $WORKSPACE | cut -f 1 -d '@')" - npm run jenkins - ''' - } - }, - "Functional Peer - Transaction Signatures" : { - node('node-02'){ - sh ''' - export TEST=test/api/peer.transactions.signatures.js TEST_TYPE='FUNC' - cd "$(echo $WORKSPACE | cut -f 1 -d '@')" - npm run jenkins - ''' - } - }, - "Functional Peer - Peers" : { - node('node-02'){ - sh ''' - export TEST=test/api/peers.js TEST_TYPE='FUNC' - cd "$(echo $WORKSPACE | cut -f 1 -d '@')" - npm run jenkins - ''' - } - }, - "Functional Peer - Votes" : { - node('node-02'){ - sh ''' - export TEST=test/api/peer.transactions.votes.js TEST_TYPE='FUNC' - cd "$(echo $WORKSPACE | cut -f 1 -d '@')" - npm run jenkins - ''' - } - }, // End Node-02 Tests - "Unit - Helpers" : { - node('node-03'){ - sh ''' - export TEST=test/unit/helpers TEST_TYPE='UNIT' - cd "$(echo $WORKSPACE | cut -f 1 -d '@')" - npm run jenkins - ''' - } - }, - "Unit - Modules" : { - node('node-03'){ - sh ''' - export TEST=test/unit/modules TEST_TYPE='UNIT' - cd "$(echo $WORKSPACE | cut -f 1 -d '@')" - npm run jenkins - ''' - } - }, - "Unit - SQL" : { - node('node-03'){ - sh ''' - export TEST=test/unit/sql TEST_TYPE='UNIT' - cd "$(echo $WORKSPACE | cut -f 1 -d '@')" - npm run jenkins - ''' - } - }, - "Unit - Logic" : { - node('node-03'){ - sh ''' - export TEST=test/unit/logic TEST_TYPE='UNIT' - cd "$(echo $WORKSPACE | cut -f 1 -d '@')" - npm run jenkins - ''' - } - }, - "Functional Stress - Transactions" : { - node('node-03'){ - sh ''' - export TEST=test/api/peer.transactions.stress.js TEST_TYPE='FUNC' - cd "$(echo $WORKSPACE | cut -f 1 -d '@')" - npm run jenkins - ''' - } - } - ) // End Parallel - } - - stage ('Gather Coverage') { - parallel( - "Gather Coverage Node-01" : { - node('node-01'){ - sh '''#!/bin/bash - export HOST=127.0.0.1:4000 - npm run fetchCoverage - # Submit coverage reports to Master - scp test/.coverage-func.zip jenkins@master-01:/var/lib/jenkins/coverage/coverage-func-node-01.zip - ''' - } - }, - "Gather Coverage Node-02" : { - node('node-02'){ - sh '''#!/bin/bash - export HOST=127.0.0.1:4000 - npm run fetchCoverage - # Submit coverage reports to Master - scp test/.coverage-func.zip jenkins@master-01:/var/lib/jenkins/coverage/coverage-func-node-02.zip - ''' - } - }, - "Gather Coverage Node-03" : { - node('node-03'){ - sh '''#!/bin/bash - export HOST=127.0.0.1:4000 - npm run fetchCoverage - # Submit coverage reports to Master - scp test/.coverage-unit/* jenkins@master-01:/var/lib/jenkins/coverage/coverage-unit/ - scp test/.coverage-func.zip jenkins@master-01:/var/lib/jenkins/coverage/coverage-func-node-03.zip - ''' - } - } - ) - } - - stage ('Submit Coverage') { - node('master-01'){ - sh ''' - cd /var/lib/jenkins/coverage/ - unzip coverage-func-node-01.zip -d node-01 - unzip coverage-func-node-02.zip -d node-02 - unzip coverage-func-node-03.zip -d node-03 - bash merge_lcov.sh . merged-lcov.info - cp merged-lcov.info $WORKSPACE/merged-lcov.info - cp .coveralls.yml $WORKSPACE/.coveralls.yml - cd $WORKSPACE - cat merged-lcov.info | coveralls -v - ''' - } - } - - stage ('Cleanup') { - parallel( - "Cleanup Node-01" : { - node('node-01'){ - sh ''' - pkill -f app.js -9 - ''' - } - }, - "Cleanup Node-02" : { - node('node-02'){ - sh ''' - pkill -f app.js -9 - ''' - } - }, - "Cleanup Node-03" : { - node('node-03'){ - sh ''' - pkill -f app.js -9 - ''' - } - }, - "Cleanup Master" : { - node('master-01'){ - sh ''' - cd /var/lib/jenkins/coverage/ - rm -rf node-0* - rm -rf *.zip - rm -rf coverage-unit/* - rm -f merged-lcov.info - rm -rf lisk/* - ''' - } - } - ) - } - - stage ('Set milestone') { - milestone 1 - currentBuild.result = 'SUCCESS' - } -} diff --git a/README.md b/README.md index c1e71839..7290e3d0 100644 --- a/README.md +++ b/README.md @@ -1,68 +1,80 @@ # ADAMANT -ADAMANT is **decentralized messaging platform** based on Lisk codebase and written in JavaScript. For more information please refer to our website: . +ADAMANT is a **decentralized blockchain messaging platform**. Applications use ADAMANT as an anonymous and encrypted relay and storage to enable messaging features. As examples, see [Messenger app](https://github.com/Adamant-im/adamant-im), [Blockchain 2FA](https://github.com/Adamant-im/adamant-2fa) and [Decentralized cryptocurrency exchanger](https://github.com/Adamant-im/adamant-exchangebot) implementations. -ADAMANT is a secure and anonymous messenger, encrypted with Blockchain. ADAMANT [solves security flaws](https://medium.com/adamant-im/adamant-security-features-e7cc836ff52c) typical for P2P and centralized messagers. +For more information refer to ADAMANT website: . -Highlights: +![ADAMANT nodes](./docs/adm-nodes.jpeg) -- The only one which is Blockchain-powered -- Anonymous. No emails, no phone numbers -- No access to user device’s data (like address book or location) -- IP is hidden for partners -- Web app, Tor Web app, iOS, Android, Windows, GUN/Linux and Mac OS apps available. Try it now: -- Messages are End-to-end encypted with curve25519xsalsa20poly1305 (NaCl box) and signed with Ed25519 EdDSA -- Trusted. Open-source project. -- Brand new [Fair dPoS consensus](https://medium.com/adamant-im/fair-delegate-system-in-dpos-568e5c3c86c8) -- Integrated crypto Wallets, In-Chat transfers and Exchange -- Secure alternative to 2FA via SMS +Additional information: -**Use this repository to run your own ADAMANT node and support true messaging decentralization. You can also promote your node to a delegate to forge blocks and receive ADM block rewards**. How to run ADAMANT node: [Instructions for users](https://medium.com/adamant-im/how-to-run-your-adamant-node-on-ubuntu-990e391e8fcc). +- [How decentralized blockchain messenger works](https://medium.com/adamant-im/how-decentralized-blockchain-messenger-works-b9932834a639) +- [Encryption overview in ADAMANT Messenger](https://medium.com/adamant-im/encryption-overview-in-adamant-messenger-878ecec1ff78) [![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](http://www.gnu.org/licenses/gpl-3.0) -# API Documentation +## API Documentation -Comprehensive [API specification](https://github.com/Adamant-im/adamant/wiki) is avalable. +Comprehensive [API specification](https://github.com/Adamant-im/adamant/wiki) is available. -The manual describes the procedure for working with accounts and/or addresses, transactions, chats, and a KVS database. Furthermore, you will find all the necessary information on transactions and messages types. Additionally, the manual suggests valuable information on creating new accounts and encrypting and decrypting messages. +The manual describes API endpoints to manage accounts, transactions, chats, and a key-value storage (KVS). Additionally, the manual suggests valuable information on creating new accounts and encrypting and decrypting messages. -# Set up +## Set up -**NOTE:** The following information is applicable to **Ubuntu 16 or 18 versions**. +[How to run ADAMANT node (instructions for users)](https://medium.com/adamant-im/how-to-run-your-adamant-node-on-ubuntu-990e391e8fcc). You can skip them if you are experienced Linux user. -For making process simplier, you can use tools/install_ubuntu_dependencies.sh script. +### Requirements -## Prerequisites — In order +- Ubuntu 18/20 (others are not tested) +- 2 GB RAM +- 50 GB disk space as on August 2021 + +### Installation script + +For new droplets, use the [Installation script](./tools/install_node.sh), included in this repository, or run it from the ADAMANT website: + +`sudo bash -c "$(wget -O - https://adamant.im/install_node.sh)"` + +The script updates Ubuntu packages, creates user named adamant, installs PostgreSQL, Node.js and other necessary packages, sets up ADAMANT node, and optionally downloads up-to-date ADAMANT blockchain image. + +Script parameters: + +- `-b`: choose GitHub branch for node installation. Example: `-b dev`. Default is `master`. +- `-n`: choose `mainnet` or `testnet` network. Example: `-n testnet`. Default is `mainnet`. + +F. e., + +`sudo bash -c "$(wget -O - https://adamant.im/install_node.sh)" -O -b dev -n testnet` + +### Prerequisites - Tool chain components — Used for compiling dependencies `sudo apt-get install -y python build-essential curl automake autoconf libtool` -- Git () — Used for cloning and updating ADAMANT +- Git — Used for cloning and updating ADAMANT `sudo apt-get install -y git` -- Node.js () — Node.js serves as the underlying engine for code execution +- Node.js — Node.js serves as the underlying engine for code execution System wide via package manager: ``` - curl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash - + curl -sL https://deb.nodesource.com/setup_14.x | sudo -E bash - sudo apt-get install -y nodejs ``` - Locally using [nvm](https://github.com/creationix/nvm): + Locally using nvm: ``` - curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash - nvm install v10.14.2 + curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.38.0/install.sh | bash + nvm i --lts=fermium ``` -- Install PostgreSQL (version 9.6.2): +- Install PostgreSQL: ``` - sudo apt-get purge -y postgres* sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt/ `lsb_release -cs`-pgdg main" > /etc/apt/sources.list.d/pgdg.list' wget -q https://www.postgresql.org/media/keys/ACCC4CF8.asc -O - | sudo apt-key add - sudo apt-get update @@ -81,14 +93,11 @@ For making process simplier, you can use tools/install_ubuntu_dependencies.sh sc sudo -u postgres psql -d adamant_main -c "alter user "$USER" with password 'password';" ``` -- PM2 () — PM2 manages the node process for ADAMANT (Optional) +- pm2 — Manages the node process for ADAMANT `sudo npm install -g pm2` - - - -## Installation Steps +### Installation Steps Clone the ADAMANT repository using Git and initialize the modules. @@ -98,27 +107,21 @@ cd adamant npm install ``` -## Alternative Ubuntu install process - -Alternative way to install ADAMANT with prerequisites. You need only Git installed locally. Or instead of cloning you can download and unpack zip from GitHub. +Then set db.password in config: ``` -# Create user -adduser adamant -sudo usermod -aG sudo adamant -su - adamant +nano config.json +``` -git clone https://github.com/Adamant-im/adamant -cd adamant -sh tools/install_ubuntu_dependencies.sh +### Bootstrap with a blockchain image -sudo -u postgres createuser --createdb $USER -createdb adamant_test -createdb adamant_main -sudo -u postgres psql -d adamant_test -c "alter user "$USER" with password 'password';" -sudo -u postgres psql -d adamant_main -c "alter user "$USER" with password 'password';" +Blockchain image saves time on node sync but you must completely trust the image. If you skip this step, your node will check every single transaction, which takes time (up for several days). -npm install +``` +wget https://explorer.adamant.im/db_backup.sql.gz +gunzip db_backup.sql.gz +psql adamant_main < db_backup.sql +rm db_backup.sql ``` ## Managing ADAMANT @@ -139,57 +142,34 @@ To stop ADAMANT after it has been started with `pm2`, issue the following comman `pm2 stop adamant` -**NOTE:** The **port**, **address** and **config-path** can be overridden by providing the relevant command switch: +To add ADAMANT node to crontab for autostart after system reboot (fix installation path): -``` -pm2 start --name adamant app.js -- -p [port] -a [address] -c [config-path] -``` +`crontab -l | { cat; echo "@reboot cd /home/adamant/adamant && pm2 start --name adamant app.js"; } | crontab -` ## Tests -Before running any tests, please ensure ADAMANT is configured to run on the same testnet that is used by the test-suite. - -Replace **config.json** and **genesisBlock.json** with the corresponding files under the **test** directory: - -``` -cp test/config.json test/genesisBlock.json . -``` - -**NOTE:** If the node was started with a different genesis block previous, trauncate the database before running tests. - -``` -dropdb adamant_test -createdb adamant_test -``` - -**NOTE:** The master passphrase for this genesis block is as follows: - -``` -wagon stock borrow episode laundry kitten salute link globe zero feed marble -``` - -Launch ADAMANT (runs on port 36667): +Before running any tests, run ADAMANT node with a testnet configuration: ``` -node app.js +npm run start:testnet ``` -Run the test suite: +Then run the test suite: ``` -npm test +npm run test:full ``` Run individual tests: ``` -npm test -- test/lib/accounts.js -npm test -- test/lib/transactions.js +npm run test:single test/api/accounts.js ``` ## Authors -- ADAMANT Tech Labs: Dmitriy Soloduhin, Aleksei Lebedev, Sergey Ushakov +- ADAMANT Foundation: Aleksei Lebedev +- ADAMANT Tech Labs: Aleksei Lebedev, Dmitriy Soloduhin, Sergey Ushakov - Boris Povod - Pavel Nekrasov - Sebastian Stupurac @@ -200,7 +180,8 @@ npm test -- test/lib/transactions.js ## License -Copyright © 2017-2019 ADAMANT TECH LABS LP +Copyright © 2020-2021 ADAMANT Foundation +Copyright © 2017-2020 ADAMANT TECH LABS LP Copyright © 2016-2017 Lisk Foundation This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. diff --git a/api/http/accounts.js b/api/http/accounts.js index dce8ec96..e1b1ad83 100644 --- a/api/http/accounts.js +++ b/api/http/accounts.js @@ -8,18 +8,18 @@ var schema = require('../../schema/accounts.js'); * Binds api with modules and creates common url. * - End point: `/api/accounts` * - Public API: - - post /open - - post /new - - get /getBalance - - get /getPublicKey - - post /generatePublicKey - - get /delegates - - get /delegates/fee - - put /delegates - - post /delegates - - get / + - post /open + - post /new + - get /getBalance + - get /getPublicKey + - post /generatePublicKey + - get /delegates + - get /delegates/fee + - put /delegates + - post /delegates + - get / * - Private API: - * - get /count + * - get /count * @memberof module:accounts * @requires helpers/Router * @requires helpers/httpApi @@ -29,35 +29,34 @@ var schema = require('../../schema/accounts.js'); */ function AccountsHttpApi (accountsModule, app) { - - var router = new Router(); - - router.map(accountsModule.shared, { - 'post /open': 'open', - 'post /new': 'new', - 'get /getBalance': 'getBalance', - 'get /getPublicKey': 'getPublickey', - 'post /generatePublicKey': 'generatePublicKey', - 'get /delegates': 'getDelegates', - 'get /delegates/fee': 'getDelegatesFee', - 'put /delegates': 'addDelegates', - 'post /delegates': 'voteForDelegates', - 'get /': 'getAccount' - }); - - router.map(accountsModule.internal, { - 'get /count': 'count' - }); - - if (process.env.DEBUG && process.env.DEBUG.toUpperCase() === 'TRUE') { - router.map(accountsModule.internal, {'get /getAllAccounts': 'getAllAccounts'}); - } - - if (process.env.TOP && process.env.TOP.toUpperCase() === 'TRUE') { - router.get('/top', httpApi.middleware.sanitize('query', schema.top, accountsModule.internal.top)); - } - - httpApi.registerEndpoint('/api/accounts', app, router, accountsModule.isLoaded); + var router = new Router(); + + router.map(accountsModule.shared, { + 'post /open': 'open', + 'post /new': 'new', + 'get /getBalance': 'getBalance', + 'get /getPublicKey': 'getPublickey', + 'post /generatePublicKey': 'generatePublicKey', + 'get /delegates': 'getDelegates', + 'get /delegates/fee': 'getDelegatesFee', + 'put /delegates': 'addDelegates', + 'post /delegates': 'voteForDelegates', + 'get /': 'getAccount' + }); + + router.map(accountsModule.internal, { + 'get /count': 'count' + }); + + if (process.env.DEBUG && process.env.DEBUG.toUpperCase() === 'TRUE') { + router.map(accountsModule.internal, { 'get /getAllAccounts': 'getAllAccounts' }); + } + + if (process.env.TOP && process.env.TOP.toUpperCase() === 'TRUE') { + router.get('/top', httpApi.middleware.sanitize('query', schema.top, accountsModule.internal.top)); + } + + httpApi.registerEndpoint('/api/accounts', app, router, accountsModule.isLoaded); } module.exports = AccountsHttpApi; diff --git a/api/http/blocks.js b/api/http/blocks.js index 799ab474..b19a3100 100644 --- a/api/http/blocks.js +++ b/api/http/blocks.js @@ -7,18 +7,18 @@ var httpApi = require('../../helpers/httpApi'); * Binds api with modules and creates common url. * - End point: `/api/blocks` * - Public API: - * - get /get - * - get / - * - get /getBroadhash - * - get /getEpoch - * - get /getHeight - * - get /getNethash - * - get /getFee - * - get /getFees - * - get /getMilestone - * - get /getReward - * - get /getSupply - * - get /getStatus + * - get /get + * - get / + * - get /getBroadhash + * - get /getEpoch + * - get /getHeight + * - get /getNethash + * - get /getFee + * - get /getFees + * - get /getMilestone + * - get /getReward + * - get /getSupply + * - get /getStatus * @memberof module:blocks * @requires helpers/Router * @requires helpers/httpApi @@ -28,30 +28,29 @@ var httpApi = require('../../helpers/httpApi'); */ // Constructor function BlocksHttpApi (blocksModule, app, logger, cache) { + var router = new Router(); - var router = new Router(); + // attach a middlware to endpoints + router.attachMiddlwareForUrls(httpApi.middleware.useCache.bind(null, logger, cache), [ + 'get /' + ]); - // attach a middlware to endpoints - router.attachMiddlwareForUrls(httpApi.middleware.useCache.bind(null, logger, cache), [ - 'get /' - ]); + router.map(blocksModule.shared, { + 'get /get': 'getBlock', + 'get /': 'getBlocks', + 'get /getBroadhash': 'getBroadhash', + 'get /getEpoch': 'getEpoch', + 'get /getHeight': 'getHeight', + 'get /getNethash': 'getNethash', + 'get /getFee': 'getFee', + 'get /getFees': 'getFees', + 'get /getMilestone': 'getMilestone', + 'get /getReward': 'getReward', + 'get /getSupply': 'getSupply', + 'get /getStatus': 'getStatus' + }); - router.map(blocksModule.shared, { - 'get /get': 'getBlock', - 'get /': 'getBlocks', - 'get /getBroadhash': 'getBroadhash', - 'get /getEpoch': 'getEpoch', - 'get /getHeight': 'getHeight', - 'get /getNethash': 'getNethash', - 'get /getFee': 'getFee', - 'get /getFees': 'getFees', - 'get /getMilestone': 'getMilestone', - 'get /getReward': 'getReward', - 'get /getSupply': 'getSupply', - 'get /getStatus': 'getStatus' - }); - - httpApi.registerEndpoint('/api/blocks', app, router, blocksModule.isLoaded); + httpApi.registerEndpoint('/api/blocks', app, router, blocksModule.isLoaded); } module.exports = BlocksHttpApi; diff --git a/api/http/chatrooms.js b/api/http/chatrooms.js index a216a331..30acc236 100644 --- a/api/http/chatrooms.js +++ b/api/http/chatrooms.js @@ -8,8 +8,8 @@ const httpApi = require('../../helpers/httpApi'); * - End point: `/api/chatrooms` * * - Sanitized - * - get /:ID - * - get /:ID/:ID + * - get /:ID + * - get /:ID/:ID * @memberof module:chatrooms * @requires helpers/Router * @requires helpers/httpApi @@ -19,16 +19,15 @@ const httpApi = require('../../helpers/httpApi'); */ // Constructor function ChatroomsHttpApi (chatroomsModule, app) { + const router = new Router(); - const router = new Router(); + router.map(chatroomsModule.internal, { + 'get /U*/U*': 'getMessages', + 'get /U*': 'getChats' + }); - router.map(chatroomsModule.internal, { - 'get /U*/U*': 'getMessages', - 'get /U*': 'getChats', - }); - - httpApi.registerEndpoint('/api/chatrooms', app, router, chatroomsModule.isLoaded); + httpApi.registerEndpoint('/api/chatrooms', app, router, chatroomsModule.isLoaded); } -module.exports = ChatroomsHttpApi; \ No newline at end of file +module.exports = ChatroomsHttpApi; diff --git a/api/http/chats.js b/api/http/chats.js index 7d57f2c8..0e0864b8 100644 --- a/api/http/chats.js +++ b/api/http/chats.js @@ -8,13 +8,13 @@ var schema = require('../../schema/dapps'); * Binds api with modules and creates common url. * - End point: `/api/chats` * - Private API: - * - post /normalize - * - post /finalize + * - post /normalize + * - post /finalize * * - Sanitized - * - get / - * - put / - * - get /get + * - get / + * - put / + * - get /get * @memberof module:chats * @requires helpers/Router * @requires helpers/httpApi @@ -24,19 +24,18 @@ var schema = require('../../schema/dapps'); */ // Constructor function ChatsHttpApi (chatsModule, app) { + var router = new Router(); - var router = new Router(); + router.map(chatsModule.internal, { + 'get /senders': 'senders', + 'get /get': 'getTransactions', + 'get /messages': 'messages', + 'post /normalize': 'normalize', + 'post /process': 'process' + }); - router.map(chatsModule.internal, { - 'get /senders': 'senders', - 'get /get': 'getTransactions', - 'get /messages': 'messages', - 'post /normalize': 'normalize', - 'post /process': 'process' - }); - - httpApi.registerEndpoint('/api/chats', app, router, chatsModule.isLoaded); + httpApi.registerEndpoint('/api/chats', app, router, chatsModule.isLoaded); } module.exports = ChatsHttpApi; diff --git a/api/http/dapps.js b/api/http/dapps.js index fa0f4159..09c84fcd 100644 --- a/api/http/dapps.js +++ b/api/http/dapps.js @@ -8,25 +8,25 @@ var schema = require('../../schema/dapps'); * Binds api with modules and creates common url. * - End point: `/api/dapps` * - Private API: - * - get /categories - * - get /installed - * - get /installedIds - * - get /ismasterpasswordenabled - * - get /installing - * - get /uninstalling - * - get /launched - * - post /launch - * - put /transaction - * - put /withdrawal - * + * - get /categories + * - get /installed + * - get /installedIds + * - get /ismasterpasswordenabled + * - get /installing + * - get /uninstalling + * - get /launched + * - post /launch + * - put /transaction + * - put /withdrawal + * * - Sanitized - * - get / - * - put / - * - get /get - * - get /search - * - post /install - * - post /uninstall - * - post /stop + * - get / + * - put / + * - get /get + * - get /search + * - post /install + * - post /uninstall + * - post /stop * @memberof module:dapps * @requires helpers/Router * @requires helpers/httpApi @@ -36,31 +36,30 @@ var schema = require('../../schema/dapps'); */ // Constructor function DappsHttpApi (dappsModule, app) { + var router = new Router(); - var router = new Router(); + router.map(dappsModule.internal, { + 'get /categories': 'categories', + 'get /installed': 'installed', + 'get /installedIds': 'installedIds', + 'get /ismasterpasswordenabled': 'isMasterPasswordEnabled', + 'get /installing': 'installing', + 'get /uninstalling': 'uninstalling', + 'get /launched': 'launched', + 'post /launch': 'launch', + 'put /transaction': 'addTransactions', + 'put /withdrawal': 'sendWithdrawal' + }); - router.map(dappsModule.internal, { - 'get /categories': 'categories', - 'get /installed': 'installed', - 'get /installedIds': 'installedIds', - 'get /ismasterpasswordenabled': 'isMasterPasswordEnabled', - 'get /installing': 'installing', - 'get /uninstalling': 'uninstalling', - 'get /launched': 'launched', - 'post /launch': 'launch', - 'put /transaction': 'addTransactions', - 'put /withdrawal': 'sendWithdrawal' - }); + router.get('/', httpApi.middleware.sanitize('query', schema.list, dappsModule.internal.list)); + router.put('/', httpApi.middleware.sanitize('body', schema.put, dappsModule.internal.put)); + router.get('/get', httpApi.middleware.sanitize('query', schema.get, dappsModule.internal.get)); + router.get('/search', httpApi.middleware.sanitize('query', schema.search, dappsModule.internal.search)); + router.post('/install', httpApi.middleware.sanitize('body', schema.install, dappsModule.internal.install)); + router.post('/uninstall', httpApi.middleware.sanitize('body', schema.uninstall, dappsModule.internal.uninstall)); + router.post('/stop', httpApi.middleware.sanitize('body', schema.stop, dappsModule.internal.stop)); - router.get('/', httpApi.middleware.sanitize('query', schema.list, dappsModule.internal.list)); - router.put('/', httpApi.middleware.sanitize('body', schema.put, dappsModule.internal.put)); - router.get('/get', httpApi.middleware.sanitize('query', schema.get, dappsModule.internal.get)); - router.get('/search', httpApi.middleware.sanitize('query', schema.search, dappsModule.internal.search)); - router.post('/install', httpApi.middleware.sanitize('body', schema.install, dappsModule.internal.install)); - router.post('/uninstall', httpApi.middleware.sanitize('body', schema.uninstall, dappsModule.internal.uninstall)); - router.post('/stop', httpApi.middleware.sanitize('body', schema.stop, dappsModule.internal.stop)); - - httpApi.registerEndpoint('/api/dapps', app, router, dappsModule.isLoaded); + httpApi.registerEndpoint('/api/dapps', app, router, dappsModule.isLoaded); } module.exports = DappsHttpApi; diff --git a/api/http/delegates.js b/api/http/delegates.js index b9685e87..f517efaa 100644 --- a/api/http/delegates.js +++ b/api/http/delegates.js @@ -7,23 +7,23 @@ var httpApi = require('../../helpers/httpApi'); * Binds api with modules and creates common url. * - End point: `/api/delegates` * - Public API: - - get /count - - get /search - - get /voters - - get /get - - get / - - get /fee - - get /forging/getForgedByAccount - - put / - - post / - - get /getNextForgers + - get /count + - get /search + - get /voters + - get /get + - get / + - get /fee + - get /forging/getForgedByAccount + - put / + - post / + - get /getNextForgers * - Private API: - * - post /forging/enable - * - post /forging/disable - * - get /forging/status + * - post /forging/enable + * - post /forging/disable + * - get /forging/status * - Debug API: - * - get /forging/disableAll - * - get /forging/enableAll + * - get /forging/disableAll + * - get /forging/enableAll * @memberof module:delegates * @requires helpers/Router * @requires helpers/httpApi @@ -33,39 +33,38 @@ var httpApi = require('../../helpers/httpApi'); */ // Constructor function DelegatesHttpApi (delegatesModule, app, logger, cache) { + var router = new Router(); - var router = new Router(); + // attach a middlware to endpoints + router.attachMiddlwareForUrls(httpApi.middleware.useCache.bind(null, logger, cache), ['get /']); - // attach a middlware to endpoints - router.attachMiddlwareForUrls(httpApi.middleware.useCache.bind(null, logger, cache), ['get /']); + router.map(delegatesModule.shared, { + 'get /count': 'count', + 'get /search': 'search', + 'get /voters': 'getVoters', + 'get /get': 'getDelegate', + 'get /': 'getDelegates', + 'get /fee': 'getFee', + 'get /forging/getForgedByAccount': 'getForgedByAccount', + 'put /': 'addDelegate', + 'post /': 'registerDelegate', + 'get /getNextForgers': 'getNextForgers' + }); - router.map(delegatesModule.shared, { - 'get /count': 'count', - 'get /search': 'search', - 'get /voters': 'getVoters', - 'get /get': 'getDelegate', - 'get /': 'getDelegates', - 'get /fee': 'getFee', - 'get /forging/getForgedByAccount': 'getForgedByAccount', - 'put /': 'addDelegate', - 'post /': 'registerDelegate', - 'get /getNextForgers': 'getNextForgers' - }); + router.map(delegatesModule.internal, { + 'post /forging/enable': 'forgingEnable', + 'post /forging/disable': 'forgingDisable', + 'get /forging/status': 'forgingStatus' + }); - router.map(delegatesModule.internal, { - 'post /forging/enable': 'forgingEnable', - 'post /forging/disable': 'forgingDisable', - 'get /forging/status': 'forgingStatus' - }); + if (process.env.DEBUG) { + router.map(delegatesModule.internal, { + 'get /forging/disableAll': 'forgingDisableAll', + 'get /forging/enableAll': 'forgingEnableAll' + }); + } - if (process.env.DEBUG) { - router.map(delegatesModule.internal, { - 'get /forging/disableAll': 'forgingDisableAll', - 'get /forging/enableAll': 'forgingEnableAll' - }); - } - - httpApi.registerEndpoint('/api/delegates', app, router, delegatesModule.isLoaded); + httpApi.registerEndpoint('/api/delegates', app, router, delegatesModule.isLoaded); } module.exports = DelegatesHttpApi; diff --git a/api/http/loader.js b/api/http/loader.js index 8b8caa1f..3691f912 100644 --- a/api/http/loader.js +++ b/api/http/loader.js @@ -6,10 +6,10 @@ var httpApi = require('../../helpers/httpApi'); * Binds api with modules and creates common url. * - End point: `/api/loader` * - Public API: - * - get /status - * - get /status/sync + * - get /status + * - get /status/sync * - Private API: - * - get /status/ping + * - get /status/ping * @memberof module:loader * @requires helpers/Router * @requires helpers/httpApi @@ -19,20 +19,19 @@ var httpApi = require('../../helpers/httpApi'); */ // Constructor function LoaderHttpApi (loaderModule, app) { + var router = new Router(); - var router = new Router(); + router.map(loaderModule.shared, { + 'get /status': 'status', + 'get /status/sync': 'sync' + }); - router.map(loaderModule.shared, { - 'get /status': 'status', - 'get /status/sync': 'sync' - }); + router.get('/status/ping', function (req, res) { + var status = loaderModule.internal.statusPing(); + return res.status(status ? 200 : 503).json({ success: status }); + }); - router.get('/status/ping', function (req, res) { - var status = loaderModule.internal.statusPing(); - return res.status(status ? 200 : 503).json({success: status}); - }); - - httpApi.registerEndpoint('/api/loader', app, router, loaderModule.isLoaded); + httpApi.registerEndpoint('/api/loader', app, router, loaderModule.isLoaded); } module.exports = LoaderHttpApi; diff --git a/api/http/multisignatures.js b/api/http/multisignatures.js index 84f38ec2..b8f119b1 100644 --- a/api/http/multisignatures.js +++ b/api/http/multisignatures.js @@ -7,10 +7,10 @@ var httpApi = require('../../helpers/httpApi'); * Binds api with modules and creates common url. * - End point: `/api/multisignatures` * - Public API: - * - get /pending - * - post /sign - * - put / - * - get /accounts + * - get /pending + * - post /sign + * - put / + * - get /accounts * @memberof module:multisignatures * @requires helpers/Router * @requires helpers/httpApi @@ -21,17 +21,16 @@ var httpApi = require('../../helpers/httpApi'); */ // Constructor function MultisignaturesHttpApi (mutlisignaturesModule, app) { + var router = new Router(); - var router = new Router(); + router.map(mutlisignaturesModule.shared, { + 'get /pending': 'pending', + 'post /sign': 'sign', + 'put /': 'addMultisignature', + 'get /accounts': 'getAccounts' + }); - router.map(mutlisignaturesModule.shared, { - 'get /pending': 'pending', - 'post /sign': 'sign', - 'put /': 'addMultisignature', - 'get /accounts': 'getAccounts' - }); - - httpApi.registerEndpoint('/api/multisignatures', app, router, mutlisignaturesModule.isLoaded); + httpApi.registerEndpoint('/api/multisignatures', app, router, mutlisignaturesModule.isLoaded); } module.exports = MultisignaturesHttpApi; diff --git a/api/http/node.js b/api/http/node.js index 0bcb8f13..4822609b 100644 --- a/api/http/node.js +++ b/api/http/node.js @@ -8,7 +8,7 @@ var schema = require('../../schema/node.js'); * Binds api with modules and creates common url. * - End point: `/api/node` * - Public API: - - get /status + - get /status * @memberof module:node * @requires helpers/Router * @requires helpers/httpApi @@ -18,15 +18,14 @@ var schema = require('../../schema/node.js'); */ function NodeHttpApi (nodeModule, app) { + var router = new Router(); - var router = new Router(); + router.map(nodeModule.shared, { + 'get /status': 'getStatus' + }); - router.map(nodeModule.shared, { - 'get /status': 'getStatus', - }); - - httpApi.registerEndpoint('/api/node', app, router, nodeModule.isLoaded); + httpApi.registerEndpoint('/api/node', app, router, nodeModule.isLoaded); } module.exports = NodeHttpApi; diff --git a/api/http/peers.js b/api/http/peers.js index f8604f53..e1683f35 100644 --- a/api/http/peers.js +++ b/api/http/peers.js @@ -7,10 +7,10 @@ var httpApi = require('../../helpers/httpApi'); * Binds api with modules and creates common url. * - End point: `/api/peers` * - Public API: - * - get / - * - get /version - * - get /get - * - get /count + * - get / + * - get /version + * - get /get + * - get /count * @memberof module:peers * @requires helpers/Router * @requires helpers/httpApi @@ -20,17 +20,16 @@ var httpApi = require('../../helpers/httpApi'); */ // Constructor function PeersHttpApi (peersModule, app) { + var router = new Router(); - var router = new Router(); + router.map(peersModule.shared, { + 'get /': 'getPeers', + 'get /version': 'version', + 'get /get': 'getPeer', + 'get /count': 'count' + }); - router.map(peersModule.shared, { - 'get /': 'getPeers', - 'get /version': 'version', - 'get /get': 'getPeer', - 'get /count': 'count' - }); - - httpApi.registerEndpoint('/api/peers', app, router, peersModule.isLoaded); + httpApi.registerEndpoint('/api/peers', app, router, peersModule.isLoaded); } module.exports = PeersHttpApi; diff --git a/api/http/server.js b/api/http/server.js index d8c73cfe..d7c8870b 100644 --- a/api/http/server.js +++ b/api/http/server.js @@ -6,7 +6,7 @@ var httpApi = require('../../helpers/httpApi'); /** * Renders main page wallet from public folder. * - Public API: - * - get / + * - get / * @memberof module:server * @requires helpers/Router * @requires helpers/httpApi @@ -16,30 +16,29 @@ var httpApi = require('../../helpers/httpApi'); */ // Constructor function ServerHttpApi (serverModule, app) { - - var router = new Router(); - - router.use(function (req, res, next) { - if (serverModule.areModulesReady()) { return next(); } - res.status(500).send({success: false, error: 'Blockchain is loading'}); - }); - - router.get('/', function (req, res) { - if (serverModule.isLoaded()) { - res.render('wallet.html', {layout: false}); - } else { - res.render('loading.html'); - } - }); - - router.use(function (req, res, next) { - if (req.url.indexOf('/api/') === -1 && req.url.indexOf('/peer/') === -1) { - return res.redirect('/'); - } - next(); - }); - - app.use('/', router); + var router = new Router(); + + router.use(function (req, res, next) { + if (serverModule.areModulesReady()) { return next(); } + res.status(500).send({ success: false, error: 'Blockchain is loading' }); + }); + + router.get('/', function (req, res) { + if (serverModule.isLoaded()) { + res.render('wallet.html', { layout: false }); + } else { + res.render('loading.html'); + } + }); + + router.use(function (req, res, next) { + if (req.url.indexOf('/api/') === -1 && req.url.indexOf('/peer/') === -1) { + return res.redirect('/'); + } + next(); + }); + + app.use('/', router); } module.exports = ServerHttpApi; diff --git a/api/http/signatures.js b/api/http/signatures.js index e76db162..f5d68e9c 100644 --- a/api/http/signatures.js +++ b/api/http/signatures.js @@ -7,8 +7,8 @@ var httpApi = require('../../helpers/httpApi'); * Binds api with modules and creates common url. * - End point: `/api/signatures` * - Public API: - * - get /fee - * - put / + * - get /fee + * - put / * @memberof module:signatures * @requires helpers/Router * @requires helpers/httpApi @@ -18,15 +18,14 @@ var httpApi = require('../../helpers/httpApi'); */ // Constructor function SignaturesHttpApi (signaturesModule, app) { + var router = new Router(); - var router = new Router(); + router.map(signaturesModule.shared, { + 'get /fee': 'getFee', + 'put /': 'addSignature' + }); - router.map(signaturesModule.shared, { - 'get /fee': 'getFee', - 'put /': 'addSignature' - }); - - httpApi.registerEndpoint('/api/signatures', app, router, signaturesModule.isLoaded); + httpApi.registerEndpoint('/api/signatures', app, router, signaturesModule.isLoaded); } module.exports = SignaturesHttpApi; diff --git a/api/http/states.js b/api/http/states.js index 2dd98228..06d2794c 100644 --- a/api/http/states.js +++ b/api/http/states.js @@ -8,11 +8,11 @@ var httpApi = require('../../helpers/httpApi'); * Binds api with modules and creates common url. * - End point: `/api/states` * - Private API: - * - post /normalize - * - post /finalize + * - post /normalize + * - post /finalize * * - Sanitized - * - get /get + * - get /get * @memberof module:states * @requires helpers/Router * @requires helpers/httpApi @@ -22,18 +22,17 @@ var httpApi = require('../../helpers/httpApi'); */ // Constructor function StatesHttpApi (statesModule, app) { + var router = new Router(); - var router = new Router(); + router.map(statesModule.internal, { + 'get /get': 'getTransactions', + 'post /get': 'getTransactions', + 'post /normalize': 'normalize', + 'post /store': 'store' + }); - router.map(statesModule.internal, { - 'get /get': 'getTransactions', - 'post /get': 'getTransactions', - 'post /normalize': 'normalize', - 'post /store': 'store' - }); - - httpApi.registerEndpoint('/api/states', app, router, statesModule.isLoaded); + httpApi.registerEndpoint('/api/states', app, router, statesModule.isLoaded); } module.exports = StatesHttpApi; diff --git a/api/http/transactions.js b/api/http/transactions.js index 3b910706..9a477f48 100644 --- a/api/http/transactions.js +++ b/api/http/transactions.js @@ -29,31 +29,30 @@ var httpApi = require('../../helpers/httpApi'); */ // Constructor function TransactionsHttpApi (transactionsModule, app, logger, cache) { + var router = new Router(); - var router = new Router(); + // attach a middleware to endpoints + router.attachMiddlwareForUrls(httpApi.middleware.useCache.bind(null, logger, cache), [ + 'get /' + ]); - // attach a middlware to endpoints - router.attachMiddlwareForUrls(httpApi.middleware.useCache.bind(null, logger, cache), [ - 'get /' - ]); + router.map(transactionsModule.shared, { + 'get /': 'getTransactions', + 'post /': 'postTransactions', + 'get /get': 'getTransaction', + 'get /count': 'getTransactionsCount', + 'get /queued/get': 'getQueuedTransaction', + 'get /queued': 'getQueuedTransactions', + 'get /multisignatures/get': 'getMultisignatureTransaction', + 'get /multisignatures': 'getMultisignatureTransactions', + 'get /unconfirmed/get': 'getUnconfirmedTransaction', + 'get /unconfirmed': 'getUnconfirmedTransactions', + 'put /': 'addTransactions', + 'post /normalize': 'normalizeTransactions', + 'post /process': 'processTransactions' + }); - router.map(transactionsModule.shared, { - 'get /': 'getTransactions', - 'post /': 'postTransactions', - 'get /get': 'getTransaction', - 'get /count': 'getTransactionsCount', - 'get /queued/get': 'getQueuedTransaction', - 'get /queued': 'getQueuedTransactions', - 'get /multisignatures/get': 'getMultisignatureTransaction', - 'get /multisignatures': 'getMultisignatureTransactions', - 'get /unconfirmed/get': 'getUnconfirmedTransaction', - 'get /unconfirmed': 'getUnconfirmedTransactions', - 'put /': 'addTransactions', - 'post /normalize': 'normalizeTransactions', - 'post /process': 'processTransactions' - }); - - httpApi.registerEndpoint('/api/transactions', app, router, transactionsModule.isLoaded); + httpApi.registerEndpoint('/api/transactions', app, router, transactionsModule.isLoaded); } module.exports = TransactionsHttpApi; diff --git a/api/http/transport.js b/api/http/transport.js index 3b192e8a..78c53faa 100644 --- a/api/http/transport.js +++ b/api/http/transport.js @@ -8,18 +8,18 @@ var schema = require('../../schema/transport'); * Binds api with modules and creates common url. * - End point: `/peer` * - Private API: - * - get /blocks/common - * - get /blocks - * - get /list - * - get /height - * - get /ping - * - get /signatures - * - get /transactions - * - post /dapp/message - * - post /dapp/request - * - post /blocks - * - post /signatures - * - post /transactions + * - get /blocks/common + * - get /blocks + * - get /list + * - get /height + * - get /ping + * - get /signatures + * - get /transactions + * - post /dapp/message + * - post /dapp/request + * - post /blocks + * - post /signatures + * - post /transactions * @memberof module:transport * @requires helpers/Router * @requires helpers/httpApi @@ -30,89 +30,88 @@ var schema = require('../../schema/transport'); */ // Constructor function TransportHttpApi (transportModule, app, logger, cache) { - - var router = new Router(); - - router.use(httpApi.middleware.attachResponseHeaders.bind(null, transportModule.headers)); - router.use(httpApi.middleware.blockchainReady.bind(null, transportModule.isLoaded)); - - router.use(handshakeMiddleware); - - router.get('/blocks/common', getCommonBlocksMiddleware); - router.get('/blocks', httpApi.middleware.sanitize('query', schema.blocks, transportModule.internal.blocks)); - - router.map(transportModule.internal, { - 'get /list': 'list', - 'get /height': 'height', - 'get /ping': 'ping', - 'get /signatures': 'getSignatures', - 'get /transactions': 'getTransactions', - 'post /dapp/message': 'postDappMessage', - 'post /dapp/request': 'postDappRequest' - - }); - - // Custom parameters internal functions - router.post('/blocks', function (req, res) { - transportModule.internal.postBlock(req.body.block, req.peer, req.method + ' ' + req.url, httpApi.respond.bind(null, res)); - }); - - router.post('/signatures', function (req, res) { - transportModule.internal.postSignatures({signatures: req.body.signatures, signature: req.body.signature}, httpApi.respond.bind(null, res)); - }); - - router.post('/transactions', function (req, res) { - transportModule.internal.postTransactions({ - transactions: req.body.transactions, - transaction: req.body.transaction - }, req.peer, req.method + ' ' + req.url, httpApi.respond.bind(null, res)); - }); - - router.use(httpApi.middleware.notFound); - - app.use('/peer', router); - - function handshakeMiddleware (req, res, next) { - transportModule.internal.handshake(req.ip, req.headers.port, req.headers, validateHeaders, function (err, peer) { - if (err) { - return res.status(500).send(err); - } - - req.peer = peer; - - if (req.body && req.body.dappid) { - req.peer.dappid = req.body.dappid; - } - return next(); - }); - - function validateHeaders (headers, cb) { - return req.sanitize(headers, schema.headers, function (err, report, sanitized) { - if (err) { - return cb(err.toString()); - } else if (!report.isValid) { - return cb(report.issues); - } - - return cb(); - }); - } - } - - function getCommonBlocksMiddleware (req, res, next) { - req.sanitize(req.query, schema.commonBlock, function (err, report, query) { - if (err) { - logger.debug('Common block request validation failed', {err: err.toString(), req: req.query}); - return next(err); - } - if (!report.isValid) { - logger.debug('Common block request validation failed', {err: report, req: req.query}); - return res.json({success: false, error: report.issues}); - } - - return transportModule.internal.blocksCommon(query.ids, req.peer, req.method + ' ' + req.url, httpApi.respond.bind(null, res)); - }); - } + var router = new Router(); + + router.use(httpApi.middleware.attachResponseHeaders.bind(null, transportModule.headers)); + router.use(httpApi.middleware.blockchainReady.bind(null, transportModule.isLoaded)); + + router.use(handshakeMiddleware); + + router.get('/blocks/common', getCommonBlocksMiddleware); + router.get('/blocks', httpApi.middleware.sanitize('query', schema.blocks, transportModule.internal.blocks)); + + router.map(transportModule.internal, { + 'get /list': 'list', + 'get /height': 'height', + 'get /ping': 'ping', + 'get /signatures': 'getSignatures', + 'get /transactions': 'getTransactions', + 'post /dapp/message': 'postDappMessage', + 'post /dapp/request': 'postDappRequest' + + }); + + // Custom parameters internal functions + router.post('/blocks', function (req, res) { + transportModule.internal.postBlock(req.body.block, req.peer, req.method + ' ' + req.url, httpApi.respond.bind(null, res)); + }); + + router.post('/signatures', function (req, res) { + transportModule.internal.postSignatures({ signatures: req.body.signatures, signature: req.body.signature }, httpApi.respond.bind(null, res)); + }); + + router.post('/transactions', function (req, res) { + transportModule.internal.postTransactions({ + transactions: req.body.transactions, + transaction: req.body.transaction + }, req.peer, req.method + ' ' + req.url, httpApi.respond.bind(null, res)); + }); + + router.use(httpApi.middleware.notFound); + + app.use('/peer', router); + + function handshakeMiddleware (req, res, next) { + transportModule.internal.handshake(req.ip, req.headers.port, req.headers, validateHeaders, function (err, peer) { + if (err) { + return res.status(500).send(err); + } + + req.peer = peer; + + if (req.body && req.body.dappid) { + req.peer.dappid = req.body.dappid; + } + return next(); + }); + + function validateHeaders (headers, cb) { + return req.sanitize(headers, schema.headers, function (err, report, sanitized) { + if (err) { + return cb(err.toString()); + } else if (!report.isValid) { + return cb(report.issues); + } + + return cb(); + }); + } + } + + function getCommonBlocksMiddleware (req, res, next) { + req.sanitize(req.query, schema.commonBlock, function (err, report, query) { + if (err) { + logger.debug('Common block request validation failed', { err: err.toString(), req: req.query }); + return next(err); + } + if (!report.isValid) { + logger.debug('Common block request validation failed', { err: report, req: req.query }); + return res.json({ success: false, error: report.issues }); + } + + return transportModule.internal.blocksCommon(query.ids, req.peer, req.method + ' ' + req.url, httpApi.respond.bind(null, res)); + }); + } } module.exports = TransportHttpApi; diff --git a/app.js b/app.js index 98f4b069..a03c5a2c 100644 --- a/app.js +++ b/app.js @@ -18,7 +18,7 @@ /** * Main entry point. - * Loads the secu modules, the secu api and run the express server as Domain master. + * Loads the ADAMANT modules, the ADAMANT api and run the express server as Domain master. * CLI options available. * @module app */ @@ -28,7 +28,6 @@ var checkIpInList = require('./helpers/checkIpInList.js'); var extend = require('extend'); var fs = require('fs'); -var genesisblock = require('./genesisBlock.json'); var git = require('./helpers/git.js'); var https = require('https'); var Logger = require('./logger.js'); @@ -49,69 +48,71 @@ var versionBuild = fs.readFileSync(path.join(__dirname, 'build'), 'utf8'); var lastCommit = ''; if (typeof gc !== 'undefined') { - setInterval(function () { - // eslint-disable-next-line no-undef - gc(); - }, 60000); + setInterval(function () { + // eslint-disable-next-line no-undef + gc(); + }, 60000); } program - .version(packageJson.version) - .option('-c, --config ', 'config file path') - .option('-p, --port ', 'listening port number') - .option('-a, --address ', 'listening host name or ip') - .option('-x, --peers [peers...]', 'peers list') - .option('-l, --log ', 'log level') - .option('-s, --snapshot ', 'verify snapshot') - .parse(process.argv); + .version(packageJson.version) + .option('-c, --config ', 'config.json file path') + .option('-g, --genesis ', 'genesisBlock.json file path') + .option('-p, --port ', 'listening port number') + .option('-a, --address ', 'listening host name or ip') + .option('-x, --peers [peers...]', 'peers list') + .option('-l, --log ', 'log level') + .option('-s, --snapshot ', 'verify snapshot') + .parse(process.argv); /** * @property {object} - The default list of configuration options. Can be updated by CLI. * @default 'config.json' */ var appConfig = require('./helpers/config.js')(program.config); +var genesisblock = require(path.resolve(process.cwd(), (program.genesis || 'genesisBlock.json'))); if (program.port) { - appConfig.port = program.port; + appConfig.port = program.port; } if (program.address) { - appConfig.address = program.address; + appConfig.address = program.address; } if (program.peers) { - if (typeof program.peers === 'string') { - appConfig.peers.list = program.peers.split(',').map(function (peer) { - peer = peer.split(':'); - return { - ip: peer.shift(), - port: peer.shift() || appConfig.port - }; - }); - } else { - appConfig.peers.list = []; - } + if (typeof program.peers === 'string') { + appConfig.peers.list = program.peers.split(',').map(function (peer) { + peer = peer.split(':'); + return { + ip: peer.shift(), + port: peer.shift() || appConfig.port + }; + }); + } else { + appConfig.peers.list = []; + } } if (program.log) { - appConfig.consoleLogLevel = program.log; + appConfig.consoleLogLevel = program.log; } if (program.snapshot) { - appConfig.loading.snapshot = Math.abs( - Math.floor(program.snapshot) - ); + appConfig.loading.snapshot = Math.abs( + Math.floor(program.snapshot) + ); } if (process.env.NODE_ENV === 'test') { - appConfig.coverage = true; + appConfig.coverage = true; } // Define top endpoint availability process.env.TOP = appConfig.topAccounts; /** - * The config object to handle secu modules and secu api. + * The config object to handle ADAMANT modules and ADAMANT api. * It loads `modules` and `api` folders content. * Also contains db configuration from config.json. * @property {object} db - Config values for database. @@ -119,49 +120,49 @@ process.env.TOP = appConfig.topAccounts; * @property {object} api - `api/http` folder content. */ var config = { - db: appConfig.db, - cache: appConfig.redis, - cacheEnabled: appConfig.cacheEnabled, - modules: { - server: './modules/server.js', - accounts: './modules/accounts.js', - transactions: './modules/transactions.js', - blocks: './modules/blocks.js', - signatures: './modules/signatures.js', - transport: './modules/transport.js', - loader: './modules/loader.js', - system: './modules/system.js', - peers: './modules/peers.js', - delegates: './modules/delegates.js', - rounds: './modules/rounds.js', - multisignatures: './modules/multisignatures.js', - dapps: './modules/dapps.js', - chats: './modules/chats.js', - chatrooms: './modules/chatrooms.js', - states: './modules/states.js', - node: './modules/node.js', - chats: './modules/chats.js', - crypto: './modules/crypto.js', - sql: './modules/sql.js', - cache: './modules/cache.js' - }, - api: { - accounts: { http: './api/http/accounts.js' }, - blocks: { http: './api/http/blocks.js' }, - dapps: { http: './api/http/dapps.js' }, - chats: { http: './api/http/chats.js' }, - chatrooms: { http: './api/http/chatrooms.js' }, - states: { http: './api/http/states.js' }, - node: { http: './api/http/node.js' }, - delegates: { http: './api/http/delegates.js' }, - loader: { http: './api/http/loader.js' }, - multisignatures: { http: './api/http/multisignatures.js' }, - peers: { http: './api/http/peers.js' }, - server: { http: './api/http/server.js' }, - signatures: { http: './api/http/signatures.js' }, - transactions: { http: './api/http/transactions.js' }, - transport: { http: './api/http/transport.js' } - } + db: appConfig.db, + cache: appConfig.redis, + cacheEnabled: appConfig.cacheEnabled, + modules: { + server: './modules/server.js', + accounts: './modules/accounts.js', + transactions: './modules/transactions.js', + blocks: './modules/blocks.js', + signatures: './modules/signatures.js', + transport: './modules/transport.js', + loader: './modules/loader.js', + system: './modules/system.js', + peers: './modules/peers.js', + delegates: './modules/delegates.js', + rounds: './modules/rounds.js', + multisignatures: './modules/multisignatures.js', + dapps: './modules/dapps.js', + chats: './modules/chats.js', + chatrooms: './modules/chatrooms.js', + states: './modules/states.js', + node: './modules/node.js', + chats: './modules/chats.js', + crypto: './modules/crypto.js', + sql: './modules/sql.js', + cache: './modules/cache.js' + }, + api: { + accounts: { http: './api/http/accounts.js' }, + blocks: { http: './api/http/blocks.js' }, + dapps: { http: './api/http/dapps.js' }, + chats: { http: './api/http/chats.js' }, + chatrooms: { http: './api/http/chatrooms.js' }, + states: { http: './api/http/states.js' }, + node: { http: './api/http/node.js' }, + delegates: { http: './api/http/delegates.js' }, + loader: { http: './api/http/loader.js' }, + multisignatures: { http: './api/http/multisignatures.js' }, + peers: { http: './api/http/peers.js' }, + server: { http: './api/http/server.js' }, + signatures: { http: './api/http/signatures.js' }, + transactions: { http: './api/http/transactions.js' }, + transport: { http: './api/http/transport.js' } + } }; /** @@ -170,16 +171,16 @@ var config = { * @property {object} - Logger instance. */ var logger = new Logger({ - echo: appConfig.consoleLogLevel, - errorLevel: appConfig.fileLogLevel, - filename: appConfig.logFileName + echo: appConfig.consoleLogLevel, + errorLevel: appConfig.fileLogLevel, + filename: appConfig.logFileName }); // Trying to get last git commit try { - lastCommit = git.getLastCommit(); + lastCommit = git.getLastCommit(); } catch (err) { - logger.debug('Cannot get last git commit', err.message); + logger.debug('Cannot get last git commit', err.message); } /** @@ -189,566 +190,565 @@ try { var d = require('domain').create(); d.on('error', function (err) { - logger.fatal('Domain master', { - message: err.message, - stack: err.stack - }); - process.exit(0); + logger.fatal('Domain master', { + message: err.message, + stack: err.stack + }); + process.exit(0); }); // runs domain d.run(function () { - var modules = []; - async.auto({ - /** - * Loads `payloadHash` and generate dapp password if it is empty and required. - * Then updates config.json with new random password. - * @method config - * @param {nodeStyleCallback} cb - Callback function with the mutated `appConfig`. - * @throws {Error} If failed to assign nethash from genesis block. - */ - config: function (cb) { - try { - appConfig.nethash = Buffer.from(genesisblock.payloadHash, 'hex').toString('hex'); - } catch (e) { - logger.error('Failed to assign nethash from genesis block'); - throw Error(e); - } - - if (appConfig.dapp.masterrequired && !appConfig.dapp.masterpassword) { - var randomstring = require('randomstring'); - - appConfig.dapp.masterpassword = randomstring.generate({ - length: 12, - readable: true, - charset: 'alphanumeric' - }); - - if (appConfig.loading.snapshot != null) { - delete appConfig.loading.snapshot; - } - - fs.writeFileSync('./config.json', JSON.stringify(appConfig, null, 4)); - cb(null, appConfig); - } else { - cb(null, appConfig); - } - }, - logger: function (cb) { - cb(null, logger); - }, - - build: function (cb) { - cb(null, versionBuild); - }, - - /** - * Returns hash of last git commit. - * @method lastCommit - * @param {nodeStyleCallback} cb - Callback function with Hash of last git commit. - */ - lastCommit: function (cb) { - cb(null, lastCommit); - }, - - genesisblock: function (cb) { - cb(null, { - block: genesisblock - }); - }, - packageJson: function (cb) { - cb(null, packageJson); + var modules = []; + async.auto({ + /** + * Loads `payloadHash` and generate dapp password if it is empty and required. + * Then updates config.json with new random password. + * @method config + * @param {nodeStyleCallback} cb - Callback function with the mutated `appConfig`. + * @throws {Error} If failed to assign nethash from genesis block. + */ + config: function (cb) { + try { + appConfig.nethash = Buffer.from(genesisblock.payloadHash, 'hex').toString('hex'); + } catch (e) { + logger.error('Failed to assign nethash from genesis block'); + throw Error(e); + } + + if (appConfig.dapp.masterrequired && !appConfig.dapp.masterpassword) { + var randomstring = require('randomstring'); + + appConfig.dapp.masterpassword = randomstring.generate({ + length: 12, + readable: true, + charset: 'alphanumeric' + }); + + if (appConfig.loading.snapshot != null) { + delete appConfig.loading.snapshot; + } + + fs.writeFileSync('./config.json', JSON.stringify(appConfig, null, 4)); + cb(null, appConfig); + } else { + cb(null, appConfig); + } + }, + logger: function (cb) { + cb(null, logger); + }, + + build: function (cb) { + cb(null, versionBuild); + }, + + /** + * Returns hash of last git commit. + * @method lastCommit + * @param {nodeStyleCallback} cb - Callback function with Hash of last git commit. + */ + lastCommit: function (cb) { + cb(null, lastCommit); + }, + + genesisblock: function (cb) { + cb(null, { + block: genesisblock + }); + }, + packageJson: function (cb) { + cb(null, packageJson); + }, + public: function (cb) { + cb(null, path.join(__dirname, 'public')); + }, + + schema: function (cb) { + cb(null, new z_schema()); + }, + + /** + * ws client PWA, + * @method clientWs + * @param {object} wsconfig - config from ws client PWA, + * @param {nodeStyleCallback} cb - Callback function with created Method: + * `emit`. + */ + clientWs: ['config', function (scope, cb) { + var ClientWs = require('./modules/clientWs'); + cb(null, new ClientWs(scope.config.wsClient, logger)); + }], + /** + * Once config is completed, creates app, http & https servers & sockets with express. + * @method network + * @param {object} scope - The results from current execution, + * at least will contain the required elements. + * @param {nodeStyleCallback} cb - Callback function with created Object: + * `{express, app, server, io, https, https_io}`. + */ + network: ['config', function (scope, cb) { + var express = require('express'); + var compression = require('compression'); + var cors = require('cors'); + var app = express(); + + if (appConfig.coverage) { + var im = require('nyc-middleware'); + logger.debug('Hook loader for coverage - do not use in production environment!'); + im.hookLoader(__dirname); + app.use('/coverage', im.createHandler()); + } + + require('./helpers/request-limiter')(app, appConfig); + + app.use(compression({ + level: 9 + })); + app.use(cors()); + app.options('*', cors()); + + var server = require('http').createServer(app); + var io = require('socket.io')(server); + + var privateKey, certificate, https, https_io; + + if (scope.config.ssl.enabled) { + privateKey = fs.readFileSync(scope.config.ssl.options.key); + certificate = fs.readFileSync(scope.config.ssl.options.cert); + + https = require('https').createServer({ + key: privateKey, + cert: certificate, + ciphers: 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:' + 'ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:DHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA256:HIGH:' + '!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!SRP:!CAMELLIA' + }, app); + + https_io = require('socket.io')(https); + } + + cb(null, { + express: express, + app: app, + server: server, + io: io, + https: https, + https_io: https_io + }); + }], + + dbSequence: ['logger', function (scope, cb) { + var sequence = new Sequence({ + onWarning: function (current, limit) { + scope.logger.warn('DB queue', current); + } + }); + cb(null, sequence); + }], + + sequence: ['logger', function (scope, cb) { + var sequence = new Sequence({ + onWarning: function (current, limit) { + scope.logger.warn('Main queue', current); + } + }); + cb(null, sequence); + }], + + balancesSequence: ['logger', function (scope, cb) { + var sequence = new Sequence({ + onWarning: function (current, limit) { + scope.logger.warn('Balance queue', current); + } + }); + cb(null, sequence); + }], + + /** + * Once config, public, genesisblock, logger, build and network are completed, + * adds configuration to `network.app`. + * @method connect + * @param {object} scope - The results from current execution, + * at least will contain the required elements. + * @param {function} cb - Callback function. + */ + connect: ['config', 'public', 'genesisblock', 'logger', 'build', 'network', function (scope, cb) { + var path = require('path'); + var bodyParser = require('body-parser'); + var methodOverride = require('method-override'); + var queryParser = require('express-query-int'); + var randomString = require('randomstring'); + + scope.nonce = randomString.generate(16); + scope.network.app.engine('html', require('ejs').renderFile); + scope.network.app.use(require('express-domain-middleware')); + scope.network.app.set('view engine', 'ejs'); + scope.network.app.set('views', path.join(__dirname, 'public')); + scope.network.app.use(scope.network.express.static(path.join(__dirname, 'public'))); + scope.network.app.use(bodyParser.raw({ + limit: '2mb' + })); + scope.network.app.use(bodyParser.urlencoded({ + extended: true, + limit: '2mb', + parameterLimit: 5000 + })); + scope.network.app.use(bodyParser.json({ + limit: '2mb' + })); + scope.network.app.use(methodOverride()); + + var ignore = ['id', 'name', 'lastBlockId', 'blockId', 'transactionId', 'address', 'recipientId', 'senderId', 'previousBlock']; + + scope.network.app.use(queryParser({ + parser: function (value, radix, name) { + if (ignore.indexOf(name) >= 0) { + return value; + } + + // Ignore conditional fields for transactions list + if (/^.+?:(blockId|recipientId|senderId)$/.test(name)) { + return value; + } + + /* eslint-disable eqeqeq */ + if (isNaN(value) || parseInt(value) != value || isNaN(parseInt(value, radix))) { + return value; + } + /* eslint-enable eqeqeq */ + return parseInt(value); + } + })); + + scope.network.app.use(require('./helpers/z_schema-express.js')(scope.schema)); + + scope.network.app.use(httpApi.middleware.logClientConnections.bind(null, scope.logger)); + + /* Instruct browser to deny display of ,