Logging and Caching

This commit is contained in:
Richard Ramos 2018-09-18 09:11:53 -04:00
parent 3c1f70df9a
commit c2534570cc
11 changed files with 312 additions and 67 deletions

View File

@ -26,12 +26,14 @@ module.exports = {
"0x0000000000000000000000000000000000000000": {
"name": "Ethereum",
"symbol": "ETH",
"minAcceptedRate": 1
"minAcceptedRate": 1,
"refreshPricePeriod": 60000
},
"%STTAddress%": {
"name": "Status Test Token",
"symbol": "SNT",
"minAcceptedRate": 0.0001500,
"refreshPricePeriod": 60000,
"pricePlugin": "../plugins/token-utils.js"
}
},

View File

@ -26,14 +26,15 @@ module.exports = {
"0x0000000000000000000000000000000000000000": {
"name": "Ethereum",
"symbol": "ETH",
"minAcceptedRate": 1
"minAcceptedRate": 1,
"refreshPricePeriod": 60000
},
"0x121a430A73Fc13e2D6d4a9dc3E943de647c30f8f": {
"name": "Status Gas Relayer Test Token",
"symbol": "SNT",
"minAcceptedRate": 0.0001500,
"pricePlugin": "../plugins/token-utils.js"
"pricePlugin": "../plugins/token-utils.js",
"refreshPricePeriod": 60000
}
},

View File

@ -191,7 +191,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.3"
}
@ -259,6 +258,14 @@
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
},
"async": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz",
"integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==",
"requires": {
"lodash": "4.17.10"
}
},
"async-limiter": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz",
@ -884,7 +891,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",
@ -897,6 +903,11 @@
"integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=",
"dev": true
},
"ci-info": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.5.1.tgz",
"integrity": "sha512-fKFIKXaYiL1exImwJ0AhR/6jxFPSKQBk2ayV5NiNoruUs2+rxC2kNw0EG+1Z9dugZRdCrppskQ8DN2cyaUM1Hw=="
},
"cipher-base": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
@ -932,11 +943,19 @@
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
"integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ="
},
"color": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz",
"integrity": "sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==",
"requires": {
"color-convert": "1.9.3",
"color-string": "1.5.3"
}
},
"color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
"dev": true,
"requires": {
"color-name": "1.1.3"
}
@ -944,8 +963,35 @@
"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="
},
"color-string": {
"version": "1.5.3",
"resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.3.tgz",
"integrity": "sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==",
"requires": {
"color-name": "1.1.3",
"simple-swizzle": "0.2.2"
}
},
"colornames": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/colornames/-/colornames-1.1.1.tgz",
"integrity": "sha1-+IiQMGhcfE/54qVZ9Qd+t2qBb5Y="
},
"colors": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/colors/-/colors-1.3.2.tgz",
"integrity": "sha512-rhP0JSBGYvpcNQj4s5AdShMeE5ahMop96cTeDl/v9qQQm2fYClE2QXZRi8wLzc+GmXSxdIqqbOIAhyObEXDbfQ=="
},
"colorspace": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.1.tgz",
"integrity": "sha512-pI3btWyiuz7Ken0BWh9Elzsmv2bM9AhA7psXib4anUXy/orfZ/E0MbQwhSOG/9L8hLlalqrU0UhOuqxW1YjmVw==",
"requires": {
"color": "3.0.0",
"text-hex": "1.0.0"
}
},
"combined-stream": {
"version": "1.0.6",
@ -980,6 +1026,17 @@
"typedarray": "0.0.6"
}
},
"consola": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/consola/-/consola-1.4.3.tgz",
"integrity": "sha512-PIbVeO9JVVeJ9eY2n8PrkL+hXBGnmaD5x4yJxp2K9nWR7zgtAzRn7rmWxu/d0Iyyr92v8s5AM0qax6xQZ5rSeQ==",
"requires": {
"chalk": "2.4.1",
"figures": "2.0.0",
"lodash": "4.17.10",
"std-env": "1.3.1"
}
},
"contains-path": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz",
@ -1254,6 +1311,16 @@
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
"integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
},
"diagnostics": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/diagnostics/-/diagnostics-1.1.1.tgz",
"integrity": "sha512-8wn1PmdunLJ9Tqbx+Fx/ZEuHfJf4NKSN2ZBj7SJC/OWRWha843+WsTjqMe1B5E3p28jqBlp+mJ2fPVxPyNgYKQ==",
"requires": {
"colorspace": "1.1.1",
"enabled": "1.0.2",
"kuler": "1.0.0"
}
},
"diffie-hellman": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz",
@ -1312,6 +1379,14 @@
"minimalistic-crypto-utils": "1.0.1"
}
},
"enabled": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/enabled/-/enabled-1.0.2.tgz",
"integrity": "sha1-ll9lE9LC0cX0ZStkouM5ZGf8L5M=",
"requires": {
"env-variable": "0.0.4"
}
},
"encodeurl": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
@ -1325,6 +1400,11 @@
"once": "1.4.0"
}
},
"env-variable": {
"version": "0.0.4",
"resolved": "https://registry.npmjs.org/env-variable/-/env-variable-0.0.4.tgz",
"integrity": "sha512-+jpGxSWG4vr6gVxUHOc4p+ilPnql7NzZxOZBxNldsKGjCF+97df3CbuX7XMaDa5oAVkKQj4rKp38rYdC4VcpDg=="
},
"error-ex": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
@ -1342,8 +1422,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",
@ -1789,6 +1868,11 @@
"integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
"dev": true
},
"fast-safe-stringify": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.6.tgz",
"integrity": "sha512-q8BZ89jjc+mz08rSxROs8VsrBBcn1SIw1kq9NjolL509tkABRk9io01RAjSaEv1Xb2uFLt8VtRiZbGp5H8iDtg=="
},
"fd-slicer": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
@ -1797,11 +1881,15 @@
"pend": "1.2.0"
}
},
"fecha": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fecha/-/fecha-2.3.3.tgz",
"integrity": "sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg=="
},
"figures": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz",
"integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=",
"dev": true,
"requires": {
"escape-string-regexp": "1.0.5"
}
@ -2097,8 +2185,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",
@ -2290,6 +2377,14 @@
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz",
"integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA=="
},
"is-ci": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz",
"integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==",
"requires": {
"ci-info": "1.5.1"
}
},
"is-fullwidth-code-point": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
@ -2484,6 +2579,14 @@
"sha3": "1.2.2"
}
},
"kuler": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/kuler/-/kuler-1.0.0.tgz",
"integrity": "sha512-oyy6pu/yWRjiVfCoJebNUKFL061sNtrs9ejKTbirIwY3oiHmENVCSkHhxDV85Dkm7JYR/czMCBeoM87WilTdSg==",
"requires": {
"colornames": "1.1.1"
}
},
"levn": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
@ -2527,8 +2630,26 @@
"lodash": {
"version": "4.17.10",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
"integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==",
"dev": true
"integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg=="
},
"logform": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/logform/-/logform-1.9.1.tgz",
"integrity": "sha512-ZHrZE8VSf7K3xKxJiQ1aoTBp2yK+cEbFcgarsjzI3nt3nE/3O0heNSppoOQMUJVMZo/xiVwCxiXIabaZApsKNQ==",
"requires": {
"colors": "1.3.2",
"fast-safe-stringify": "2.0.6",
"fecha": "2.3.3",
"ms": "2.1.1",
"triple-beam": "1.3.0"
},
"dependencies": {
"ms": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
}
}
},
"loose-envify": {
"version": "1.4.0",
@ -2583,6 +2704,11 @@
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
"integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
},
"memory-cache": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/memory-cache/-/memory-cache-0.2.0.tgz",
"integrity": "sha1-eJCwHVLADI68nVM+H46xfjA0hxo="
},
"merge-descriptors": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
@ -2792,6 +2918,11 @@
"wrappy": "1.0.2"
}
},
"one-time": {
"version": "0.0.4",
"resolved": "https://registry.npmjs.org/one-time/-/one-time-0.0.4.tgz",
"integrity": "sha1-+M33eISCb+Tf+T46nMN7HkSAdC4="
},
"onetime": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz",
@ -3433,6 +3564,21 @@
"simple-concat": "1.0.0"
}
},
"simple-swizzle": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
"integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=",
"requires": {
"is-arrayish": "0.3.2"
},
"dependencies": {
"is-arrayish": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
"integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="
}
}
},
"slice-ansi": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz",
@ -3510,11 +3656,24 @@
"tweetnacl": "0.14.5"
}
},
"stack-trace": {
"version": "0.0.10",
"resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz",
"integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA="
},
"statuses": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
"integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
},
"std-env": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/std-env/-/std-env-1.3.1.tgz",
"integrity": "sha512-KI2F2pPJpd3lHjng+QLezu0eq+QDtXcv1um016mhOPAJFHKL+09ykK5PUBWta2pZDC8BVV0VPya08A15bUXSLQ==",
"requires": {
"is-ci": "1.2.1"
}
},
"strict-uri-encode": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz",
@ -3596,7 +3755,6 @@
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"requires": {
"has-flag": "3.0.0"
}
@ -3678,6 +3836,11 @@
}
}
},
"text-hex": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz",
"integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg=="
},
"text-table": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
@ -3750,6 +3913,11 @@
"integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=",
"dev": true
},
"triple-beam": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz",
"integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw=="
},
"tunnel-agent": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
@ -4191,6 +4359,31 @@
"isexe": "2.0.0"
}
},
"winston": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/winston/-/winston-3.1.0.tgz",
"integrity": "sha512-FsQfEE+8YIEeuZEYhHDk5cILo1HOcWkGwvoidLrDgPog0r4bser1lEIOco2dN9zpDJ1M88hfDgZvxe5z4xNcwg==",
"requires": {
"async": "2.6.1",
"diagnostics": "1.1.1",
"is-stream": "1.1.0",
"logform": "1.9.1",
"one-time": "0.0.4",
"readable-stream": "2.3.6",
"stack-trace": "0.0.10",
"triple-beam": "1.3.0",
"winston-transport": "4.2.0"
}
},
"winston-transport": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.2.0.tgz",
"integrity": "sha512-0R1bvFqxSlK/ZKTH86nymOuKv/cT1PQBMuDdA7k7f0S9fM44dNH6bXnuxwXPrN8lefJgtZq08BKdyZ0DZIy/rg==",
"requires": {
"readable-stream": "2.3.6",
"triple-beam": "1.3.0"
}
},
"wordwrap": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",

View File

@ -22,9 +22,12 @@
},
"dependencies": {
"axios": "^0.18.0",
"consola": "^1.4.3",
"daemonize2": "^0.4.2",
"ganache-cli": "^6.1.0",
"jsum": "^0.1.4",
"web3": "^1.0.0-beta.33"
"memory-cache": "^0.2.0",
"web3": "^1.0.0-beta.33",
"winston": "^3.1.0"
}
}

View File

@ -8,11 +8,12 @@ class ContractSettings {
* @param {object} web3 - Web3 object already configured
* @param {object} eventEmitter - Event Emitter
*/
constructor(config, web3, eventEmitter){
constructor(config, web3, eventEmitter, logger){
this.tokens = config.tokens;
this.topics = [];
this.contracts = config.contracts;
this.config = config;
this.logger = logger;
this.web3 = web3;
this.events = eventEmitter;
@ -107,8 +108,8 @@ class ContractSettings {
this.pendingToLoad--;
if(this.pendingToLoad == 0) this.events.emit("setup:complete", this);
} catch(err) {
console.error("Invalid contract for " + topicName);
console.error(err);
this.logger.error("Invalid contract for " + topicName);
this.logger.error(err);
process.exit();
}
}

View File

@ -9,11 +9,13 @@ class MessageProcessor {
* @param {object} web3 - Web3 object already configured
* @param {object} events - Event emitter
*/
constructor(config, settings, web3, events){
constructor(config, settings, web3, events, logger, cache){
this.config = config;
this.settings = settings;
this.web3 = web3;
this.events = events;
this.logger = logger;
this.cache = cache;
}
/**
@ -23,7 +25,7 @@ class MessageProcessor {
* @returns {object} State of validation
*/
async _validateInput(contract, input){
console.info("Processing '%s' request to contract: %s", input.action, input.contract);
this.logger.info("Processing '" + input.action + "' request to contract: " + input.contract);
if(contract == undefined){
return {success: false, message: 'Unknown contract'};
@ -71,9 +73,9 @@ class MessageProcessor {
if(strategy || contract.strategy){
let validationResult;
if(strategy){
validationResult = await strategy.execute(input, reply);
validationResult = await strategy.execute(input, this.cache);
} else {
validationResult = await contract.strategy.execute(input, reply);
validationResult = await contract.strategy.execute(input, this.cache);
}
if(!validationResult.success){
@ -114,7 +116,7 @@ class MessageProcessor {
if(nodeBalance < p.gas){
reply("Relayer unavailable");
console.error("Relayer doesn't have enough gas to process trx: %s, required %s", nodeBalance, p.gas);
this.logger.error("Relayer doesn't have enough gas to process trx: " + nodeBalance + ", required " + p.gas);
this.events.emit('exit');
} else {
try {
@ -129,7 +131,7 @@ class MessageProcessor {
} catch(err){
reply("Couldn't mine transaction: " + err.message);
// TODO log this?
console.error(err);
this.logger.error(err);
}
}
}

View File

@ -4,9 +4,24 @@ const config = require('../config/config.js');
const ContractSettings = require('./contract-settings');
const MessageProcessor = require('./message-processor');
const JSum = require('jsum');
const logger = require('consola');
const winston = require('winston');
var cache = require('memory-cache');
// Setting up logging
const wLogger = winston.createLogger({
level: 'info',
format: winston.format.simple(),
transports: [
new winston.transports.Console(),
new winston.transports.File({filename: 'gas-relayer.log'})
]
});
logger.clear().add(new logger.WinstonReporter(wLogger));
console.info("Starting...");
// Service Init
logger.info("Starting...");
const events = new EventEmitter();
// Web3 Connection
@ -17,14 +32,14 @@ const web3 = new Web3(wsProvider);
web3.eth.net.isListening()
.then(() => events.emit('web3:connected', connectionURL))
.catch(error => {
console.error(error);
logger.error(error);
process.exit();
});
events.on('web3:connected', connURL => {
console.info("Connected to '%s'", connURL);
let settings = new ContractSettings(config, web3, events);
logger.info("Connected to '" + connURL + "'");
let settings = new ContractSettings(config, web3, events, logger);
settings.process();
});
@ -37,9 +52,9 @@ const shhOptions = {
const verifyBalance = async (exitSubs) => {
const nodeBalance = await web3.eth.getBalance(config.node.blockchain.account);
if(web3.utils.toBN(nodeBalance).lte(web3.utils.toBN(100000))){ // TODO: tune minimum amount required for transactions
console.log("Not enough balance available for processing transactions");
console.log("> Account: %s", config.node.blockchain.account);
console.log("> Balance: %s", nodeBalance);
logger.info("Not enough balance available for processing transactions");
logger.info("> Account: " + config.node.blockchain.account);
logger.info("> Balance: " + nodeBalance);
if(exitSubs){
web3.shh.clearSubscriptions();
@ -51,7 +66,7 @@ const verifyBalance = async (exitSubs) => {
events.on('exit', () => {
web3.shh.clearSubscriptions();
console.log("Closing service...");
logger.info("Closing service...");
process.exit(0);
});
@ -67,11 +82,11 @@ events.on('setup:complete', async (settings) => {
// Listening to whisper
// Individual subscriptions due to https://github.com/ethereum/web3.js/issues/1361
// once this is fixed, we'll be able to use an array of topics and a single subs for symkey and a single subs for privKey
console.info(`Sym Key: ${config.node.whisper.symKey}`);
console.info(`Relayer Public Key: ${pubKey}`);
console.info("Topics Available:");
logger.info(`Sym Key: ${config.node.whisper.symKey}`);
logger.info(`Relayer Public Key: ${pubKey}`);
logger.info("Topics Available:");
for(let contract in settings.contracts) {
console.info("- %s: %s [%s]", settings.getContractByTopic(contract).name, contract, Object.keys(settings.getContractByTopic(contract).allowedFunctions).join(', '));
logger.info("- " + settings.getContractByTopic(contract).name + ": " + contract + " [" + (Object.keys(settings.getContractByTopic(contract).allowedFunctions).join(', ')) + "]");
shhOptions.topics = [contract];
// Listen to public channel - Used for reporting availability
@ -126,7 +141,7 @@ const extractInput = (message) => {
obj.gasPrice = parsedObj.gasPrice;
}
} catch(err){
console.error("Couldn't parse " + message);
logger.error("Couldn't parse " + message);
}
return obj;
@ -136,28 +151,29 @@ const extractInput = (message) => {
let messagesCheckSum = {};
events.on('server:listen', (shhOptions, settings) => {
let processor = new MessageProcessor(config, settings, web3, events);
let processor = new MessageProcessor(config, settings, web3, events, logger, cache);
web3.shh.subscribe('messages', shhOptions, async (error, message) => {
if(error){
console.error(error);
logger.error(error);
return;
}
verifyBalance(true);
const input = extractInput(message);
const inputCheckSum = JSum.digest(input, 'SHA256', 'hex');
const inputCheckSum = JSum.digest({input}, 'SHA256', 'hex');
const reply = replyFunction(message, inputCheckSum);
// TODO: Probably it makes sense to have some small db to store checksums
if(messagesCheckSum[inputCheckSum] && messagesCheckSum[inputCheckSum] + 3600000 > (new Date().getTime())){
if(cache.get(inputCheckSum)){
reply("Duplicated message received");
} else {
let validationResult;
switch(input.action){
case 'transaction':
messagesCheckSum[inputCheckSum] = (new Date().getTime());
cache.put(inputCheckSum, (new Date().getTime()), 86400000);
processor.processTransaction(settings.getContractByTopic(message.topic),
input,
reply);
@ -181,26 +197,14 @@ events.on('server:listen', (shhOptions, settings) => {
});
});
// Cleaning old message checksums
const deleteOldChecksums = () => {
for (var key in messagesCheckSum) {
if (messagesCheckSum.hasOwnProperty(key)) {
if(messagesCheckSum[key] + 86400000 < (new Date().getTime())){
delete messagesCheckSum[key];
}
}
}
};
setInterval(deleteOldChecksums, 3600000);
// Daemon helper functions
process.on("uncaughtException", function(err) {
// TODO
console.error(err);
logger.error(err);
});
process.once("SIGTERM", function() {
console.log("Stopping...");
logger.info("Stopping...");
});

View File

@ -11,14 +11,27 @@ class AvailabilityStrategy extends Strategy {
* @param {object} input - Object obtained from an 'availability' request. It expects an object with this structure `{contract, address, action, gasToken, gasPrice}`
* @returns {object} Status of validation, and minimum price
*/
async execute(input){
async execute(input, cache){
// Verifying if token is allowed
const token = this.settings.getToken(input.gasToken);
if(token == undefined) return {success: false, message: "Token not allowed"};
// Get Price
const tokenRate = await token.pricePlugin.getRate();
let tokenRate = cache.get(input.gasToken);
if(tokenRate === null){
try {
tokenRate = await token.pricePlugin.getRate();
cache.put(input.gasToken, tokenRate, token.refreshPricePeriod);
} catch (err) {
console.error(err);
return {
success: false,
message: "Token price unavailable"
};
}
}
const minRate = token.minAcceptedRate;
if(tokenRate >= minRate){ // TODO: verify this

View File

@ -90,7 +90,7 @@ class BaseStrategy {
}
/*
async execute(message, reply){
async execute(input){
return {
success: true,
message: "Valid transaction"

View File

@ -32,7 +32,7 @@ class IdentityStrategy extends Strategy {
* @param {object} input - Object obtained from an 'transaction' request. It expects an object with this structure `{contract, address, action, functionName, functionParameters, payload}`
* @returns {object} Status of validation and estimated gas
*/
async execute(input){
async execute(input, cache){
if(this.contract.isIdentity){
let validInstance = await this._validateInstance(input);
if(!validInstance){
@ -87,7 +87,20 @@ class IdentityStrategy extends Strategy {
}
// Get Price
const tokenRate = await token.pricePlugin.getRate();
let tokenRate = cache.get(input.gasToken);
if(tokenRate === null){
try {
tokenRate = await token.pricePlugin.getRate();
cache.put(input.gasToken, tokenRate, token.refreshPricePeriod);
} catch (err) {
console.error(err);
return {
success: false,
message: "Token price unavailable"
};
}
}
const minRate = token.minAcceptedRate;
if(tokenRate < minRate){ // TODO: verify this. Maybe we want to accept a minRate instead of just simply not processing the trx

View File

@ -14,7 +14,7 @@ class SNTStrategy extends Strategy {
* @param {object} input - Object obtained from an 'transaction' request. It expects an object with this structure `{contract, address, action, functionName, functionParameters, payload}`
* @returns {object} Status of validation and estimated gas
*/
async execute(input){
async execute(input, cache){
const params = this._obtainParametersFunc(input);
// Verifying if token is allowed
@ -30,7 +30,20 @@ class SNTStrategy extends Strategy {
});
// Get Price
const tokenRate = await token.pricePlugin.getRate();
let tokenRate = cache.get(input.gasToken);
if(tokenRate === null){
try {
tokenRate = await token.pricePlugin.getRate();
cache.put(input.gasToken, tokenRate, token.refreshPricePeriod);
} catch (err) {
console.error(err);
return {
success: false,
message: "Token price unavailable"
};
}
}
const minRate = token.minAcceptedRate;
if(tokenRate < minRate){ // TODO: verify this. Maybe we want to accept a minRate instead of just simply not processing the trx