diff --git a/.gitignore b/.gitignore index 1dcef2d..604d51c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ +package-lock.json node_modules .env \ No newline at end of file diff --git a/config/index.js b/config/index.js index 6eb03ae..0a49888 100644 --- a/config/index.js +++ b/config/index.js @@ -1,3 +1,9 @@ +/** + * Chronobank/eth-blockprocessor configuration + * @module config + * @returns {Object} Configuration + */ + require('dotenv').config(); const config = { diff --git a/factories/index.js b/factories/index.js index be6a2b0..66d47d6 100644 --- a/factories/index.js +++ b/factories/index.js @@ -1,8 +1,10 @@ +/** + * Bootstrap file for rescursive search for all factories + * @returns {Object} factories + */ + const requireAll = require('require-all'); -/** @factory - * @description search for all controllers and expose them - */ module.exports = requireAll({ dirname : __dirname, filter : /(.+Factory)\.js$/, diff --git a/factories/messages/accountMessageFactory.js b/factories/messages/accountMessageFactory.js index 7793695..55e469b 100644 --- a/factories/messages/accountMessageFactory.js +++ b/factories/messages/accountMessageFactory.js @@ -1,3 +1,9 @@ +/** + * accountMessageFactory factory + * @module factory/accountMessage + * @returns {Object} + */ + module.exports = { wrongAddress: {success: false, message: 'wrong address'}, }; diff --git a/factories/messages/genericMessageFactory.js b/factories/messages/genericMessageFactory.js index e838e74..e4f15d3 100644 --- a/factories/messages/genericMessageFactory.js +++ b/factories/messages/genericMessageFactory.js @@ -1,3 +1,9 @@ +/** + * genericMessageFactory factory + * @module factory/genericMessage + * @returns {Object} + */ + module.exports = { success: {success: true, message: 'ok'}, fail: {success: false, message: 'fail'} diff --git a/factories/messages/transactionMessageFactory.js b/factories/messages/transactionMessageFactory.js index 17a4d98..f61b825 100644 --- a/factories/messages/transactionMessageFactory.js +++ b/factories/messages/transactionMessageFactory.js @@ -1,3 +1,9 @@ +/** + * transactionMessageFactory factory + * @module factory/transactionMessage + * @returns {Object} + */ + module.exports = { wrongTo: {success: false, message: 'to address'}, wrongFrom: {success: false, message: 'wrong from address'} diff --git a/index.js b/index.js index 4986acd..268ee83 100644 --- a/index.js +++ b/index.js @@ -1,3 +1,11 @@ +/** + * Middleware service for handling emitted events on chronobank platform + * @module Chronobank/eth-blockprocessor + * @requires config + * @requires models/blockModel + * @requires services/blockProcessService + */ + const mongoose = require('mongoose'), config = require('./config'), blockModel = require('./models/blockModel'), @@ -11,12 +19,6 @@ const mongoose = require('mongoose'), log = bunyan.createLogger({name: 'app'}), blockProcessService = require('./services/blockProcessService'); -/** - * @module entry point - * @description registers all smartContract's events, - * listen for changes, and notify plugins. - */ - mongoose.Promise = Promise; mongoose.connect(config.mongo.uri, {useMongoClient: true}); @@ -61,12 +63,15 @@ const init = async () => { await channel.publish('events', `${config.rabbit.serviceName}_transaction.${address}`, new Buffer(JSON.stringify(tx))); }); + /** + * Recursive routine for processing incoming blocks. + * @return {undefined} + */ let processBlock = async () => { try { let filteredTxs = await Promise.resolve(blockProcessService(currentBlock, web3)).timeout(20000); for (let tx of filteredTxs) { - let addresses = _.chain([tx.to, tx.from]) .union(tx.logs.map(log => log.address)) .uniq() diff --git a/ipcConverter.js b/ipcConverter.js index 290aed2..72525e6 100644 --- a/ipcConverter.js +++ b/ipcConverter.js @@ -1,3 +1,9 @@ +/** + * Rise a testrpc server + * @module testrpc-server + * @requires ethereumjs-testrpc + */ + const net = require('net'), config = require('./config'), bunyan = require('bunyan'), @@ -9,10 +15,9 @@ const net = require('net'), let RPCServer = TestRPC.server(); RPCServer.listen(8545); +// create RPC server const server = net.createServer(stream => { - stream.on('data', c => { - try { let payload = JSON.parse(c.toString()); RPCServer.provider.sendAsync(payload, (err, data) => { @@ -28,11 +33,32 @@ const server = net.createServer(stream => { code: -32000 })); } - + }); +}) + .on('error', err => { + // If pipe file exists try to remove it & start server again + if(err.code === 'EADDRINUSE' && removePipeFile(config.web3.uri)) + server.listen(config.web3.uri); + else + process.exit(1); }); -}); +/** + * Remove pipe file + * @param {string} filename Path to pipe file + * @return {boolean} Whether file removed or not + */ +const removePipeFile = filename => { + try { + fs.accessSync(filename, fs.F_OK | fs.W_OK) || fs.unlinkSync(filename); + return true; + } catch (e) { + log.error(e.message); + return false; + } +}; +// Create directory for Win32 if (!/^win/.test(process.platform)) { let pathIpc = path.parse(config.web3.uri).dir; @@ -40,7 +66,30 @@ if (!/^win/.test(process.platform)) { fs.mkdirSync(pathIpc); } +// Clean up pipe file after shutdown process + +/** + * Stub for windows. Emulate SIGINT for Win32 + */ +if (process.platform === 'win32') { + const rl = require('readline').createInterface({ + input: process.stdin, + output: process.stdout + }); + + rl.on('SIGINT', function () { + process.emit('SIGINT'); + }); +} + +process.on('SIGINT', function () { + try { + removePipeFile(config.web3.uri); + } catch (e) {} + process.exit(); +}); + +//Going to start server server.listen(config.web3.uri, () => { log.info(`Server: on listening for network - ${config.web3.network}`); }); - diff --git a/models/accountModel.js b/models/accountModel.js index 2761fce..f70b968 100644 --- a/models/accountModel.js +++ b/models/accountModel.js @@ -1,11 +1,15 @@ +/** + * Mongoose model. Accounts + * @module models/accountModel + * @returns {Object} Mongoose model + * @requires factory/accountMessageFactory + */ + const mongoose = require('mongoose'), messages = require('../factories/messages/accountMessageFactory'); require('mongoose-long')(mongoose); -/** @model accountModel - * @description account model - represents an eth account - */ const Account = new mongoose.Schema({ address: { type: String, diff --git a/models/blockModel.js b/models/blockModel.js index 2e65530..77ea98c 100644 --- a/models/blockModel.js +++ b/models/blockModel.js @@ -1,13 +1,15 @@ +/** + * Mongoose model. Represents a block in eth + * @module models/blockModel + * @returns {Object} Mongoose model + */ + const mongoose = require('mongoose'); -/** @model blockModel - * @description block model - represents a block in eth - */ const Block = new mongoose.Schema({ block: {type: Number}, network: {type: String}, - created: {type: Date, required: true, default: Date.now}, - + created: {type: Date, required: true, default: Date.now} }); module.exports = mongoose.model('EthBlock', Block); diff --git a/services/blockProcessService.js b/services/blockProcessService.js index 7fa32c0..306da84 100644 --- a/services/blockProcessService.js +++ b/services/blockProcessService.js @@ -1,14 +1,33 @@ +/** + * Block processor + * @module services/blockProcess + * @requires services/filterTxsByAccount + */ const _ = require('lodash'), Promise = require('bluebird'), filterTxsByAccountService = require('./filterTxsByAccountService'); -module.exports = async (currentBlock, web3) => { +/** + * Block processor routine + * @param {number} currentBlock Current block + * @param {number} web3 Latest block from network + * @return {array} Filtered transactions + */ +module.exports = async (currentBlock, web3) => { + /** + * Get latest block number from network + * @type {number} + */ let block = await Promise.promisify(web3.eth.getBlockNumber)(); if (block <= currentBlock) return Promise.reject({code: 0}); + /** + * Get raw block + * @type {Object} + */ let rawBlock = await Promise.promisify(web3.eth.getBlock)(currentBlock + 1, true); if (!rawBlock.transactions || _.isEmpty(rawBlock.transactions)) diff --git a/services/filterTxsByAccountService.js b/services/filterTxsByAccountService.js index 1159a16..48ea542 100644 --- a/services/filterTxsByAccountService.js +++ b/services/filterTxsByAccountService.js @@ -1,8 +1,13 @@ +/** + * Transaction filter + * @module services/filterTxsByAccount + * @requires models/accountModel + */ + const _ = require('lodash'), accountModel = require('../models/accountModel'); module.exports = async (txs) => { - let query = { $or: [ { @@ -32,6 +37,7 @@ module.exports = async (txs) => { } ] }; + let accounts = await accountModel.find(query); accounts = _.chain(accounts) @@ -48,5 +54,4 @@ module.exports = async (txs) => { ); }) .value(); - };