diff --git a/app/modules/config.js b/app/modules/config.js new file mode 100644 index 0000000000000000000000000000000000000000..40920684f47f28b45d9b406b108a1c7b44a6c87e --- /dev/null +++ b/app/modules/config.js @@ -0,0 +1,12 @@ +"use strict"; + +module.exports = { + duniter: { + cli: [{ + name: 'config', + desc: 'Register configuration in database', + // The command does nothing particular, it just stops the process right after configuration phase is over + onConfiguredExecute: (server, conf, program, params, wizardTasks) => Promise.resolve(conf) + }] + } +} diff --git a/app/modules/gen.js b/app/modules/gen.js new file mode 100644 index 0000000000000000000000000000000000000000..3fd46d132fa743a92b6371fbf747a0a828d10e82 --- /dev/null +++ b/app/modules/gen.js @@ -0,0 +1,135 @@ +"use strict"; + +const co = require('co'); +const async = require('async'); +const multicaster = require('../lib/streams/multicaster'); +const Peer = require('../lib/entity/peer'); +const logger = require('../lib/logger')('gen'); + +module.exports = { + + duniter: { + + cliOptions: [ + {value: '--show', desc: 'With gen-next or gen-root commands, displays the generated block.'}, + {value: '--check', desc: 'With gen-next: just check validity of generated block.'} + ], + + cli: [{ + name: 'gen-next [host] [port] [difficulty]', + desc: 'Tries to generate the next block of the blockchain.', + onPluggedDALExecute: (server, conf, program, params, startServices, stopServices) => co(function*() { + const host = params[0]; + const port = params[1]; + const difficulty = params[2]; + return generateAndSend(program, host, port, difficulty, server, (server) => server.BlockchainService.generateNext); + }) + }, { + name: 'gen-root [host] [port] [difficulty]', + desc: 'Tries to generate root block, with choice of root members.', + onPluggedDALExecute: (server, conf, program, params, startServices, stopServices) => co(function*() { + const host = params[0]; + const port = params[1]; + const difficulty = params[2]; + if (!host) { + throw 'Host is required.'; + } + if (!port) { + throw 'Port is required.'; + } + if (!difficulty) { + throw 'Difficulty is required.'; + } + return generateAndSend(program, host, port, difficulty, server, (server) => server.BlockchainService.generateManualRoot); + }) + }] + } +} + +function generateAndSend(program, host, port, difficulty, server, getGenerationMethod) { + return new Promise((resolve, reject) => { + async.waterfall([ + function (next) { + const method = getGenerationMethod(server); + co(function*(){ + try { + const block = yield method(); + next(null, block); + } catch(e) { + next(e); + } + }); + }, + function (block, next) { + if (program.check) { + block.time = block.medianTime; + program.show && console.log(block.getRawSigned()); + co(function*(){ + try { + yield server.doCheckBlock(block); + logger.info('Acceptable block'); + next(); + } catch (e) { + next(e); + } + }); + } + else { + logger.debug('Block to be sent: %s', block.quickDescription()); + async.waterfall([ + function (next) { + // Extract key pair + co(function*(){ + try { + const pair = yield server.conf.keyPair; + next(null, pair); + } catch(e) { + next(e); + } + }); + }, + function (pair, next) { + proveAndSend(program, server, block, pair.publicKey, parseInt(difficulty), host, parseInt(port), next); + } + ], next); + } + } + ], (err, data) => { + err && reject(err); + !err && resolve(data); + }); + }); +} + +function proveAndSend(program, server, block, issuer, difficulty, host, port, done) { + const BlockchainService = server.BlockchainService; + async.waterfall([ + function (next) { + block.issuer = issuer; + program.show && console.log(block.getRawSigned()); + co(function*(){ + try { + const proven = yield BlockchainService.prove(block, difficulty); + next(null, proven); + } catch(e) { + next(e); + } + }); + }, + function (block, next) { + const peer = new Peer({ + endpoints: [['BASIC_MERKLED_API', host, port].join(' ')] + }); + program.show && console.log(block.getRawSigned()); + logger.info('Posted block ' + block.quickDescription()); + co(function*(){ + try { + yield multicaster(server.conf).sendBlock(peer, block); + next(); + } catch(e) { + next(e); + } + }); + } + ], done); +} diff --git a/app/modules/synchronization.js b/app/modules/synchronization.js new file mode 100644 index 0000000000000000000000000000000000000000..87871f12ff99b188d1426387adccb20ef4bdc54a --- /dev/null +++ b/app/modules/synchronization.js @@ -0,0 +1,34 @@ +"use strict"; + +const co = require('co'); + +module.exports = { + duniter: { + cli: [{ + name: 'sync [host] [port] [to]', + desc: 'Synchronize blockchain from a remote Duniter node', + onPluggedDALExecute: (server, conf, program, params, startServices, stopServices) => co(function*() { + const host = params[0]; + const port = params[1]; + const to = params[2]; + if (!host) { + throw 'Host is required.'; + } + if (!port) { + throw 'Port is required.'; + } + let cautious; + if (program.nocautious) { + cautious = false; + } + if (program.cautious) { + cautious = true; + } + yield server.synchronize(host, port, parseInt(to), 0, !program.nointeractive, cautious, program.nopeers, program.noshuffle); + if (server) { + yield server.disconnect(); + } + }) + }] + } +} diff --git a/app/modules/wizard.js b/app/modules/wizard.js new file mode 100644 index 0000000000000000000000000000000000000000..95fa1e0ead23aa5e5cec49f334a595d1db329578 --- /dev/null +++ b/app/modules/wizard.js @@ -0,0 +1,37 @@ +"use strict"; + +const Q = require('q'); +const co = require('co'); +const wizard = require('../lib/wizard'); +const logger = require('../lib/logger')('wizard'); + +module.exports = { + duniter: { + + wizard: { + // The wizard itself also defines its personal tasks + 'currency': Q.nbind(wizard().configCurrency, null), + 'pow': Q.nbind(wizard().configPoW, null), + 'network': Q.nbind(wizard().configNetwork, null), + 'network-reconfigure': Q.nbind(wizard().configNetworkReconfigure, null), + 'ucp': Q.nbind(wizard().configUCP, null) + }, + + cli: [{ + name: 'wizard [step]', + desc: 'Launch the configuration wizard.', + + onConfiguredExecute: (server, conf, program, params, wizardTasks) => co(function*() { + const step = params[0]; + const tasks = step ? [wizardTasks[step]] : Object.values(wizardTasks); + for (const task of tasks) { + yield task(conf, program); + } + // Check config + yield server.checkConfig(); + yield server.dal.saveConf(conf); + logger.debug("Configuration saved."); + }) + }] + } +}; diff --git a/index.js b/index.js index 162024ba2e1d4ffd332159fba617389b2e8572e2..a5b0a15daabcab794abf5ff285dd0d879790ce37 100644 --- a/index.js +++ b/index.js @@ -2,218 +2,20 @@ const Q = require('q'); const co = require('co'); -const async = require('async'); const util = require('util'); const stream = require('stream'); const _ = require('underscore'); -const dkeypair = require('duniter-keypair'); const Server = require('./server'); const directory = require('./app/lib/system/directory'); const constants = require('./app/lib/constants'); const wizard = require('./app/lib/wizard'); -const multicaster = require('./app/lib/streams/multicaster'); -const Peer = require('./app/lib/entity/peer'); const logger = require('./app/lib/logger')('duniter'); -const configDependency = { - duniter: { - cli: [{ - name: 'config', - desc: 'Register configuration in database', - // The command does nothing particular, it just stops the process right after configuration phase is over - onConfiguredExecute: (server, conf, program, params, wizardTasks) => Promise.resolve(conf) - }] - } -}; -const wizardDependency = { - duniter: { - - wizard: { - // The wizard itself also defines its personal tasks - 'currency': Q.nbind(wizard().configCurrency, null), - 'pow': Q.nbind(wizard().configPoW, null), - 'network': Q.nbind(wizard().configNetwork, null), - 'network-reconfigure': Q.nbind(wizard().configNetworkReconfigure, null), - 'ucp': Q.nbind(wizard().configUCP, null) - }, - - cli: [{ - name: 'wizard [step]', - desc: 'Launch the configuration wizard.', - - onConfiguredExecute: (server, conf, program, params, wizardTasks) => co(function*() { - const step = params[0]; - const tasks = step ? [wizardTasks[step]] : Object.values(wizardTasks); - for (const task of tasks) { - yield task(conf, program); - } - // Check config - yield server.checkConfig(); - yield server.dal.saveConf(conf); - logger.debug("Configuration saved."); - }) - }] - } -}; - -const syncDependency = { - duniter: { - cli: [{ - name: 'sync [host] [port] [to]', - desc: 'Synchronize blockchain from a remote Duniter node', - onPluggedDALExecute: (server, conf, program, params, startServices, stopServices) => co(function*() { - const host = params[0]; - const port = params[1]; - const to = params[2]; - if (!host) { - throw 'Host is required.'; - } - if (!port) { - throw 'Port is required.'; - } - let cautious; - if (program.nocautious) { - cautious = false; - } - if (program.cautious) { - cautious = true; - } - yield server.synchronize(host, port, parseInt(to), 0, !program.nointeractive, cautious, program.nopeers, program.noshuffle); - if (server) { - yield server.disconnect(); - } - }) - }] - } -}; - -const genBlockDependency = { - - duniter: { - - cliOptions: [ - {value: '--show', desc: 'With gen-next or gen-root commands, displays the generated block.'}, - {value: '--check', desc: 'With gen-next: just check validity of generated block.'} - ], - - cli: [{ - name: 'gen-next [host] [port] [difficulty]', - desc: 'Tries to generate the next block of the blockchain.', - onPluggedDALExecute: (server, conf, program, params, startServices, stopServices) => co(function*() { - const host = params[0]; - const port = params[1]; - const difficulty = params[2]; - return generateAndSend(program, host, port, difficulty, server, (server) => server.BlockchainService.generateNext); - }) - }, { - name: 'gen-root [host] [port] [difficulty]', - desc: 'Tries to generate root block, with choice of root members.', - onPluggedDALExecute: (server, conf, program, params, startServices, stopServices) => co(function*() { - const host = params[0]; - const port = params[1]; - const difficulty = params[2]; - if (!host) { - throw 'Host is required.'; - } - if (!port) { - throw 'Port is required.'; - } - if (!difficulty) { - throw 'Difficulty is required.'; - } - return generateAndSend(program, host, port, difficulty, server, (server) => server.BlockchainService.generateManualRoot); - }) - }] - } -} - -function generateAndSend(program, host, port, difficulty, server, getGenerationMethod) { - return new Promise((resolve, reject) => { - async.waterfall([ - function (next) { - const method = getGenerationMethod(server); - co(function*(){ - try { - const block = yield method(); - next(null, block); - } catch(e) { - next(e); - } - }); - }, - function (block, next) { - if (program.check) { - block.time = block.medianTime; - program.show && console.log(block.getRawSigned()); - co(function*(){ - try { - yield server.doCheckBlock(block); - logger.info('Acceptable block'); - next(); - } catch (e) { - next(e); - } - }); - } - else { - logger.debug('Block to be sent: %s', block.quickDescription()); - async.waterfall([ - function (next) { - // Extract key pair - co(function*(){ - try { - const pair = yield server.conf.keyPair; - next(null, pair); - } catch(e) { - next(e); - } - }); - }, - function (pair, next) { - proveAndSend(program, server, block, pair.publicKey, parseInt(difficulty), host, parseInt(port), next); - } - ], next); - } - } - ], (err, data) => { - err && reject(err); - !err && resolve(data); - }); - }); -} - -function proveAndSend(program, server, block, issuer, difficulty, host, port, done) { - const BlockchainService = server.BlockchainService; - async.waterfall([ - function (next) { - block.issuer = issuer; - program.show && console.log(block.getRawSigned()); - co(function*(){ - try { - const proven = yield BlockchainService.prove(block, difficulty); - next(null, proven); - } catch(e) { - next(e); - } - }); - }, - function (block, next) { - const peer = new Peer({ - endpoints: [['BASIC_MERKLED_API', host, port].join(' ')] - }); - program.show && console.log(block.getRawSigned()); - logger.info('Posted block ' + block.quickDescription()); - co(function*(){ - try { - yield multicaster(server.conf).sendBlock(peer, block); - next(); - } catch(e) { - next(e); - } - }); - } - ], done); -} +const dkeypairDependency = require('duniter-keypair'); +const configDependency = require('./app/modules/config'); +const wizardDependency = require('./app/modules/wizard'); +const genDependency = require('./app/modules/gen'); +const syncDependency = require('./app/modules/synchronization'); const MINIMAL_DEPENDENCIES = [ { name: 'duniter-config', required: configDependency } @@ -223,8 +25,8 @@ const DEFAULT_DEPENDENCIES = [ { name: 'duniter-config', required: configDependency }, { name: 'duniter-sync', required: syncDependency }, { name: 'duniter-wizard', required: wizardDependency }, - { name: 'duniter-gen', required: genBlockDependency }, - { name: 'duniter-keypair', required: dkeypair } + { name: 'duniter-gen', required: genDependency }, + { name: 'duniter-keypair', required: dkeypairDependency } ]; module.exports = function (home, memory, overConf) {