diff --git a/.editorconfig b/.editorconfig index 99580d06..cf80b4e9 100644 --- a/.editorconfig +++ b/.editorconfig @@ -5,5 +5,5 @@ charset = utf-8 end_of_line = lf insert_final_newline = true indent_style = space -indent_size = 2 +indent_size = 4 trim_trailing_whitespace = true diff --git a/.gitignore b/.gitignore index 3e77aa05..82f2272b 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,8 @@ /parity-data/reserved-peers /parity-data/spec.json /parity-data/StakingToken.json +/parity-data/watchBackedUpNode.* +/parity-data/isMining.* # NPM files /node_modules/ diff --git a/config/node6.toml b/config/node1-no-signer.toml similarity index 64% rename from config/node6.toml rename to config/node1-no-signer.toml index 98e49e2f..95dcecfb 100644 --- a/config/node6.toml +++ b/config/node1-no-signer.toml @@ -1,22 +1,20 @@ [parity] chain = "./parity-data/spec.json" -base_path = "parity-data/node6" +base_path = "parity-data/node1" [ui] disable = true [network] -port = 30306 -discovery = true -reserved_peers="parity-data/reserved-peers" +port = 30301 nat = "none" [rpc] apis = ["web3", "eth", "pubsub", "net", "parity", "parity_set", "parity_pubsub", "personal", "traces", "rpc", "shh", "shh_pubsub"] -port = 8546 +port = 8541 [websockets] -port = 9546 +port = 9541 [ipc] disable = true @@ -28,13 +26,11 @@ disable = true enable = false [account] -unlock = ["0x522df396ae70a058bd69778408630fdb023389b2"] +unlock = ["0xbbcaa8d48289bb1ffcf9808d9aa4b1d215054c78", "0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24"] password = ["config/password"] [mining] -force_sealing = true min_gas_price = 1000000000 -engine_signer = "0x522df396ae70a058bd69778408630fdb023389b2" reseal_on_txs = "none" extra_data = "Parity" diff --git a/config/node1.toml b/config/node1.toml index 2ae47b1f..8ac9ab76 100644 --- a/config/node1.toml +++ b/config/node1.toml @@ -30,7 +30,6 @@ unlock = ["0xbbcaa8d48289bb1ffcf9808d9aa4b1d215054c78", "0x32e4e4c7c5d1cea5db5f9 password = ["config/password"] [mining] -force_sealing = true min_gas_price = 1000000000 engine_signer = "0xbbcaa8d48289bb1ffcf9808d9aa4b1d215054c78" reseal_on_txs = "none" diff --git a/config/node4.toml b/config/node4.toml index e9a13295..097d271b 100644 --- a/config/node4.toml +++ b/config/node4.toml @@ -7,6 +7,8 @@ disable = true [network] port = 30304 +discovery = true +reserved_peers="parity-data/reserved-peers" nat = "none" [rpc] @@ -26,13 +28,11 @@ disable = true enable = false [account] -unlock = ["0xbbcaa8d48289bb1ffcf9808d9aa4b1d215054c78"] +unlock = ["0xbbcaa8d48289bb1ffcf9808d9aa4b1d215054c78", "0x32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24"] password = ["config/password"] [mining] -force_sealing = true min_gas_price = 1000000000 -engine_signer = "0xbbcaa8d48289bb1ffcf9808d9aa4b1d215054c78" reseal_on_txs = "none" extra_data = "Parity" diff --git a/package-lock.json b/package-lock.json index fbd685af..63f8466e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,6 +4,19 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==" + }, + "@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "requires": { + "defer-to-connect": "^1.0.1" + } + }, "@types/node": { "version": "10.14.6", "resolved": "https://registry.npmjs.org/@types/node/-/node-10.14.6.tgz", @@ -275,6 +288,13 @@ "requires": { "js-sha3": "^0.6.1", "safe-buffer": "^5.1.1" + }, + "dependencies": { + "js-sha3": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.6.1.tgz", + "integrity": "sha1-W4n3enR3Z5h39YxKB1JAk0sflcA=" + } } }, "browserify-sign": { @@ -339,6 +359,30 @@ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" }, + "cacheable-request": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.0.0.tgz", + "integrity": "sha512-2N7AmszH/WPPpl5Z3XMw1HAP+8d+xugnKQAeKvxFZ/04dbT/CAznqwbl+7eSr3HkwdepNwtb2yx3CAMQWvG01Q==", + "requires": { + "clone-response": "^1.0.2", + "get-stream": "^4.0.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^1.0.1", + "normalize-url": "^3.1.0", + "responselike": "^1.0.2" + }, + "dependencies": { + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "requires": { + "pump": "^3.0.0" + } + } + } + }, "camelcase": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", @@ -419,6 +463,14 @@ "wrap-ansi": "^2.0.0" } }, + "clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "requires": { + "mimic-response": "^1.0.0" + } + }, "code-point-at": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", @@ -694,6 +746,11 @@ "type-detect": "^4.0.0" } }, + "defer-to-connect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.0.2.tgz", + "integrity": "sha512-k09hcQcTDY+cwgiwa6PYKLm3jlagNzQ+RSvhjzESOGOx+MNOuXkxTfEvPrO1IOQ81tArCFYQgi631clB70RpQw==" + }, "define-properties": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", @@ -857,13 +914,6 @@ "requires": { "idna-uts46-hx": "^2.3.1", "js-sha3": "^0.5.7" - }, - "dependencies": { - "js-sha3": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", - "integrity": "sha1-DU/9gALVMzqrr0oj7tL2N0yfKOc=" - } } }, "eth-lib": { @@ -909,9 +959,9 @@ } }, "ethers": { - "version": "4.0.0-beta.1", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-4.0.0-beta.1.tgz", - "integrity": "sha512-SoYhktEbLxf+fiux5SfCEwdzWENMvgIbMZD90I62s4GZD9nEjgEWy8ZboI3hck193Vs0bDoTohDISx84f2H2tw==", + "version": "4.0.27", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-4.0.27.tgz", + "integrity": "sha512-+DXZLP/tyFnXWxqr2fXLT67KlGUfLuvDkHSOtSC9TUVG9OIj6yrG5JPeXRMYo15xkOYwnjgdMKrXp5V94rtjJA==", "requires": { "@types/node": "^10.3.2", "aes-js": "3.0.0", @@ -919,7 +969,7 @@ "elliptic": "6.3.3", "hash.js": "1.1.3", "js-sha3": "0.5.7", - "scrypt-js": "2.0.3", + "scrypt-js": "2.0.4", "setimmediate": "1.0.4", "uuid": "2.0.1", "xmlhttprequest": "1.8.0" @@ -944,21 +994,6 @@ "inherits": "^2.0.3", "minimalistic-assert": "^1.0.0" } - }, - "js-sha3": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", - "integrity": "sha1-DU/9gALVMzqrr0oj7tL2N0yfKOc=" - }, - "setimmediate": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.4.tgz", - "integrity": "sha1-IOgd5iLUoCWIzgyNqJc8vPHTE48=" - }, - "uuid": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.1.tgz", - "integrity": "sha1-wqMN7bPlNdcsz4LjQ5QaULqFM6w=" } } }, @@ -1351,24 +1386,31 @@ } }, "got": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/got/-/got-7.1.0.tgz", - "integrity": "sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw==", + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", + "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", "requires": { - "decompress-response": "^3.2.0", + "@sindresorhus/is": "^0.14.0", + "@szmarczak/http-timer": "^1.1.2", + "cacheable-request": "^6.0.0", + "decompress-response": "^3.3.0", "duplexer3": "^0.1.4", - "get-stream": "^3.0.0", - "is-plain-obj": "^1.1.0", - "is-retry-allowed": "^1.0.0", - "is-stream": "^1.0.0", - "isurl": "^1.0.0-alpha5", - "lowercase-keys": "^1.0.0", - "p-cancelable": "^0.3.0", - "p-timeout": "^1.1.1", - "safe-buffer": "^5.0.1", - "timed-out": "^4.0.0", - "url-parse-lax": "^1.0.0", - "url-to-options": "^1.0.1" + "get-stream": "^4.1.0", + "lowercase-keys": "^1.0.1", + "mimic-response": "^1.0.1", + "p-cancelable": "^1.0.0", + "to-readable-stream": "^1.0.0", + "url-parse-lax": "^3.0.0" + }, + "dependencies": { + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "requires": { + "pump": "^3.0.0" + } + } } }, "graceful-fs": { @@ -1464,6 +1506,11 @@ "minimalistic-crypto-utils": "^1.0.1" } }, + "http-cache-semantics": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.0.3.tgz", + "integrity": "sha512-TcIMG3qeVLgDr1TEd2XvHaTnMPwYQUQMIBLy+5pLSDKYFc7UIqj39w8EGzZkaxoLv/l2K8HaI0t5AVA+YYgUew==" + }, "http-errors": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", @@ -1644,9 +1691,9 @@ } }, "js-sha3": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.6.1.tgz", - "integrity": "sha1-W4n3enR3Z5h39YxKB1JAk0sflcA=" + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", + "integrity": "sha1-DU/9gALVMzqrr0oj7tL2N0yfKOc=" }, "js-yaml": { "version": "3.13.1", @@ -1662,6 +1709,11 @@ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" }, + "json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=" + }, "json-schema": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", @@ -1751,6 +1803,14 @@ } } }, + "keyv": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", + "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "requires": { + "json-buffer": "3.0.0" + } + }, "klaw": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", @@ -2226,6 +2286,11 @@ } } }, + "normalize-url": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz", + "integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==" + }, "npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", @@ -2330,9 +2395,9 @@ "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" }, "p-cancelable": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.3.0.tgz", - "integrity": "sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw==" + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==" }, "p-defer": { "version": "1.0.0", @@ -2471,9 +2536,9 @@ } }, "prepend-http": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", - "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=" }, "process": { "version": "0.5.2", @@ -2629,6 +2694,11 @@ "version": "6.5.2", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + }, + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" } } }, @@ -2647,27 +2717,20 @@ "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=" }, + "responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "requires": { + "lowercase-keys": "^1.0.0" + } + }, "rimraf": { "version": "2.6.3", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", "requires": { "glob": "^7.1.3" - }, - "dependencies": { - "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - } } }, "ripemd160": { @@ -2707,9 +2770,9 @@ } }, "scrypt-js": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-2.0.3.tgz", - "integrity": "sha1-uwBAvgMEPamgEqLOqfyfhSz8h9Q=" + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-2.0.4.tgz", + "integrity": "sha512-4KsaGcPnuhtCZQCxFxN3GVYIhKFPTdLd8PLC552XwbMndtD0cjRFAhDuuydXQ0h08ZfPgzqe6EKHozpuH74iDw==" }, "scrypt.js": { "version": "0.2.0", @@ -2836,9 +2899,9 @@ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" }, "setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.4.tgz", + "integrity": "sha1-IOgd5iLUoCWIzgyNqJc8vPHTE48=" }, "setprototypeof": { "version": "1.1.1", @@ -3050,6 +3113,50 @@ "graceful-fs": "^4.1.2", "jsonfile": "^2.1.0" } + }, + "got": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/got/-/got-7.1.0.tgz", + "integrity": "sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw==", + "requires": { + "decompress-response": "^3.2.0", + "duplexer3": "^0.1.4", + "get-stream": "^3.0.0", + "is-plain-obj": "^1.1.0", + "is-retry-allowed": "^1.0.0", + "is-stream": "^1.0.0", + "isurl": "^1.0.0-alpha5", + "lowercase-keys": "^1.0.0", + "p-cancelable": "^0.3.0", + "p-timeout": "^1.1.1", + "safe-buffer": "^5.0.1", + "timed-out": "^4.0.0", + "url-parse-lax": "^1.0.0", + "url-to-options": "^1.0.1" + } + }, + "p-cancelable": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.3.0.tgz", + "integrity": "sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw==" + }, + "prepend-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=" + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" + }, + "url-parse-lax": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", + "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", + "requires": { + "prepend-http": "^1.0.1" + } } } }, @@ -3135,6 +3242,11 @@ "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==" }, + "to-readable-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", + "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==" + }, "toidentifier": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", @@ -3224,11 +3336,11 @@ } }, "url-parse-lax": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", - "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", "requires": { - "prepend-http": "^1.0.1" + "prepend-http": "^2.0.0" } }, "url-set-query": { @@ -3257,9 +3369,9 @@ "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" }, "uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.1.tgz", + "integrity": "sha1-wqMN7bPlNdcsz4LjQ5QaULqFM6w=" }, "vary": { "version": "1.1.2", @@ -3298,6 +3410,47 @@ "got": "7.1.0", "swarm-js": "0.1.37", "underscore": "1.8.3" + }, + "dependencies": { + "got": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/got/-/got-7.1.0.tgz", + "integrity": "sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw==", + "requires": { + "decompress-response": "^3.2.0", + "duplexer3": "^0.1.4", + "get-stream": "^3.0.0", + "is-plain-obj": "^1.1.0", + "is-retry-allowed": "^1.0.0", + "is-stream": "^1.0.0", + "isurl": "^1.0.0-alpha5", + "lowercase-keys": "^1.0.0", + "p-cancelable": "^0.3.0", + "p-timeout": "^1.1.1", + "safe-buffer": "^5.0.1", + "timed-out": "^4.0.0", + "url-parse-lax": "^1.0.0", + "url-to-options": "^1.0.1" + } + }, + "p-cancelable": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.3.0.tgz", + "integrity": "sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw==" + }, + "prepend-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=" + }, + "url-parse-lax": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", + "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", + "requires": { + "prepend-http": "^1.0.1" + } + } } }, "web3-core": { @@ -3392,6 +3545,50 @@ "ethers": "4.0.0-beta.1", "underscore": "1.8.3", "web3-utils": "1.0.0-beta.37" + }, + "dependencies": { + "elliptic": { + "version": "6.3.3", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.3.3.tgz", + "integrity": "sha1-VILZZG1UvLif19mU/J4ulWiHbj8=", + "requires": { + "bn.js": "^4.4.0", + "brorand": "^1.0.1", + "hash.js": "^1.0.0", + "inherits": "^2.0.1" + } + }, + "ethers": { + "version": "4.0.0-beta.1", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-4.0.0-beta.1.tgz", + "integrity": "sha512-SoYhktEbLxf+fiux5SfCEwdzWENMvgIbMZD90I62s4GZD9nEjgEWy8ZboI3hck193Vs0bDoTohDISx84f2H2tw==", + "requires": { + "@types/node": "^10.3.2", + "aes-js": "3.0.0", + "bn.js": "^4.4.0", + "elliptic": "6.3.3", + "hash.js": "1.1.3", + "js-sha3": "0.5.7", + "scrypt-js": "2.0.3", + "setimmediate": "1.0.4", + "uuid": "2.0.1", + "xmlhttprequest": "1.8.0" + } + }, + "hash.js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", + "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.0" + } + }, + "scrypt-js": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-2.0.3.tgz", + "integrity": "sha1-uwBAvgMEPamgEqLOqfyfhSz8h9Q=" + } } }, "web3-eth-accounts": { @@ -3420,11 +3617,6 @@ "elliptic": "^6.4.0", "xhr-request-promise": "^0.1.2" } - }, - "uuid": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.1.tgz", - "integrity": "sha1-wqMN7bPlNdcsz4LjQ5QaULqFM6w=" } } }, @@ -3522,7 +3714,7 @@ "requires": { "underscore": "1.8.3", "web3-core-helpers": "1.0.0-beta.37", - "websocket": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2" + "websocket": "git://github.com/frozeman/WebSocket-Node.git#browserifyCompatible" } }, "web3-shh": { diff --git a/package.json b/package.json index d5da5cdc..2c4b9c9b 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "get-all-submodules": "git submodule update --init --remote", "compile-posdao-contracts": "cd ./posdao-contracts && npm i && npm run compile", "make-spec": ". ./scripts/network-spec && cd ./posdao-contracts && npm i && node ./scripts/make_spec.js", - "start-test-setup": "bash scripts/start-test-setup ../parity-ethereum/target/debug/parity && node scripts/deploy-staking-token.js", + "start-test-setup": "bash scripts/start-test-setup ../parity-ethereum/target/debug/parity && node scripts/deploy-staking-token.js && (node scripts/isMining.js > ./parity-data/isMining.out 2> ./parity-data/isMining.err &) && (node scripts/watchBackedUpNode.js > ./parity-data/watchBackedUpNode.out 2> ./parity-data/watchBackedUpNode.err &)", "test": "node_modules/.bin/mocha --bail --timeout 600000 && npm run watcher", "stop-test-setup": "bash scripts/stop-test-setup", "watcher": "node scripts/watcher.js" @@ -24,6 +24,8 @@ "chai-as-promised": "^7.1.1", "chai-bn": "^0.1.1", "ethereumjs-tx": "^1.3.7", + "ethers": "^4.0.27", + "got": "^9.6.0", "keythereum": "^1.0.4", "mocha": "^6.1.4", "solc": "0.5.2", diff --git a/parity-data/node4/keys/DPoSChain/owner.json b/parity-data/node4/keys/DPoSChain/owner.json new file mode 100644 index 00000000..f02da352 --- /dev/null +++ b/parity-data/node4/keys/DPoSChain/owner.json @@ -0,0 +1 @@ +{"version":3,"id":"be60c5ac-6c4a-44c4-a12f-9558131ab64a","address":"32e4e4c7c5d1cea5db5f9202a9e4d99e56c91a24","Crypto":{"ciphertext":"68d1202b416408cb22ca60ba4f4deabcbddad7a262e014e1239dbe7354677ebb","cipherparams":{"iv":"a37afd65f955ab252340496defade99d"},"cipher":"aes-128-ctr","kdf":"scrypt","kdfparams":{"dklen":32,"salt":"47fdc45755f6f75072fb8c1a1eea9ec3a06450754eb78f0cc726baef22fed0bf","n":8192,"r":8,"p":1},"mac":"00def76f42948515e1f498b433860ef4a0fca7f9ce7a81eee0abc470f365ceb7"}} diff --git a/parity-data/node6/.keep b/parity-data/node6/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/parity-data/node6/keys/DPoSChain/address_book.json b/parity-data/node6/keys/DPoSChain/address_book.json deleted file mode 100644 index 9e26dfee..00000000 --- a/parity-data/node6/keys/DPoSChain/address_book.json +++ /dev/null @@ -1 +0,0 @@ -{} \ No newline at end of file diff --git a/parity-data/node6/keys/DPoSChain/validator3.json b/parity-data/node6/keys/DPoSChain/validator3.json deleted file mode 100644 index 92681b67..00000000 --- a/parity-data/node6/keys/DPoSChain/validator3.json +++ /dev/null @@ -1 +0,0 @@ -{"id":"35142060-03f5-78a0-fe4c-1d2545137da8","version":3,"crypto":{"cipher":"aes-128-ctr","cipherparams":{"iv":"beeb869ca61be05c3e746e60b5d1a5c1"},"ciphertext":"35ff91c26c89cbe35e4071cfc7c87c2ec10a8b2d6b2fa1e942c1cd4f49ee4b37","kdf":"pbkdf2","kdfparams":{"c":10240,"dklen":32,"prf":"hmac-sha256","salt":"0aa0176bf16d0d1340d20932faea5299c17b09f0f401e500545f92904d43301c"},"mac":"c4ce345c9f9eeac861bd2f8e6f41be14e221e4d374fee6d0625e682391af0d04"},"address":"522df396ae70a058bd69778408630fdb023389b2","name":"","meta":"{}"} \ No newline at end of file diff --git a/posdao-contracts b/posdao-contracts index 00cc4086..50d5b096 160000 --- a/posdao-contracts +++ b/posdao-contracts @@ -1 +1 @@ -Subproject commit 00cc4086ba3f2cfd533f25e4fd8098391b6a01b1 +Subproject commit 50d5b096d55f2c6078d4fc1054a5489d4a9c9e1b diff --git a/scripts/isMining.js b/scripts/isMining.js new file mode 100644 index 00000000..0251c7bc --- /dev/null +++ b/scripts/isMining.js @@ -0,0 +1,42 @@ +// This script provides a secure way to check remotely whether the node is mining/sealing blocks or +// not. It does this by redirecting requests to a locally open RPC port of Parity. That port can be +// closed for remote requests thus alleviating security concerns related to remote RPC calls. + +var assert = require("assert"); +const http = require("http"); +const ethers = require("ethers"); + +// Local Parity RPC port. +const RPC_PORT = "8541"; +// isMining server port open for remote connections. +const SERVER_PORT = "15116"; + +var provider = new ethers.providers.JsonRpcProvider(`http://localhost:${RPC_PORT}`); + +async function isMining() { + try { + let response = await provider.send("eth_mining", []); + assert(typeof response === "boolean"); + return response; + } catch (e) { + console.log("isMining ERROR:" + e); + return false; + } +} + +function requestHandler(request, response) { + response.writeHead(200, {"Content-Type": "text/plain"}); + isMining().then(b => { + if (b) { + response.end("true"); + } else { + response.end("false"); + } + }).catch(e => { + response.end("false"); + }); +} + +var server = http.createServer(requestHandler); +server.listen(SERVER_PORT); +console.log(`Listening on port ${SERVER_PORT} and serving on port ${SERVER_PORT}`); diff --git a/scripts/start-test-setup b/scripts/start-test-setup index 471c919a..4a8fcf02 100644 --- a/scripts/start-test-setup +++ b/scripts/start-test-setup @@ -6,7 +6,7 @@ set -u PARITY=$1 NODE=`which node` $NODE ./scripts/addCandidateBalances.js -for i in $(seq 1 9); do +for i in 1 2 3 4 7 8 9; do rm -rf -- "./parity-data/node$i/chains" "$PARITY" --config "./config/node${i}.toml" > "./parity-data/node${i}/log" 2>&1 & "$NODE" ./scripts/getReservedPeer.js "$i" diff --git a/scripts/stop-test-setup b/scripts/stop-test-setup index 9b955a6b..e5bf3403 100644 --- a/scripts/stop-test-setup +++ b/scripts/stop-test-setup @@ -1,16 +1,34 @@ #!/bin/bash function kill_at_port { - PID=`lsof -t -i:${1}` - if [ "$PID" != "" ]; then + PID=`lsof -t -i:${1}` + if [ "$PID" != "" ]; then echo Killing pid $PID at port $1 - kill -9 $PID + kill -9 $PID else echo Nothing to kill at port $1 - fi + fi +} + +function kill_at_file { + if [[ ! -a $1 ]]; then + echo "No such file: "$1 + return + fi + + PID=`lsof -t ${1}` + if [ "$PID" != "" ]; then + echo Killing pid $PID at file $1 + kill -9 $PID + else + echo Nothing to kill at file $1 + fi } # Kill test nodes. -for i in $(seq 1 9); do +for i in 1 2 3 4 7 8 9; do kill_at_port 854$i done + +kill_at_file "./parity-data/isMining.out" +kill_at_file "./parity-data/watchBackedUpNode.out" diff --git a/scripts/watchBackedUpNode.js b/scripts/watchBackedUpNode.js new file mode 100644 index 00000000..ba650055 --- /dev/null +++ b/scripts/watchBackedUpNode.js @@ -0,0 +1,115 @@ +// Validator node failover script +// +// The script should be run on the secondary (failover) node that backs up a primary node. The +// secondary node has signing disabled by default. It starts signing blocks when the primary node is +// a validator but has not produced a block when it was its turn and this script cannot connect to +// it by HTTP. The secondary node stops sigining blocks as soon as the HTTP connection to the +// primary node re-establishes. + +const assert = require("assert"); +const fs = require("fs"); +const findSignedBlock = require('../utils/findSignedBlock.js'); +const got = require("got"); +const { promisify } = require("util"); +const path = require("path"); +const readFile = promisify(fs.readFile); +const ethers = require("ethers"); + +const URL1 = "http://localhost:15116"; // remote address of the primary (replace in production) +const URL2 = "http://localhost:8544"; // local address of the secondary +const RETRY_TIMEOUT_SECONDS = 2; +const SCAN_INTERVAL_SECONDS = 5; +const PASSWORD_PATH = "/../config/password" +const SIGNER_ADDRESS = "0xbbcaa8d48289bb1ffcf9808d9aa4b1d215054c78"; + +var Web3 = require("web3"); +var web3 = new Web3(new Web3.providers.HttpProvider(URL2)); +var provider = new ethers.providers.JsonRpcProvider(URL2); +// `true` if the primary is required to sign and `false` if the secondary does. +var primaryHasToSign = true; +var validatorSetContract = require('../utils/getContract')('ValidatorSetAuRa', web3).instance; + +// Starts signing at the secondary node by setting the secondary signer address. +async function startSecondarySigning() { + console.log(`Reserve node starts signing`); + + let password = await readFile(path.join(__dirname, PASSWORD_PATH), "UTF-8"); + assert(typeof password === "string"); + await provider.send( + "parity_setEngineSigner", + [ SIGNER_ADDRESS, password.trim() ] + ); +} + +// Stops signing at the secondary node by setting the dummy signer address. +async function stopSecondarySigning() { + console.log(`Reserve node stops signing`); + await provider.send("parity_clearEngineSigner", []); +} + +async function startScan() { + var secondaryListening = false; + try { + secondaryListening = await web3.eth.net.isListening(); + } catch(e) { + console.log("Disconnected from secondary"); + } + assert(typeof secondaryListening === "boolean"); + if (secondaryListening) { + let validators = await validatorSetContract.methods.getValidators().call(); + validators = validators.map(v => v.toLowerCase()); + // Perform failover checks only if the primary is currently a validator. + if (validators.indexOf(SIGNER_ADDRESS.toLowerCase()) != -1) { + var primarySigning = false; + var connected = true; + try { + let response = await got(URL1, { json: false }); + if (response.body.trim() === "true") { + primarySigning = true; + } + } catch(e) { + console.log("Disconnected from primary"); + // For the start, assume that the primary is still mining even though the secondary + // cannot check that. + primarySigning = true; + connected = false; + } + if (!connected) { + // Ensure that we (the secondary mode) are still connected to the network by + // checking that other validators continued to sign blocks. + let signed = await findSignedBlock(web3, SIGNER_ADDRESS, validators.length); + if (!signed) { + // Since there is a gap in signed blocks, it follows that, if the primary is the + // current signer (primaryHasToSign == true), that it is has become disconnected + // from the rest of the network, while the secondary node (us) is still + // connected. + console.log(`Failed to find a block authored by ${SIGNER_ADDRESS}`); + primarySigning = false; + } + } + if (!primarySigning) { + if (primaryHasToSign) { + console.log("Primary has stopped signing; making the secondary sign"); + primaryHasToSign = false; + await startSecondarySigning(); + } + } else if (connected) { + if (!primaryHasToSign) { + console.log("Primary has come back up; moving the secondary to reserve"); + primaryHasToSign = true; + await stopSecondarySigning(); + } + } + } + setTimeout(startScan, SCAN_INTERVAL_SECONDS * 1000); + } else { + console.log(`Disconnected from secondary; retry in ${RETRY_TIMEOUT_SECONDS}s`); + setTimeout(startScan, RETRY_TIMEOUT_SECONDS * 1000); + } +} + +try { + startScan(); +} catch(e) { + console.log("startScan ERROR: " + e); +} diff --git a/test/3_failover.js b/test/3_failover.js new file mode 100644 index 00000000..3810d401 --- /dev/null +++ b/test/3_failover.js @@ -0,0 +1,149 @@ +const { promisify } = require("util"); +const exec = promisify(require('child_process').exec); +const spawn = require('child_process').spawn; +const fs = require("fs"); +const readFile = promisify(fs.readFile); +const ethers = require("ethers"); +const path = require("path"); +const Web3 = require('web3'); +const URL1 = "http://localhost:8541"; // primary address +const URL2 = "http://localhost:8544"; // secondary address +const web3 = new Web3(URL2); +const BN = web3.utils.BN; +const assert = require('chai').assert; +const expect = require('chai') + .use(require('chai-bn')(BN)) + .use(require('chai-as-promised')) + .expect; +const rpc1 = new ethers.providers.JsonRpcProvider(URL1); +const rpc2 = new ethers.providers.JsonRpcProvider(URL2); +const validatorSetContract = require('../utils/getContract')('ValidatorSetAuRa', web3).instance; + +const PASSWORD_PATH = "/../config/password" +const SIGNER_ADDRESS = '0xbbcaa8d48289bb1ffcf9808d9aa4b1d215054c78'; +const PARITY = '../parity-ethereum/target/debug/parity'; + +async function killPrimary() { + let cmd = 'kill -9 $(lsof -t -i:9541)'; + console.log('***** Killing primary node'); + var execOutput = await exec(cmd); + expect(execOutput.stderr, `Error when killing primary node: ${execOutput.stderr}`).to.be.empty; +} + +async function killIsMining() { + let cmd = 'kill -9 $(lsof -t ./parity-data/isMining.out)'; + console.log('***** Killing isMining.js'); + var execOutput = await exec(cmd); + expect(execOutput.stderr, `Error when killing isMining.js: ${execOutput.stderr}`).to.be.empty; +} + +function startPrimary(configToml) { + var out = fs.openSync('./parity-data/node1/log', 'a'); + console.log('***** Restarting primary node'); + spawn(PARITY, ['--config', configToml], { + detached: true, + stdio: ['ignore', out, out] + }).unref(); +} + +function startIsMining() { + var out = fs.openSync('./parity-data/isMining.out', 'a'); + var err = fs.openSync('./parity-data/isMining.err', 'a'); + console.log('***** Restarting isMining.js'); + spawn('node', ['./scripts/isMining.js'], { + detached: true, + stdio: ['ignore', out, err] + }).unref(); +} + +describe('Primary node is backed up by secondary node', () => { + it('Secondary node starts in reserve', async () => { + var signing2 = await rpc2.send('eth_mining', []); + expect(signing2, 'Secondary node should start in reserve').to.be.false; + }); + + it('isMining.js goes down, primary still signs, secondary stays in reserve', async () => { + killIsMining(); + var validators = await validatorSetContract.methods.getValidators().call(); + await new Promise(r => setTimeout(r, 2 * (validators.length + 1) * 5000)); + var signing1 = await rpc1.send('eth_mining', []); + expect(signing1, 'Primary node should stay being the signer').to.be.true; + var signing2 = await rpc2.send('eth_mining', []); + expect(signing2, 'Secondary node should stay in reserve').to.be.false; + }); + + it('isMining.js is down, primary node is down, secondary node signs', async () => { + killPrimary(); + var validators = await validatorSetContract.methods.getValidators().call(); + await new Promise(r => setTimeout(r, 2 * (validators.length + 1) * 5000)); + var signing2 = await rpc2.send('eth_mining', []); + expect(signing2, 'Secondary node should start signing').to.be.true; + }); + + it('isMining.js is up, primary node is up and starts to sign', async () => { + startIsMining(); + startPrimary('./config/node1.toml'); + var signing2 = true; + while (signing2) { + await new Promise(r => setTimeout(r, 999)); + signing2 = await rpc2.send('eth_mining', []); + assert.typeOf(signing2, 'boolean'); + } + console.log('***** Secondary node stopped signing OK'); + }); + + it('Primary node disconnects and reconnects with the engine signer not set', async () => { + await killPrimary(); + var signing2 = false; + // Wait until the secondary starts to sign. + while (!signing2) { + await new Promise(r => setTimeout(r, 999)); + signing2 = await rpc2.send('eth_mining', []); + assert.typeOf(signing2, 'boolean'); + }; + console.log('***** Secondary node is now signing instead of the primary node'); + startPrimary('./config/node1-no-signer.toml'); + var validators = await validatorSetContract.methods.getValidators().call(); + await new Promise(r => setTimeout(r, 2 * (validators.length + 1) * 5000)); + signing2 = await rpc2.send('eth_mining', []); + expect(signing2, 'Secondary node should stay being the signer').to.be.true; + }); + + // After the last test, Node 1 is still not signing. The following test returns Node 1 in the + // initial state where it is a signer. So in fact the starting state for this test is where the + // previous test left off. + it('Secondary stops signing as soon as the primary starts to sign', async () => { + let password = await readFile(path.join(__dirname, PASSWORD_PATH), "UTF-8"); + assert(typeof password === "string"); + await rpc1.send( + "parity_setEngineSigner", + [ SIGNER_ADDRESS, password.trim() ] + ); + var signing2 = true; + while (signing2) { + await new Promise(r => setTimeout(r, 999)); + signing2 = await rpc2.send('eth_mining', []); + assert.typeOf(signing2, 'boolean'); + }; + console.log('***** Secondary node stopped signing OK'); + }); + + it('Primary node disconnects and reconnects with the engine signer set', async () => { + await killPrimary(); + var signing2 = false; + // Wait until the secondary starts to sign. + while (!signing2) { + await new Promise(r => setTimeout(r, 999)); + signing2 = await rpc2.send('eth_mining', []); + assert.typeOf(signing2, 'boolean'); + }; + console.log('***** Secondary node is now signing instead of primary node'); + startPrimary('./config/node1.toml'); + while (signing2) { + await new Promise(r => setTimeout(r, 999)); + signing2 = await rpc2.send('eth_mining', []); + assert.typeOf(signing2, 'boolean'); + }; + console.log('***** Secondary node stopped signing OK'); + }); +}); diff --git a/utils/findSignedBlock.js b/utils/findSignedBlock.js new file mode 100644 index 00000000..8c17b65f --- /dev/null +++ b/utils/findSignedBlock.js @@ -0,0 +1,24 @@ +'use strict'; +const assert = require('assert'); + +module.exports = async function (web3, signer_address, depth) { + assert(typeof signer_address === "string"); + assert(typeof depth === "number"); + var lastBlock = await web3.eth.getBlock("latest"); + var lastBlockNum = lastBlock.number; + assert(typeof lastBlockNum === "number"); + if (lastBlockNum < depth) { + return true; + } + var startBlockNum = lastBlockNum - depth; + + console.log(`Scanning blocks from ${startBlockNum} to ${lastBlockNum}`); + + for (var i = startBlockNum; i <= lastBlockNum; i++) { + let block = await web3.eth.getBlock(i); + if (block.author.toLowerCase() === signer_address.toLowerCase()) { + return true; + } + } + return false; +}