diff --git a/config/collected-signatures-watcher-config.js b/config/collected-signatures-watcher-config.js index 9574923..c1bff45 100644 --- a/config/collected-signatures-watcher-config.js +++ b/config/collected-signatures-watcher-config.js @@ -4,6 +4,7 @@ const HomeABI = require('../abis/HomeBridge.abi') module.exports = { event: 'CollectedSignatures', + name: 'watcher-collected-signatures', url: process.env.HOME_RPC_URL, contractAddress: process.env.HOME_BRIDGE_ADDRESS, abi: HomeABI, diff --git a/config/deposit-watcher-config.js b/config/deposit-watcher-config.js index 34a045e..4c5e9c4 100644 --- a/config/deposit-watcher-config.js +++ b/config/deposit-watcher-config.js @@ -4,6 +4,7 @@ const HomeABI = require('../abis/HomeBridge.abi') module.exports = { event: 'Deposit', + name: 'watcher-deposit', url: process.env.HOME_RPC_URL, contractAddress: process.env.HOME_BRIDGE_ADDRESS, abi: HomeABI, diff --git a/config/foreign-sender-config.js b/config/foreign-sender-config.js index 1de7c5f..0babd7d 100644 --- a/config/foreign-sender-config.js +++ b/config/foreign-sender-config.js @@ -4,5 +4,6 @@ module.exports = { url: process.env.FOREIGN_RPC_URL, contractAddress: process.env.FOREIGN_BRIDGE_ADDRESS, queue: 'foreign', - id: 'foreign' + id: 'foreign', + name: 'sender-foreign' } diff --git a/config/home-sender-config.js b/config/home-sender-config.js index b415839..1a895b7 100644 --- a/config/home-sender-config.js +++ b/config/home-sender-config.js @@ -4,5 +4,6 @@ module.exports = { url: process.env.HOME_RPC_URL, contractAddress: process.env.HOME_BRIDGE_ADDRESS, queue: 'home', - id: 'home' + id: 'home', + name: 'sender-home' } diff --git a/config/withdraw-watcher-config.js b/config/withdraw-watcher-config.js index 1a6fb8b..5fa7fc3 100644 --- a/config/withdraw-watcher-config.js +++ b/config/withdraw-watcher-config.js @@ -4,6 +4,7 @@ const ForeignABI = require('../abis/ForeignBridge.abi') module.exports = { event: 'Withdraw', + name: 'watcher-withdraw', url: process.env.FOREIGN_RPC_URL, contractAddress: process.env.FOREIGN_BRIDGE_ADDRESS, abi: ForeignABI, diff --git a/package-lock.json b/package-lock.json index 63e33ed..87f50df 100644 --- a/package-lock.json +++ b/package-lock.json @@ -625,7 +625,6 @@ "version": "2.4.1", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", - "dev": true, "requires": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -636,7 +635,6 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, "requires": { "color-convert": "^1.9.0" } @@ -645,7 +643,6 @@ "version": "5.4.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", - "dev": true, "requires": { "has-flag": "^3.0.0" } @@ -708,7 +705,6 @@ "version": "1.9.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", - "dev": true, "requires": { "color-name": "^1.1.1" } @@ -716,8 +712,7 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, "combined-stream": { "version": "1.0.6", @@ -1239,8 +1234,7 @@ "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, "eslint": { "version": "4.19.1", @@ -1582,6 +1576,11 @@ "integrity": "sha512-KaJUt+M9t1qaIteSvjc6P3RbMdXsNhK61GRftR6SNxqmhthcd9MGIi4T+o0jD8LUSpSnSKXE20nLtJ3fOHxQig==", "dev": true }, + "fast-json-parse": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fast-json-parse/-/fast-json-parse-1.0.3.tgz", + "integrity": "sha512-FRWsaZRWEJ1ESVNbDWmsAlqDk96gPQezzLghafp5J4GUKjbCz3OkAHuZs5TuPEtkbVQERysLp9xv6c24fBm8Aw==" + }, "fast-json-stable-stringify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", @@ -1593,6 +1592,11 @@ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, + "fast-safe-stringify": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-1.2.3.tgz", + "integrity": "sha512-QJYT/i0QYoiZBQ71ivxdyTqkwKkQ0oxACXHYxH2zYHJEgzi2LsbjgvtzTbLi1SZcF190Db2YP7I7eTsU2egOlw==" + }, "fd-slicer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz", @@ -1625,6 +1629,16 @@ "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", "integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=" }, + "fill-keys": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/fill-keys/-/fill-keys-1.0.2.tgz", + "integrity": "sha1-mo+jb06K1jTjv2tPPIiCVRRS6yA=", + "dev": true, + "requires": { + "is-object": "~1.0.1", + "merge-descriptors": "~1.0.0" + } + }, "finalhandler": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", @@ -1668,6 +1682,11 @@ "write": "^0.2.1" } }, + "flatstr": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/flatstr/-/flatstr-1.0.8.tgz", + "integrity": "sha512-YXblbv/vc1zuVVUtnKl1hPqqk7TalZCppnKE7Pr8FI/Rp48vzckS/4SJ4Y9O9RNiI82Vcw/FydmtqdQOg1Dpqw==" + }, "flexbuffer": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/flexbuffer/-/flexbuffer-0.0.6.tgz", @@ -1893,8 +1912,7 @@ "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" }, "has-symbol-support-x": { "version": "1.4.2", @@ -2672,6 +2690,12 @@ "resolved": "https://registry.npmjs.org/mock-fs/-/mock-fs-4.4.2.tgz", "integrity": "sha512-dF+yxZSojSiI8AXGoxj5qdFWpucndc54Ug+TwlpHFaV7j22MGG+OML2+FVa6xAZtjb/OFFQhOC37Jegx2GbEwA==" }, + "module-not-found-error": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/module-not-found-error/-/module-not-found-error-1.0.1.tgz", + "integrity": "sha1-z4tP9PKWQGdNbN0CsOO8UjwrvcA=", + "dev": true + }, "mout": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/mout/-/mout-0.11.1.tgz", @@ -5061,6 +5085,26 @@ "pinkie": "^2.0.0" } }, + "pino": { + "version": "4.17.3", + "resolved": "https://registry.npmjs.org/pino/-/pino-4.17.3.tgz", + "integrity": "sha512-3CBWMG1k6QdOyz9br3WzOhUQD52QFskbmlgX51wGXLPAY0UbKPsUIayYcVOQMCqjmeqEPCAG3V/Uvry+FjwtoQ==", + "requires": { + "chalk": "^2.4.1", + "fast-json-parse": "^1.0.3", + "fast-safe-stringify": "^1.2.3", + "flatstr": "^1.0.5", + "pino-std-serializers": "^2.0.0", + "pump": "^3.0.0", + "quick-format-unescaped": "^1.1.2", + "split2": "^2.2.0" + } + }, + "pino-std-serializers": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-2.1.0.tgz", + "integrity": "sha512-NqWvrQD/GpY78ybiNBzi/dg8ylERhDo6nB33j5sfCKpUmWLc3lYzeoBjyRoCMvEpDpL9lmH6ufRd0jw6rcd1pQ==" + }, "pkg-dir": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz", @@ -5132,6 +5176,28 @@ "ipaddr.js": "1.6.0" } }, + "proxyquire": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/proxyquire/-/proxyquire-2.0.1.tgz", + "integrity": "sha512-fQr3VQrbdzHrdaDn3XuisVoJlJNDJizHAvUXw9IuXRR8BpV2x0N7LsCxrpJkeKfPbNjiNU/V5vc008cI0TmzzQ==", + "dev": true, + "requires": { + "fill-keys": "^1.0.2", + "module-not-found-error": "^1.0.0", + "resolve": "~1.5.0" + }, + "dependencies": { + "resolve": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.5.0.tgz", + "integrity": "sha512-hgoSGrc3pjzAPHNBg+KnFcK2HwlHTs/YrAGUr6qgTVUZmXv1UEXXl0bZNBKMA9fud6lRYFdPGz0xXxycPzmmiw==", + "dev": true, + "requires": { + "path-parse": "^1.0.5" + } + } + } + }, "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", @@ -5150,6 +5216,15 @@ "randombytes": "^2.0.1" } }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "punycode": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", @@ -5170,6 +5245,14 @@ "strict-uri-encode": "^1.0.0" } }, + "quick-format-unescaped": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-1.1.2.tgz", + "integrity": "sha1-DKWB3jF0vs7yWsPC6JVjQjgdtpg=", + "requires": { + "fast-safe-stringify": "^1.0.8" + } + }, "randombytes": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.6.tgz", @@ -5677,6 +5760,14 @@ "integrity": "sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA==", "dev": true }, + "split2": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-2.2.0.tgz", + "integrity": "sha512-RAb22TG39LhI31MbreBgIuKiIKhVsawfTgEGqKHTK87aG+ul/PB8Sqoi3I7kVdRWiCfrKxK3uo4/YUkpNvhPbw==", + "requires": { + "through2": "^2.0.2" + } + }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -5889,6 +5980,15 @@ "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" }, + "through2": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", + "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", + "requires": { + "readable-stream": "^2.1.5", + "xtend": "~4.0.1" + } + }, "timed-out": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", diff --git a/package.json b/package.json index 52d6270..cc528d7 100644 --- a/package.json +++ b/package.json @@ -11,8 +11,8 @@ "sender:home": "node src/sender.js home-sender-config.js", "sender:foreign": "node src/sender.js foreign-sender-config.js", "dev": "concurrently -n 'watcher:deposit,watcher:collected-signatures,watcher:withdraw,sender:home,sender:foreign' -c 'red,green,yellow,blue,magenta' 'npm run watcher:deposit' 'npm run watcher:collected-signatures' 'npm run watcher:withdraw' 'npm run sender:home' 'npm run sender:foreign'", - "test": "mocha", - "coverage": "nyc --reporter=text --reporter=html mocha", + "test": "NODE_ENV=test mocha", + "coverage": "NODE_ENV=test nyc --reporter=text --reporter=html mocha", "postinstall": "npm install --prefix e2e" }, "author": "", @@ -24,6 +24,7 @@ "dotenv": "^5.0.1", "ioredis": "^3.2.2", "node-fetch": "^2.1.2", + "pino": "^4.17.3", "promise-retry": "^1.1.1", "redlock": "^3.1.2", "web3": "^1.0.0-beta.34", @@ -42,6 +43,7 @@ "mocha": "^5.2.0", "nyc": "^12.0.2", "prettier": "^1.12.1", + "proxyquire": "^2.0.1", "sinon": "^6.1.0" }, "engines": { diff --git a/src/events/processCollectedSignatures.js b/src/events/processCollectedSignatures.js index cdc18f2..1094e56 100644 --- a/src/events/processCollectedSignatures.js +++ b/src/events/processCollectedSignatures.js @@ -1,5 +1,6 @@ require('dotenv').config() const Web3 = require('web3') +const logger = require('../services/logger') const { signatureToVRS } = require('../utils/message') const { @@ -24,7 +25,7 @@ const foreignBridge = new web3Foreign.eth.Contract(ForeignABI, FOREIGN_BRIDGE_AD async function processCollectedSignatures(signatures) { const txToSend = [] - const callbacks = signatures.map(async (colSignature, indexSig) => { + const callbacks = signatures.map(async colSignature => { const { authorityResponsibleForRelay, messageHash, @@ -32,6 +33,10 @@ async function processCollectedSignatures(signatures) { } = colSignature.returnValues if (authorityResponsibleForRelay === web3Home.utils.toChecksumAddress(VALIDATOR_ADDRESS)) { + logger.info( + { eventTransactionHash: colSignature.transactionHash }, + `Processing CollectedSignatures ${colSignature.transactionHash}` + ) const message = await homeBridge.methods.message(messageHash).call() const requiredSignatures = [] @@ -53,7 +58,13 @@ async function processCollectedSignatures(signatures) { try { gasEstimate = await foreignBridge.methods.deposit(v, r, s, message).estimateGas() } catch (e) { - console.log(indexSig + 1, ' # already processed col sig', colSignature.transactionHash) + if (e.message.includes('Invalid JSON RPC response')) { + throw new Error(`RPC Connection Error: deposit Gas Estimate cannot be obtained.`) + } + logger.info( + { eventTransactionHash: colSignature.transactionHash }, + `Already processed CollectedSignatures ${colSignature.transactionHash}` + ) return } const data = await foreignBridge.methods.deposit(v, r, s, message).encodeABI() @@ -62,6 +73,11 @@ async function processCollectedSignatures(signatures) { gasEstimate, transactionReference: colSignature.transactionHash }) + } else { + logger.info( + { eventTransactionHash: colSignature.transactionHash }, + `Validator not responsible for relaying CollectedSignatures ${colSignature.transactionHash}` + ) } }) diff --git a/src/events/processDeposits.js b/src/events/processDeposits.js index 7fdd094..ee3934a 100644 --- a/src/events/processDeposits.js +++ b/src/events/processDeposits.js @@ -1,5 +1,6 @@ require('dotenv').config() const Web3 = require('web3') +const logger = require('../services/logger') const { createMessage } = require('../utils/message') const { @@ -18,9 +19,14 @@ const homeBridge = new web3Home.eth.Contract(HomeABI, HOME_BRIDGE_ADDRESS) async function processDeposits(deposits) { const txToSend = [] - const callbacks = deposits.map(async (deposit, index) => { + const callbacks = deposits.map(async deposit => { const { recipient, value } = deposit.returnValues + logger.info( + { eventTransactionHash: deposit.transactionHash, sender: recipient, value }, + `Processing Deposit ${deposit.transactionHash}` + ) + const message = createMessage({ recipient, value, @@ -35,7 +41,13 @@ async function processDeposits(deposits) { .submitSignature(signature.signature, message) .estimateGas({ from: VALIDATOR_ADDRESS }) } catch (e) { - console.log(index + 1, '# already processed deposit ', deposit.transactionHash) + if (e.message.includes('Invalid JSON RPC response')) { + throw new Error(`RPC Connection Error: submitSignature Gas Estimate cannot be obtained.`) + } + logger.info( + { eventTransactionHash: deposit.transactionHash }, + `Already processed Deposit ${deposit.transactionHash}` + ) return } diff --git a/src/events/processWithdraw.js b/src/events/processWithdraw.js index dbc718d..53ca28b 100644 --- a/src/events/processWithdraw.js +++ b/src/events/processWithdraw.js @@ -1,5 +1,6 @@ require('dotenv').config() const Web3 = require('web3') +const logger = require('../services/logger') const { HOME_RPC_URL, HOME_BRIDGE_ADDRESS, VALIDATOR_ADDRESS } = process.env @@ -12,16 +13,27 @@ const homeBridge = new web3Home.eth.Contract(HomeABI, HOME_BRIDGE_ADDRESS) async function processWithdraw(withdrawals) { const txToSend = [] - const callbacks = withdrawals.map(async (withdrawal, index) => { + const callbacks = withdrawals.map(async withdrawal => { const { recipient, value } = withdrawal.returnValues + logger.info( + { eventTransactionHash: withdrawal.transactionHash, sender: recipient, value }, + `Processing Withdraw ${withdrawal.transactionHash}` + ) + let gasEstimate try { gasEstimate = await homeBridge.methods .withdraw(recipient, value, withdrawal.transactionHash) .estimateGas({ from: VALIDATOR_ADDRESS }) } catch (e) { - console.log(index + 1, '# already processed withdrawal', withdrawal.transactionHash) + if (e.message.includes('Invalid JSON RPC response')) { + throw new Error(`RPC Connection Error: withdraw Gas Estimate cannot be obtained.`) + } + logger.info( + { eventTransactionHash: withdrawal.transactionHash }, + `Already processed Withdraw ${withdrawal.transactionHash}` + ) return } diff --git a/src/sender.js b/src/sender.js index 3d33135..f9e9e65 100644 --- a/src/sender.js +++ b/src/sender.js @@ -4,6 +4,7 @@ const Web3 = require('web3') const { connectSenderToQueue } = require('./services/amqpClient') const { redis, redlock } = require('./services/redisClient') const GasPrice = require('./services/gasPrice') +const logger = require('./services/logger') const { sendTx } = require('./tx/sendTx') const { getNonce, getChainId } = require('./tx/web3') const { addExtraGas, checkHTTPS, syncForEach, waitForFunds } = require('./utils/utils') @@ -12,7 +13,7 @@ const { EXTRA_GAS_PERCENTAGE } = require('./utils/constants') const { VALIDATOR_ADDRESS, VALIDATOR_ADDRESS_PRIVATE_KEY, REDIS_LOCK_TTL } = process.env if (process.argv.length < 3) { - console.error('Please check the number of arguments, config file was not provided') + logger.error('Please check the number of arguments, config file was not provided') process.exit(1) } @@ -39,13 +40,13 @@ async function initialize() { cb: main }) } catch (e) { - console.log(e.message) + logger.error(e.message) process.exit(1) } } function resume(newBalance) { - console.log( + logger.info( `Validator balance changed. New balance is ${newBalance}. Resume messages processing.` ) initialize() @@ -67,24 +68,17 @@ function updateNonce(nonce) { async function main({ msg, ackMsg, nackMsg, sendToQueue, channel }) { try { if (redis.status !== 'ready') { - console.log('Redis not connected.') nackMsg(msg) return } const txArray = JSON.parse(msg.content) - console.log(`Msg received with ${txArray.length} Tx to send`) - + logger.info(`Msg received with ${txArray.length} Tx to send`) const gasPrice = await GasPrice.getPrice() const ttl = REDIS_LOCK_TTL * txArray.length - const startTryLock = new Date() const lock = await redlock.lock(nonceLock, ttl) - const startTimeLocked = new Date() - const timeWaitingForLock = startTimeLocked - startTryLock - console.log('Nonce Locked! After: ', timeWaitingForLock) - let nonce = await readNonce() let insufficientFunds = false let minimumBalance = null @@ -108,17 +102,23 @@ async function main({ msg, ackMsg, nackMsg, sendToQueue, channel }) { }) nonce++ - console.log(`Tx generated ${txHash} for event Tx ${job.transactionReference}`) + logger.info( + { eventTransactionHash: job.transactionReference, generatedTransactionHash: txHash }, + `Tx generated ${txHash} for event Tx ${job.transactionReference}` + ) } catch (e) { - console.error(e.message) - console.error(`Tx Failed for event Tx ${job.transactionReference}`) + logger.error( + { eventTransactionHash: job.transactionReference, error: e.message }, + `Tx Failed for event Tx ${job.transactionReference}.`, + e.message + ) failedTx.push(job) if (e.message.includes('Insufficient funds')) { insufficientFunds = true const currentBalance = await web3Instance.eth.getBalance(VALIDATOR_ADDRESS) minimumBalance = gasLimit.multipliedBy(gasPrice) - console.error( + logger.error( `Insufficient funds: ${currentBalance}. Stop processing messages until the balance is at least ${minimumBalance}.` ) } else if ( @@ -133,21 +133,19 @@ async function main({ msg, ackMsg, nackMsg, sendToQueue, channel }) { await updateNonce(nonce) await lock.unlock() - const timeLocked = new Date() - startTimeLocked - console.log('Nonce Released! Time Locked: ', timeLocked) - if (failedTx.length) { - console.log(`Sending ${failedTx.length} Failed Tx to Queue`) + logger.info(`Sending ${failedTx.length} Failed Tx to Queue`) await sendToQueue(failedTx) } ackMsg(msg) + logger.info(`Finished processing msg`) if (insufficientFunds) { channel.close() waitForFunds(web3Instance, VALIDATOR_ADDRESS, minimumBalance, resume) } } catch (e) { - console.error(e) + logger.error(e) nackMsg(msg) } } diff --git a/src/services/amqpClient.js b/src/services/amqpClient.js index 2cd4316..7fbd830 100644 --- a/src/services/amqpClient.js +++ b/src/services/amqpClient.js @@ -1,12 +1,13 @@ require('dotenv').config() const connection = require('amqp-connection-manager').connect(process.env.QUEUE_URL) +const logger = require('./logger') connection.on('connect', () => { - console.log('Connected to amqp Broker') + logger.info('Connected to amqp Broker') }) connection.on('disconnect', () => { - console.error('Disconnected from amqp Broker') + logger.error('Disconnected from amqp Broker') }) function connectWatcherToQueue({ queueName, cb }) { diff --git a/src/services/gasPrice.js b/src/services/gasPrice.js index 440c318..6d13243 100644 --- a/src/services/gasPrice.js +++ b/src/services/gasPrice.js @@ -3,6 +3,7 @@ const Web3 = require('web3') const fetch = require('node-fetch') const HomeABI = require('../../abis/HomeBridge.abi') const ForeignABI = require('../../abis/ForeignBridge.abi') +const logger = require('../services/logger') const { FOREIGN_BRIDGE_ADDRESS, @@ -44,12 +45,12 @@ async function fetchGasPrice({ bridgeContract, oracleFn }) { try { gasPrice = await oracleFn() } catch (e) { - console.error(`Gas Price API is not available. ${e.message}`) + logger.error(`Gas Price API is not available. ${e.message}`) try { gasPrice = await bridgeContract.methods.gasPrice().call() } catch (e) { - console.error(`There was a problem getting the gas price from the contract. ${e.message}`) + logger.error(`There was a problem getting the gas price from the contract. ${e.message}`) } } return gasPrice diff --git a/src/services/logger.js b/src/services/logger.js new file mode 100644 index 0000000..5f0ced3 --- /dev/null +++ b/src/services/logger.js @@ -0,0 +1,19 @@ +const pino = require('pino') +const path = require('path') + +const config = + process.env.NODE_ENV !== 'test' ? require(path.join('../../config/', process.argv[2])) : {} + +const logger = pino({ + enabled: process.env.NODE_ENV !== 'test', + prettyPrint: process.env.NODE_ENV !== 'production', + name: config.name, + base: + process.env.NODE_ENV === 'production' + ? { + validator: process.env.VALIDATOR_ADDRESS + } + : {} +}) + +module.exports = logger diff --git a/src/services/redisClient.js b/src/services/redisClient.js index 2fa0a11..eb47307 100644 --- a/src/services/redisClient.js +++ b/src/services/redisClient.js @@ -1,5 +1,6 @@ const Redis = require('ioredis') const Redlock = require('redlock') +const logger = require('./logger') const redis = new Redis(process.env.REDIS_URL) const redlock = new Redlock([redis], { @@ -10,11 +11,11 @@ const redlock = new Redlock([redis], { }) redis.on('connect', () => { - console.log('Connected to redis') + logger.info('Connected to redis') }) -redis.on('reconnecting', () => { - console.log('Trying to connect to redis') +redis.on('error', () => { + logger.error('Disconnected from redis') }) module.exports = { diff --git a/src/utils/utils.js b/src/utils/utils.js index 6555102..40dbff2 100644 --- a/src/utils/utils.js +++ b/src/utils/utils.js @@ -1,5 +1,6 @@ const BigNumber = require('bignumber.js') const promiseRetry = require('promise-retry') +const logger = require('../services/logger') async function syncForEach(array, callback) { for (let index = 0; index < array.length; index++) { @@ -13,7 +14,7 @@ function checkHTTPS(ALLOW_HTTP) { if (ALLOW_HTTP !== 'yes') { throw new Error(`http is not allowed: ${url}`) } else { - console.warn(`You are using http (${url}). In production https must be used instead.`) + logger.warn(`You are using http (${url}). In production https must be used instead.`) } } } diff --git a/src/watcher.js b/src/watcher.js index 3b78293..5247e82 100644 --- a/src/watcher.js +++ b/src/watcher.js @@ -7,11 +7,12 @@ const processDeposits = require('./events/processDeposits') const processCollectedSignatures = require('./events/processCollectedSignatures') const processWithdraw = require('./events/processWithdraw') const { redis } = require('./services/redisClient') +const logger = require('./services/logger') const { getRequiredBlockConfirmations, getEvents } = require('./tx/web3') const { checkHTTPS } = require('./utils/utils') if (process.argv.length < 3) { - console.error('Please check the number of arguments, config file was not provided') + logger.error('Please check the number of arguments, config file was not provided') process.exit(1) } @@ -36,7 +37,7 @@ async function initialize() { cb: runMain }) } catch (e) { - console.log(e) + logger.error(e) process.exit(1) } } @@ -47,7 +48,7 @@ async function runMain({ sendToQueue }) { await main({ sendToQueue }) } } catch (e) { - console.error(e) + logger.error(e) } setTimeout(() => { @@ -101,11 +102,11 @@ async function main({ sendToQueue }) { fromBlock: lastProcessedBlock + 1, toBlock: lastBlockToProcess }) - console.log(`Found ${events.length} ${config.event}`) + logger.info(`Found ${events.length} ${config.event} events`) if (events.length) { const job = await processEvents(events) - console.log('Tx to send: ', job.length) + logger.info('Transactions to send:', job.length) if (job.length) { await sendToQueue(job) @@ -114,7 +115,7 @@ async function main({ sendToQueue }) { await updateLastProcessedBlock(lastBlockToProcess) } catch (e) { - console.error(e) + logger.error(e) } } diff --git a/test/utils.test.js b/test/utils.test.js index 1eae2cd..8327a90 100644 --- a/test/utils.test.js +++ b/test/utils.test.js @@ -2,7 +2,8 @@ const sinon = require('sinon') const chai = require('chai') const chaiAsPromised = require('chai-as-promised') const BigNumber = require('bignumber.js') -const { addExtraGas, checkHTTPS, syncForEach } = require('../src/utils/utils') +const proxyquire = require('proxyquire') +const { addExtraGas, syncForEach } = require('../src/utils/utils') chai.use(chaiAsPromised) const { expect } = chai @@ -35,31 +36,30 @@ describe('utils', () => { }) describe('checkHTTPS', () => { + let utils + const logger = { warn: sinon.stub() } beforeEach(() => { - sinon.stub(console, 'warn') - }) - - afterEach(() => { - console.warn.restore() + logger.warn.reset() + utils = proxyquire('../src/utils/utils', { '../services/logger': logger }) }) it('should do nothing if HTTP is allowed and the URL is https', () => { - checkHTTPS('yes')('https://www.google.com') - expect(console.warn.called).to.equal(false) + utils.checkHTTPS('yes')('https://www.google.com') + expect(logger.warn.called).to.equal(false) }) it('should emit a warning if HTTP is allowed and the URL is http', () => { - checkHTTPS('yes')('http://www.google.com') - expect(console.warn.called).to.equal(true) + utils.checkHTTPS('yes')('http://www.google.com') + expect(logger.warn.called).to.equal(true) }) it('should do nothing if HTTP is not allowed and the URL is https', () => { - checkHTTPS('no')('https://www.google.com') - expect(console.warn.called).to.equal(false) + utils.checkHTTPS('no')('https://www.google.com') + expect(logger.warn.called).to.equal(false) }) it('should throw an error if HTTP is not allowed and the URL is http', () => { - expect(() => checkHTTPS('no')('http://www.google.com')).to.throw() + expect(() => utils.checkHTTPS('no')('http://www.google.com')).to.throw() }) })