diff --git a/apps/block_scout_web/assets/package-lock.json b/apps/block_scout_web/assets/package-lock.json index f531a1f5d5..becb999fbc 100644 --- a/apps/block_scout_web/assets/package-lock.json +++ b/apps/block_scout_web/assets/package-lock.json @@ -3807,27 +3807,27 @@ "dependencies": { "abbrev": { "version": "1.1.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "dev": true, "optional": true }, "ansi-regex": { "version": "2.1.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", "dev": true }, "aproba": { "version": "1.2.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", "dev": true, "optional": true }, "are-we-there-yet": { "version": "1.1.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz", "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", "dev": true, "optional": true, @@ -3838,13 +3838,13 @@ }, "balanced-match": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true }, "brace-expansion": { "version": "1.1.11", - "resolved": false, + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "requires": { @@ -3854,39 +3854,39 @@ }, "chownr": { "version": "1.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.0.1.tgz", "integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=", "dev": true, "optional": true }, "code-point-at": { "version": "1.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true }, "concat-map": { "version": "0.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, "console-control-strings": { "version": "1.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", "dev": true }, "core-util-is": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true, "optional": true }, "debug": { "version": "2.6.9", - "resolved": false, + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "optional": true, @@ -3896,28 +3896,28 @@ }, "deep-extend": { "version": "0.5.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.5.1.tgz", "integrity": "sha512-N8vBdOa+DF7zkRrDCsaOXoCs/E2fJfx9B9MrKnnSiHNh4ws7eSys6YQE4KvT1cecKmOASYQBhbKjeuDD9lT81w==", "dev": true, "optional": true }, "delegates": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", "dev": true, "optional": true }, "detect-libc": { "version": "1.0.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", "dev": true, "optional": true }, "fs-minipass": { "version": "1.2.5", - "resolved": false, + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz", "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==", "dev": true, "optional": true, @@ -3927,14 +3927,14 @@ }, "fs.realpath": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true, "optional": true }, "gauge": { "version": "2.7.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "dev": true, "optional": true, @@ -3951,7 +3951,7 @@ }, "glob": { "version": "7.1.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "dev": true, "optional": true, @@ -3966,14 +3966,14 @@ }, "has-unicode": { "version": "2.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", "dev": true, "optional": true }, "iconv-lite": { "version": "0.4.21", - "resolved": false, + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.21.tgz", "integrity": "sha512-En5V9za5mBt2oUA03WGD3TwDv0MKAruqsuxstbMUZaj9W9k/m1CV/9py3l0L5kw9Bln8fdHQmzHSYtvpvTLpKw==", "dev": true, "optional": true, @@ -3983,7 +3983,7 @@ }, "ignore-walk": { "version": "3.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz", "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", "dev": true, "optional": true, @@ -3993,7 +3993,7 @@ }, "inflight": { "version": "1.0.6", - "resolved": false, + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "optional": true, @@ -4004,20 +4004,20 @@ }, "inherits": { "version": "2.0.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "dev": true }, "ini": { "version": "1.3.5", - "resolved": false, + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", "dev": true, "optional": true }, "is-fullwidth-code-point": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, "requires": { @@ -4026,14 +4026,14 @@ }, "isarray": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true, "optional": true }, "minimatch": { "version": "3.0.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { @@ -4042,13 +4042,13 @@ }, "minimist": { "version": "0.0.8", - "resolved": false, + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "dev": true }, "minipass": { "version": "2.2.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.2.4.tgz", "integrity": "sha512-hzXIWWet/BzWhYs2b+u7dRHlruXhwdgvlTMDKC6Cb1U7ps6Ac6yQlR39xsbjWJE377YTCtKwIXIpJ5oP+j5y8g==", "dev": true, "requires": { @@ -4058,7 +4058,7 @@ }, "minizlib": { "version": "1.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.1.0.tgz", "integrity": "sha512-4T6Ur/GctZ27nHfpt9THOdRZNgyJ9FZchYO1ceg5S8Q3DNLCKYy44nCZzgCJgcvx2UM8czmqak5BCxJMrq37lA==", "dev": true, "optional": true, @@ -4068,7 +4068,7 @@ }, "mkdirp": { "version": "0.5.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, "requires": { @@ -4077,14 +4077,14 @@ }, "ms": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true, "optional": true }, "needle": { "version": "2.2.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/needle/-/needle-2.2.0.tgz", "integrity": "sha512-eFagy6c+TYayorXw/qtAdSvaUpEbBsDwDyxYFgLZ0lTojfH7K+OdBqAF7TAFwDokJaGpubpSGG0wO3iC0XPi8w==", "dev": true, "optional": true, @@ -4096,7 +4096,7 @@ }, "node-pre-gyp": { "version": "0.10.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.10.0.tgz", "integrity": "sha512-G7kEonQLRbcA/mOoFoxvlMrw6Q6dPf92+t/l0DFSMuSlDoWaI9JWIyPwK0jyE1bph//CUEL65/Fz1m2vJbmjQQ==", "dev": true, "optional": true, @@ -4115,7 +4115,7 @@ }, "nopt": { "version": "4.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", "dev": true, "optional": true, @@ -4126,14 +4126,14 @@ }, "npm-bundled": { "version": "1.0.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.3.tgz", "integrity": "sha512-ByQ3oJ/5ETLyglU2+8dBObvhfWXX8dtPZDMePCahptliFX2iIuhyEszyFk401PZUNQH20vvdW5MLjJxkwU80Ow==", "dev": true, "optional": true }, "npm-packlist": { "version": "1.1.10", - "resolved": false, + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.1.10.tgz", "integrity": "sha512-AQC0Dyhzn4EiYEfIUjCdMl0JJ61I2ER9ukf/sLxJUcZHfo+VyEfz2rMJgLZSS1v30OxPQe1cN0LZA1xbcaVfWA==", "dev": true, "optional": true, @@ -4144,7 +4144,7 @@ }, "npmlog": { "version": "4.1.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "dev": true, "optional": true, @@ -4157,20 +4157,20 @@ }, "number-is-nan": { "version": "1.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true }, "object-assign": { "version": "4.1.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "dev": true, "optional": true }, "once": { "version": "1.4.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "requires": { @@ -4179,21 +4179,21 @@ }, "os-homedir": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", "dev": true, "optional": true }, "os-tmpdir": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true, "optional": true }, "osenv": { "version": "0.1.5", - "resolved": false, + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", "dev": true, "optional": true, @@ -4204,21 +4204,21 @@ }, "path-is-absolute": { "version": "1.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true, "optional": true }, "process-nextick-args": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", "dev": true, "optional": true }, "rc": { "version": "1.2.7", - "resolved": false, + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.7.tgz", "integrity": "sha512-LdLD8xD4zzLsAT5xyushXDNscEjB7+2ulnl8+r1pnESlYtlJtVSoCMBGr30eDRJ3+2Gq89jK9P9e4tCEH1+ywA==", "dev": true, "optional": true, @@ -4231,7 +4231,7 @@ "dependencies": { "minimist": { "version": "1.2.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true, "optional": true @@ -4240,7 +4240,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": false, + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "optional": true, @@ -4256,7 +4256,7 @@ }, "rimraf": { "version": "2.6.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", "dev": true, "optional": true, @@ -4266,48 +4266,48 @@ }, "safe-buffer": { "version": "5.1.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", "dev": true }, "safer-buffer": { "version": "2.1.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true, "optional": true }, "sax": { "version": "1.2.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "dev": true, "optional": true }, "semver": { "version": "5.5.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", "dev": true, "optional": true }, "set-blocking": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true, "optional": true }, "signal-exit": { "version": "3.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true, "optional": true }, "string-width": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "requires": { @@ -4318,7 +4318,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "optional": true, @@ -4328,7 +4328,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { @@ -4337,14 +4337,14 @@ }, "strip-json-comments": { "version": "2.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "dev": true, "optional": true }, "tar": { "version": "4.4.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.1.tgz", "integrity": "sha512-O+v1r9yN4tOsvl90p5HAP4AEqbYhx4036AGMm075fH9F8Qwi3oJ+v4u50FkT/KkvywNGtwkk0zRI+8eYm1X/xg==", "dev": true, "optional": true, @@ -4360,14 +4360,14 @@ }, "util-deprecate": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true, "optional": true }, "wide-align": { "version": "1.1.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz", "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==", "dev": true, "optional": true, @@ -4377,13 +4377,13 @@ }, "wrappy": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, "yallist": { "version": "3.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.2.tgz", "integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=", "dev": true } diff --git a/apps/block_scout_web/lib/block_scout_web/chain.ex b/apps/block_scout_web/lib/block_scout_web/chain.ex index c132d72307..0e7f5eeb38 100644 --- a/apps/block_scout_web/lib/block_scout_web/chain.ex +++ b/apps/block_scout_web/lib/block_scout_web/chain.ex @@ -183,10 +183,7 @@ defmodule BlockScoutWeb.Chain do end defp paging_params(%Address.Token{name: name, type: type, inserted_at: inserted_at}) do - inserted_at_datetime = - inserted_at - |> DateTime.from_naive!("Etc/UTC") - |> DateTime.to_iso8601() + inserted_at_datetime = DateTime.to_iso8601(inserted_at) %{"token_name" => name, "token_type" => type, "token_inserted_at" => inserted_at_datetime} end diff --git a/apps/block_scout_web/mix.exs b/apps/block_scout_web/mix.exs index 5516c589f1..ff15339505 100644 --- a/apps/block_scout_web/mix.exs +++ b/apps/block_scout_web/mix.exs @@ -74,6 +74,9 @@ defmodule BlockScoutWeb.Mixfile do # For Absinthe to load data in batches {:dataloader, "~> 1.0.0"}, {:dialyxir, "~> 0.5", only: [:dev, :test], runtime: false}, + # Need until https://github.com/absinthe-graphql/absinthe_relay/pull/125 is released, then can be removed + # The current `absinthe_relay` is compatible though as shown from that PR + {:ecto, "~> 3.0", override: true}, {:ex_cldr_numbers, "~> 1.0"}, {:ex_cldr_units, "~> 1.0"}, {:ex_machina, "~> 2.1", only: [:test]}, diff --git a/apps/block_scout_web/test/block_scout_web/channels/address_channel_test.exs b/apps/block_scout_web/test/block_scout_web/channels/address_channel_test.exs index 1ab7489231..2e59c8435c 100644 --- a/apps/block_scout_web/test/block_scout_web/channels/address_channel_test.exs +++ b/apps/block_scout_web/test/block_scout_web/channels/address_channel_test.exs @@ -1,7 +1,10 @@ defmodule BlockScoutWeb.AddressChannelTest do - use BlockScoutWeb.ChannelCase + use BlockScoutWeb.ChannelCase, + # ETS tables are shared in `Explorer.Counters.AddressesWithBalanceCounter` + async: false alias BlockScoutWeb.Notifier + alias Explorer.Counters.AddressesWithBalanceCounter test "subscribed user is notified of new_address count event" do topic = "addresses:new_address" @@ -9,6 +12,9 @@ defmodule BlockScoutWeb.AddressChannelTest do address = insert(:address) + start_supervised!(AddressesWithBalanceCounter) + AddressesWithBalanceCounter.consolidate() + Notifier.handle_event({:chain_event, :addresses, :realtime, [address]}) assert_receive %Phoenix.Socket.Broadcast{topic: ^topic, event: "count", payload: %{count: _}}, 5_000 @@ -24,6 +30,10 @@ defmodule BlockScoutWeb.AddressChannelTest do test "notified of balance_update for matching address", %{address: address, topic: topic} do address_with_balance = %{address | fetched_coin_balance: 1} + + start_supervised!(AddressesWithBalanceCounter) + AddressesWithBalanceCounter.consolidate() + Notifier.handle_event({:chain_event, :addresses, :realtime, [address_with_balance]}) assert_receive %Phoenix.Socket.Broadcast{topic: ^topic, event: "balance_update", payload: payload}, 5_000 @@ -31,6 +41,9 @@ defmodule BlockScoutWeb.AddressChannelTest do end test "not notified of balance_update if fetched_coin_balance is nil", %{address: address} do + start_supervised!(AddressesWithBalanceCounter) + AddressesWithBalanceCounter.consolidate() + Notifier.handle_event({:chain_event, :addresses, :realtime, [address]}) refute_receive _, 100, "Message was broadcast for nil fetched_coin_balance." diff --git a/apps/block_scout_web/test/block_scout_web/controllers/address_contract_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/address_contract_controller_test.exs index 2bd2171b02..eed61473b9 100644 --- a/apps/block_scout_web/test/block_scout_web/controllers/address_contract_controller_test.exs +++ b/apps/block_scout_web/test/block_scout_web/controllers/address_contract_controller_test.exs @@ -1,9 +1,12 @@ defmodule BlockScoutWeb.AddressContractControllerTest do - use BlockScoutWeb.ConnCase + use BlockScoutWeb.ConnCase, + # ETS table is shared in `Explorer.Counters.BlockValidationCounter` + async: false import BlockScoutWeb.Router.Helpers, only: [address_contract_path: 3] alias Explorer.Chain.Hash + alias Explorer.Counters.BlockValidationCounter alias Explorer.ExchangeRates.Token alias Explorer.Factory @@ -44,6 +47,8 @@ defmodule BlockScoutWeb.AddressContractControllerTest do created_contract_address: address ) + start_supervised!(BlockValidationCounter) + conn = get(conn, address_contract_path(BlockScoutWeb.Endpoint, :index, address)) assert html_response(conn, 200) diff --git a/apps/block_scout_web/test/block_scout_web/controllers/address_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/address_controller_test.exs index 7734ef05aa..5a002fcde6 100644 --- a/apps/block_scout_web/test/block_scout_web/controllers/address_controller_test.exs +++ b/apps/block_scout_web/test/block_scout_web/controllers/address_controller_test.exs @@ -1,5 +1,9 @@ defmodule BlockScoutWeb.AddressControllerTest do - use BlockScoutWeb.ConnCase + use BlockScoutWeb.ConnCase, + # ETS tables are shared in `Explorer.Counters.*` + async: false + + alias Explorer.Counters.{AddressesWithBalanceCounter, BlockValidationCounter} describe "GET index/2" do test "returns top addresses", %{conn: conn} do @@ -8,6 +12,11 @@ defmodule BlockScoutWeb.AddressControllerTest do |> Enum.map(&insert(:address, fetched_coin_balance: &1)) |> Enum.map(& &1.hash) + start_supervised!(AddressesWithBalanceCounter) + AddressesWithBalanceCounter.consolidate() + + start_supervised!(BlockValidationCounter) + conn = get(conn, address_path(conn, :index)) assert conn.assigns.address_tx_count_pairs @@ -19,6 +28,11 @@ defmodule BlockScoutWeb.AddressControllerTest do address = insert(:address, fetched_coin_balance: 1) address_name = insert(:address_name, address: address, primary: true, name: "POA Wallet") + start_supervised!(AddressesWithBalanceCounter) + AddressesWithBalanceCounter.consolidate() + + start_supervised!(BlockValidationCounter) + conn = get(conn, address_path(conn, :index)) assert html_response(conn, 200) =~ address_name.name diff --git a/apps/block_scout_web/test/block_scout_web/controllers/address_internal_transaction_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/address_internal_transaction_controller_test.exs index dd30205fd4..75d84d966a 100644 --- a/apps/block_scout_web/test/block_scout_web/controllers/address_internal_transaction_controller_test.exs +++ b/apps/block_scout_web/test/block_scout_web/controllers/address_internal_transaction_controller_test.exs @@ -1,10 +1,13 @@ defmodule BlockScoutWeb.AddressInternalTransactionControllerTest do - use BlockScoutWeb.ConnCase + use BlockScoutWeb.ConnCase, + # ETS table is shared in `Explorer.Counters.BlockValidationCounter` + async: false import BlockScoutWeb.Router.Helpers, only: [address_internal_transaction_path: 3, address_internal_transaction_path: 4] alias Explorer.Chain.{Block, InternalTransaction, Transaction} + alias Explorer.Counters.BlockValidationCounter alias Explorer.ExchangeRates.Token describe "GET index/3" do @@ -25,6 +28,8 @@ defmodule BlockScoutWeb.AddressInternalTransactionControllerTest do test "includes USD exchange rate value for address in assigns", %{conn: conn} do address = insert(:address) + start_supervised!(BlockValidationCounter) + conn = get(conn, address_internal_transaction_path(BlockScoutWeb.Endpoint, :index, address.hash)) assert %Token{} = conn.assigns.exchange_rate diff --git a/apps/block_scout_web/test/block_scout_web/controllers/address_read_contract_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/address_read_contract_controller_test.exs index 8008c79d3a..f65d8a4d32 100644 --- a/apps/block_scout_web/test/block_scout_web/controllers/address_read_contract_controller_test.exs +++ b/apps/block_scout_web/test/block_scout_web/controllers/address_read_contract_controller_test.exs @@ -1,6 +1,9 @@ defmodule BlockScoutWeb.AddressReadContractControllerTest do - use BlockScoutWeb.ConnCase + use BlockScoutWeb.ConnCase, + # ETS table is shared in `Explorer.Counters.BlockValidationCounter` + async: false + alias Explorer.Counters.BlockValidationCounter alias Explorer.ExchangeRates.Token describe "GET index/3" do @@ -23,6 +26,9 @@ defmodule BlockScoutWeb.AddressReadContractControllerTest do transaction = insert(:transaction, from_address: contract_address) + start_supervised!(BlockValidationCounter) + BlockValidationCounter.consolidate_blocks() + insert( :internal_transaction_create, index: 0, diff --git a/apps/block_scout_web/test/block_scout_web/controllers/address_token_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/address_token_controller_test.exs index ff4211ba3f..20e386f530 100644 --- a/apps/block_scout_web/test/block_scout_web/controllers/address_token_controller_test.exs +++ b/apps/block_scout_web/test/block_scout_web/controllers/address_token_controller_test.exs @@ -1,9 +1,12 @@ defmodule BlockScoutWeb.AddressTokenControllerTest do - use BlockScoutWeb.ConnCase + use BlockScoutWeb.ConnCase, + # ETS table is shared in `Explorer.Counters.BlockValidationCounter` + async: false import BlockScoutWeb.Router.Helpers, only: [address_token_path: 3] alias Explorer.Chain.{Token} + alias Explorer.Counters.BlockValidationCounter describe "GET index/2" do test "with invalid address hash", %{conn: conn} do @@ -57,6 +60,8 @@ defmodule BlockScoutWeb.AddressTokenControllerTest do to_address: address ) + start_supervised!(BlockValidationCounter) + conn = get(conn, address_token_path(conn, :index, address)) actual_token_hashes = @@ -100,6 +105,8 @@ defmodule BlockScoutWeb.AddressTokenControllerTest do insert(:token_transfer, token: token, from_address: address) %Token{name: name, type: type} = token + start_supervised!(BlockValidationCounter) + conn = get(conn, address_token_path(BlockScoutWeb.Endpoint, :index, address.hash), %{ "name" => name, @@ -130,6 +137,8 @@ defmodule BlockScoutWeb.AddressTokenControllerTest do insert(:token_transfer, token_contract_address: token.contract_address, from_address: address) end) + start_supervised!(BlockValidationCounter) + conn = get(conn, address_token_path(BlockScoutWeb.Endpoint, :index, address.hash)) assert conn.assigns.next_page_params @@ -140,6 +149,8 @@ defmodule BlockScoutWeb.AddressTokenControllerTest do token = insert(:token) insert(:token_transfer, token_contract_address: token.contract_address, from_address: address) + start_supervised!(BlockValidationCounter) + conn = get(conn, address_token_path(BlockScoutWeb.Endpoint, :index, address.hash)) refute conn.assigns.next_page_params diff --git a/apps/block_scout_web/test/block_scout_web/controllers/address_transaction_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/address_transaction_controller_test.exs index 2d5b72f154..d21495b0eb 100644 --- a/apps/block_scout_web/test/block_scout_web/controllers/address_transaction_controller_test.exs +++ b/apps/block_scout_web/test/block_scout_web/controllers/address_transaction_controller_test.exs @@ -1,9 +1,12 @@ defmodule BlockScoutWeb.AddressTransactionControllerTest do - use BlockScoutWeb.ConnCase + use BlockScoutWeb.ConnCase, + # ETS table is shared in `Explorer.Counters.BlockValidationCounter` + async: false import BlockScoutWeb.Router.Helpers, only: [address_transaction_path: 3, address_transaction_path: 4] - alias Explorer.Chain.{Block, Transaction} + alias Explorer.Chain.Transaction + alias Explorer.Counters.BlockValidationCounter alias Explorer.ExchangeRates.Token describe "GET index/2" do @@ -47,6 +50,8 @@ defmodule BlockScoutWeb.AddressTransactionControllerTest do test "includes USD exchange rate value for address in assigns", %{conn: conn} do address = insert(:address) + start_supervised!(BlockValidationCounter) + conn = get(conn, address_transaction_path(BlockScoutWeb.Endpoint, :index, address.hash)) assert %Token{} = conn.assigns.exchange_rate @@ -82,7 +87,7 @@ defmodule BlockScoutWeb.AddressTransactionControllerTest do test "next_page_params exist if not on last page", %{conn: conn} do address = insert(:address) - block = %Block{number: number} = insert(:block) + block = insert(:block) 60 |> insert_list(:transaction, from_address: address) diff --git a/apps/block_scout_web/test/block_scout_web/controllers/chain_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/chain_controller_test.exs index 8582ea2c80..1a71add242 100644 --- a/apps/block_scout_web/test/block_scout_web/controllers/chain_controller_test.exs +++ b/apps/block_scout_web/test/block_scout_web/controllers/chain_controller_test.exs @@ -1,12 +1,18 @@ defmodule BlockScoutWeb.ChainControllerTest do - use BlockScoutWeb.ConnCase + use BlockScoutWeb.ConnCase, + # ETS table is shared in `Explorer.Counters.AddressesWithBalanceCounter` + async: false import BlockScoutWeb.Router.Helpers, only: [chain_path: 2, block_path: 3, transaction_path: 3, address_path: 3] alias Explorer.Chain.Block + alias Explorer.Counters.AddressesWithBalanceCounter describe "GET index/2" do test "returns a welcome message", %{conn: conn} do + start_supervised!(AddressesWithBalanceCounter) + AddressesWithBalanceCounter.consolidate() + conn = get(conn, chain_path(BlockScoutWeb.Endpoint, :show)) assert(html_response(conn, 200) =~ "POA") @@ -14,6 +20,10 @@ defmodule BlockScoutWeb.ChainControllerTest do test "returns a block", %{conn: conn} do insert(:block, %{number: 23}) + + start_supervised!(AddressesWithBalanceCounter) + AddressesWithBalanceCounter.consolidate() + conn = get(conn, "/") assert(List.first(conn.assigns.blocks).number == 23) @@ -22,6 +32,10 @@ defmodule BlockScoutWeb.ChainControllerTest do test "excludes all but the most recent five blocks", %{conn: conn} do old_block = insert(:block) insert_list(5, :block) + + start_supervised!(AddressesWithBalanceCounter) + AddressesWithBalanceCounter.consolidate() + conn = get(conn, "/") refute(Enum.member?(conn.assigns.blocks, old_block)) @@ -35,6 +49,9 @@ defmodule BlockScoutWeb.ChainControllerTest do unassociated = insert(:transaction) + start_supervised!(AddressesWithBalanceCounter) + AddressesWithBalanceCounter.consolidate() + conn = get(conn, "/") transaction_hashes = Enum.map(conn.assigns.transactions, fn transaction -> transaction.hash end) @@ -49,6 +66,9 @@ defmodule BlockScoutWeb.ChainControllerTest do |> insert() |> with_block() + start_supervised!(AddressesWithBalanceCounter) + AddressesWithBalanceCounter.consolidate() + conn = get(conn, "/") assert(List.first(conn.assigns.transactions).hash == transaction.hash) @@ -58,6 +78,9 @@ defmodule BlockScoutWeb.ChainControllerTest do today = Date.utc_today() for day <- -40..0, do: insert(:market_history, date: Date.add(today, day)) + start_supervised!(AddressesWithBalanceCounter) + AddressesWithBalanceCounter.consolidate() + conn = get(conn, "/") assert Map.has_key?(conn.assigns, :market_history_data) @@ -70,6 +93,9 @@ defmodule BlockScoutWeb.ChainControllerTest do insert(:block, miner: miner_address, miner_hash: nil) + start_supervised!(AddressesWithBalanceCounter) + AddressesWithBalanceCounter.consolidate() + conn = get(conn, chain_path(conn, :show)) assert html_response(conn, 200) =~ miner_name end diff --git a/apps/block_scout_web/test/block_scout_web/controllers/pending_transaction_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/pending_transaction_controller_test.exs index 3fd4701481..4fa4ad79d1 100644 --- a/apps/block_scout_web/test/block_scout_web/controllers/pending_transaction_controller_test.exs +++ b/apps/block_scout_web/test/block_scout_web/controllers/pending_transaction_controller_test.exs @@ -59,12 +59,9 @@ defmodule BlockScoutWeb.PendingTransactionControllerTest do end test "next_page_path exist if not on last page", %{conn: conn} do - %Transaction{inserted_at: inserted_at, hash: hash} = - 60 - |> insert_list(:transaction) - |> Enum.fetch!(10) - - converted_date = DateTime.to_iso8601(inserted_at) + 60 + |> insert_list(:transaction) + |> Enum.fetch!(10) conn = get(conn, pending_transaction_path(BlockScoutWeb.Endpoint, :index, %{"type" => "JSON"})) diff --git a/apps/block_scout_web/test/block_scout_web/controllers/tokens/holder_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/tokens/holder_controller_test.exs index 95e9242a1b..17b327814a 100644 --- a/apps/block_scout_web/test/block_scout_web/controllers/tokens/holder_controller_test.exs +++ b/apps/block_scout_web/test/block_scout_web/controllers/tokens/holder_controller_test.exs @@ -1,7 +1,10 @@ defmodule BlockScoutWeb.Tokens.HolderControllerTest do - use BlockScoutWeb.ConnCase + use BlockScoutWeb.ConnCase, + # ETS table is shared in `Explorer.Counters.TokenHoldersCounter` + async: false alias Explorer.Chain.Hash + alias Explorer.Counters.{TokenHoldersCounter, TokenTransferCounter} describe "GET index/3" do test "with invalid address hash", %{conn: conn} do @@ -26,6 +29,12 @@ defmodule BlockScoutWeb.Tokens.HolderControllerTest do token_contract_address_hash: token.contract_address_hash ) + start_supervised!(TokenHoldersCounter) + TokenHoldersCounter.consolidate() + + start_supervised!(TokenTransferCounter) + TokenTransferCounter.consolidate() + conn = get( conn, diff --git a/apps/block_scout_web/test/block_scout_web/controllers/tokens/inventory_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/tokens/inventory_controller_test.exs index 7ce68af4d1..91e84fdf29 100644 --- a/apps/block_scout_web/test/block_scout_web/controllers/tokens/inventory_controller_test.exs +++ b/apps/block_scout_web/test/block_scout_web/controllers/tokens/inventory_controller_test.exs @@ -1,5 +1,9 @@ defmodule BlockScoutWeb.Tokens.InventoryControllerTest do - use BlockScoutWeb.ConnCase + use BlockScoutWeb.ConnCase, + # ETS table is shared in `Explorer.Counters.*` + async: false + + alias Explorer.Counters.{TokenHoldersCounter, TokenTransferCounter} describe "GET index/3" do test "with invalid address hash", %{conn: conn} do @@ -31,6 +35,12 @@ defmodule BlockScoutWeb.Tokens.InventoryControllerTest do token: token ) + start_supervised!(TokenHoldersCounter) + TokenHoldersCounter.consolidate() + + start_supervised!(TokenTransferCounter) + TokenTransferCounter.consolidate() + conn = get( conn, @@ -60,6 +70,12 @@ defmodule BlockScoutWeb.Tokens.InventoryControllerTest do ) ) + start_supervised!(TokenHoldersCounter) + TokenHoldersCounter.consolidate() + + start_supervised!(TokenTransferCounter) + TokenTransferCounter.consolidate() + conn = get(conn, token_inventory_path(conn, :index, token.contract_address_hash), %{ "token_id" => "999" @@ -92,6 +108,12 @@ defmodule BlockScoutWeb.Tokens.InventoryControllerTest do "unique_token" => 1050 } + start_supervised!(TokenHoldersCounter) + TokenHoldersCounter.consolidate() + + start_supervised!(TokenTransferCounter) + TokenTransferCounter.consolidate() + conn = get(conn, token_inventory_path(conn, :index, token.contract_address_hash)) assert conn.assigns.next_page_params == expected_next_page_params @@ -113,6 +135,12 @@ defmodule BlockScoutWeb.Tokens.InventoryControllerTest do token_id: 1000 ) + start_supervised!(TokenHoldersCounter) + TokenHoldersCounter.consolidate() + + start_supervised!(TokenTransferCounter) + TokenTransferCounter.consolidate() + conn = get(conn, token_inventory_path(conn, :index, token.contract_address_hash)) refute conn.assigns.next_page_params diff --git a/apps/block_scout_web/test/block_scout_web/controllers/tokens/read_contract_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/tokens/read_contract_controller_test.exs index 5b72d3b92f..02eaa091a3 100644 --- a/apps/block_scout_web/test/block_scout_web/controllers/tokens/read_contract_controller_test.exs +++ b/apps/block_scout_web/test/block_scout_web/controllers/tokens/read_contract_controller_test.exs @@ -1,5 +1,9 @@ defmodule BlockScoutWeb.Tokens.ReadContractControllerTest do - use BlockScoutWeb.ConnCase + use BlockScoutWeb.ConnCase, + # ETS tables are shared in `Explorer.Counters.*` + async: false + + alias Explorer.Counters.{TokenHoldersCounter, TokenTransferCounter} describe "GET index/3" do test "with invalid address hash", %{conn: conn} do @@ -26,6 +30,12 @@ defmodule BlockScoutWeb.Tokens.ReadContractControllerTest do token: token ) + start_supervised!(TokenHoldersCounter) + TokenHoldersCounter.consolidate() + + start_supervised!(TokenTransferCounter) + TokenTransferCounter.consolidate() + conn = get(conn, token_read_contract_path(BlockScoutWeb.Endpoint, :index, token.contract_address_hash)) assert html_response(conn, 200) diff --git a/apps/block_scout_web/test/block_scout_web/controllers/transaction_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/transaction_controller_test.exs index 1e62745824..cd2e557f93 100644 --- a/apps/block_scout_web/test/block_scout_web/controllers/transaction_controller_test.exs +++ b/apps/block_scout_web/test/block_scout_web/controllers/transaction_controller_test.exs @@ -1,10 +1,11 @@ defmodule BlockScoutWeb.TransactionControllerTest do use BlockScoutWeb.ConnCase - alias Explorer.Chain.{Block, Transaction} import BlockScoutWeb.Router.Helpers, only: [transaction_path: 3, transaction_internal_transaction_path: 3, transaction_token_transfer_path: 3] + alias Explorer.Chain.Transaction + describe "GET index/2" do test "returns a collated transactions", %{conn: conn} do :transaction diff --git a/apps/block_scout_web/test/block_scout_web/features/address_contract_verification_test.exs b/apps/block_scout_web/test/block_scout_web/features/address_contract_verification_test.exs index b1b60ebd96..6704f76486 100644 --- a/apps/block_scout_web/test/block_scout_web/features/address_contract_verification_test.exs +++ b/apps/block_scout_web/test/block_scout_web/features/address_contract_verification_test.exs @@ -1,9 +1,10 @@ defmodule BlockScoutWeb.AddressContractVerificationTest do use BlockScoutWeb.FeatureCase, async: true - alias Plug.Conn - alias Explorer.Factory alias BlockScoutWeb.{AddressContractPage, ContractVerifyPage} + alias Explorer.Counters.BlockValidationCounter + alias Explorer.Factory + alias Plug.Conn setup do bypass = Bypass.open() @@ -29,6 +30,9 @@ defmodule BlockScoutWeb.AddressContractVerificationTest do transaction: transaction ) + start_supervised!(BlockValidationCounter) + BlockValidationCounter.consolidate_blocks() + session |> AddressContractPage.visit_page(address) |> AddressContractPage.click_verify_and_publish() diff --git a/apps/block_scout_web/test/block_scout_web/features/viewing_addresses_test.exs b/apps/block_scout_web/test/block_scout_web/features/viewing_addresses_test.exs index 4c76366c1b..32c01e0af1 100644 --- a/apps/block_scout_web/test/block_scout_web/features/viewing_addresses_test.exs +++ b/apps/block_scout_web/test/block_scout_web/features/viewing_addresses_test.exs @@ -1,6 +1,9 @@ defmodule BlockScoutWeb.ViewingAddressesTest do - use BlockScoutWeb.FeatureCase, async: true + use BlockScoutWeb.FeatureCase, + # Because ETS tables is shared for `Explorer.Counters.*` + async: false + alias Explorer.Counters.{AddressesWithBalanceCounter, BlockValidationCounter} alias BlockScoutWeb.{AddressPage, AddressView, Notifier} setup do @@ -38,6 +41,12 @@ defmodule BlockScoutWeb.ViewingAddressesTest do [first_address | _] = addresses [last_address | _] = Enum.reverse(addresses) + start_supervised!(BlockValidationCounter) + BlockValidationCounter.consolidate_blocks() + + start_supervised!(AddressesWithBalanceCounter) + AddressesWithBalanceCounter.consolidate() + session |> AddressPage.visit_page() |> assert_has(AddressPage.address(first_address)) @@ -48,6 +57,9 @@ defmodule BlockScoutWeb.ViewingAddressesTest do test "viewing address overview information", %{session: session} do address = insert(:address, fetched_coin_balance: 500) + start_supervised!(BlockValidationCounter) + BlockValidationCounter.consolidate_blocks() + session |> AddressPage.visit_page(address) |> assert_text(AddressPage.balance(), "0.0000000000000005 POA") @@ -68,6 +80,9 @@ defmodule BlockScoutWeb.ViewingAddressesTest do created_contract_address: contract ) + start_supervised!(BlockValidationCounter) + BlockValidationCounter.consolidate_blocks() + address_hash = AddressView.trimmed_hash(address.hash) transaction_hash = AddressView.trimmed_hash(transaction.hash) @@ -101,6 +116,9 @@ defmodule BlockScoutWeb.ViewingAddressesTest do created_contract_address: another_contract ) + start_supervised!(BlockValidationCounter) + BlockValidationCounter.consolidate_blocks() + contract_hash = AddressView.trimmed_hash(contract.hash) transaction_hash = AddressView.trimmed_hash(transaction.hash) @@ -111,6 +129,13 @@ defmodule BlockScoutWeb.ViewingAddressesTest do end describe "viewing transactions" do + setup do + start_supervised!(BlockValidationCounter) + BlockValidationCounter.consolidate_blocks() + + :ok + end + test "sees all addresses transactions by default", %{ addresses: addresses, session: session, @@ -189,6 +214,9 @@ defmodule BlockScoutWeb.ViewingAddressesTest do internal_transaction_lincoln_to_address: internal_transaction, session: session } do + start_supervised!(BlockValidationCounter) + BlockValidationCounter.consolidate_blocks() + session |> AddressPage.visit_page(addresses.lincoln) |> AddressPage.click_internal_transactions() @@ -202,6 +230,9 @@ defmodule BlockScoutWeb.ViewingAddressesTest do |> insert(from_address: addresses.lincoln) |> with_block(insert(:block, number: 7000)) + start_supervised!(BlockValidationCounter) + BlockValidationCounter.consolidate_blocks() + session |> AddressPage.visit_page(addresses.lincoln) |> AddressPage.click_internal_transactions() @@ -249,6 +280,9 @@ defmodule BlockScoutWeb.ViewingAddressesTest do token_contract_address: contract_address ) + start_supervised!(BlockValidationCounter) + BlockValidationCounter.consolidate_blocks() + session |> AddressPage.visit_page(lincoln) |> assert_has(AddressPage.token_transfers(transaction, count: 1)) @@ -290,6 +324,9 @@ defmodule BlockScoutWeb.ViewingAddressesTest do token_contract_address: contract_address ) + start_supervised!(BlockValidationCounter) + BlockValidationCounter.consolidate_blocks() + session |> AddressPage.visit_page(morty) |> assert_has(AddressPage.token_transfers(transaction, count: 1)) @@ -324,6 +361,9 @@ defmodule BlockScoutWeb.ViewingAddressesTest do token_contract_address: contract_address ) + start_supervised!(BlockValidationCounter) + BlockValidationCounter.consolidate_blocks() + session |> AddressPage.visit_page(lincoln) |> assert_has(AddressPage.token_transfers(transaction, count: 1)) @@ -354,6 +394,9 @@ defmodule BlockScoutWeb.ViewingAddressesTest do token_contract_address: contract_address ) + start_supervised!(BlockValidationCounter) + BlockValidationCounter.consolidate_blocks() + session |> AddressPage.visit_page(lincoln) |> click(AddressPage.token_transfers_expansion(transaction)) @@ -388,6 +431,9 @@ defmodule BlockScoutWeb.ViewingAddressesTest do insert(:token_balance, address: lincoln, token_contract_address_hash: contract_address.hash) + start_supervised!(BlockValidationCounter) + BlockValidationCounter.consolidate_blocks() + session |> AddressPage.visit_page(lincoln) |> AddressPage.click_tokens() @@ -441,6 +487,9 @@ defmodule BlockScoutWeb.ViewingAddressesTest do insert(:address_current_token_balance, address: lincoln, token_contract_address_hash: contract_address_2.hash) + start_supervised!(BlockValidationCounter) + BlockValidationCounter.consolidate_blocks() + {:ok, lincoln: lincoln} end @@ -486,6 +535,9 @@ defmodule BlockScoutWeb.ViewingAddressesTest do insert(:fetched_balance, address_hash: address.hash, value: 5, block_number: block.number) insert(:fetched_balance, address_hash: address.hash, value: 10, block_number: block_one_day_ago.number) + start_supervised!(BlockValidationCounter) + BlockValidationCounter.consolidate_blocks() + {:ok, address: address} end diff --git a/apps/block_scout_web/test/block_scout_web/features/viewing_app_test.exs b/apps/block_scout_web/test/block_scout_web/features/viewing_app_test.exs index 960de0049b..31a4564811 100644 --- a/apps/block_scout_web/test/block_scout_web/features/viewing_app_test.exs +++ b/apps/block_scout_web/test/block_scout_web/features/viewing_app_test.exs @@ -4,6 +4,7 @@ defmodule BlockScoutWeb.ViewingAppTest do use BlockScoutWeb.FeatureCase, async: true alias BlockScoutWeb.{AppPage, Notifier} + alias Explorer.Counters.AddressesWithBalanceCounter describe "loading bar when indexing" do test "shows blocks indexed percentage", %{session: session} do @@ -11,6 +12,9 @@ defmodule BlockScoutWeb.ViewingAppTest do insert(:block, number: index) end + start_supervised!(AddressesWithBalanceCounter) + AddressesWithBalanceCounter.consolidate() + assert Explorer.Chain.indexed_ratio() == 0.5 session @@ -23,6 +27,9 @@ defmodule BlockScoutWeb.ViewingAppTest do insert(:block, number: index) end + start_supervised!(AddressesWithBalanceCounter) + AddressesWithBalanceCounter.consolidate() + assert Explorer.Chain.indexed_ratio() == 1.0 session @@ -35,6 +42,9 @@ defmodule BlockScoutWeb.ViewingAppTest do insert(:block, number: index) end + start_supervised!(AddressesWithBalanceCounter) + AddressesWithBalanceCounter.consolidate() + assert Explorer.Chain.indexed_ratio() == 0.5 session @@ -52,6 +62,9 @@ defmodule BlockScoutWeb.ViewingAppTest do insert(:block, number: index) end + start_supervised!(AddressesWithBalanceCounter) + AddressesWithBalanceCounter.consolidate() + assert Explorer.Chain.indexed_ratio() == 0.9 session @@ -70,6 +83,9 @@ defmodule BlockScoutWeb.ViewingAppTest do insert(:block, number: index) end + start_supervised!(AddressesWithBalanceCounter) + AddressesWithBalanceCounter.consolidate() + assert Explorer.Chain.indexed_ratio() == 1.0 session diff --git a/apps/block_scout_web/test/block_scout_web/features/viewing_chain_test.exs b/apps/block_scout_web/test/block_scout_web/features/viewing_chain_test.exs index f88b4513f9..15d69e712b 100644 --- a/apps/block_scout_web/test/block_scout_web/features/viewing_chain_test.exs +++ b/apps/block_scout_web/test/block_scout_web/features/viewing_chain_test.exs @@ -1,10 +1,13 @@ defmodule BlockScoutWeb.ViewingChainTest do @moduledoc false - use BlockScoutWeb.FeatureCase, async: true + use BlockScoutWeb.FeatureCase, + # MUST Be false because ETS tables for Counters are shared + async: false alias BlockScoutWeb.{AddressPage, BlockPage, ChainPage, TransactionPage} alias Explorer.Chain.Block + alias Explorer.Counters.{AddressesWithBalanceCounter, BlockValidationCounter} setup do Enum.map(401..404, &insert(:block, number: &1)) @@ -29,6 +32,12 @@ defmodule BlockScoutWeb.ViewingChainTest do test "search for address", %{session: session} do address = insert(:address) + start_supervised!(AddressesWithBalanceCounter) + AddressesWithBalanceCounter.consolidate() + + start_supervised!(BlockValidationCounter) + BlockValidationCounter.consolidate_blocks() + session |> ChainPage.visit_page() |> ChainPage.search(to_string(address.hash)) @@ -40,6 +49,9 @@ defmodule BlockScoutWeb.ViewingChainTest do test "search for blocks from chain page", %{session: session} do block = insert(:block, number: 6) + start_supervised!(AddressesWithBalanceCounter) + AddressesWithBalanceCounter.consolidate() + session |> ChainPage.visit_page() |> ChainPage.search(to_string(block.number)) @@ -47,6 +59,9 @@ defmodule BlockScoutWeb.ViewingChainTest do end test "blocks list", %{session: session} do + start_supervised!(AddressesWithBalanceCounter) + AddressesWithBalanceCounter.consolidate() + session |> ChainPage.visit_page() |> assert_has(ChainPage.blocks(count: 4)) @@ -55,6 +70,9 @@ defmodule BlockScoutWeb.ViewingChainTest do test "inserts place holder blocks on render for out of order blocks", %{session: session} do insert(:block, number: 409) + start_supervised!(AddressesWithBalanceCounter) + AddressesWithBalanceCounter.consolidate() + session |> ChainPage.visit_page() |> assert_has(ChainPage.block(%Block{number: 408})) @@ -66,6 +84,9 @@ defmodule BlockScoutWeb.ViewingChainTest do test "search for transactions", %{session: session} do transaction = insert(:transaction) + start_supervised!(AddressesWithBalanceCounter) + AddressesWithBalanceCounter.consolidate() + session |> ChainPage.visit_page() |> ChainPage.search(to_string(transaction.hash)) @@ -73,6 +94,9 @@ defmodule BlockScoutWeb.ViewingChainTest do end test "transactions list", %{session: session} do + start_supervised!(AddressesWithBalanceCounter) + AddressesWithBalanceCounter.consolidate() + session |> ChainPage.visit_page() |> assert_has(ChainPage.transactions(count: 5)) @@ -87,6 +111,9 @@ defmodule BlockScoutWeb.ViewingChainTest do |> with_contract_creation(contract_address) |> with_block(block) + start_supervised!(AddressesWithBalanceCounter) + AddressesWithBalanceCounter.consolidate() + session |> ChainPage.visit_page() |> assert_has(ChainPage.contract_creation(transaction)) @@ -111,6 +138,9 @@ defmodule BlockScoutWeb.ViewingChainTest do token_contract_address: contract_token_address ) + start_supervised!(AddressesWithBalanceCounter) + AddressesWithBalanceCounter.consolidate() + session |> ChainPage.visit_page() |> assert_has(ChainPage.token_transfers(transaction, count: 1)) diff --git a/apps/block_scout_web/test/block_scout_web/features/viewing_tokens_test.exs b/apps/block_scout_web/test/block_scout_web/features/viewing_tokens_test.exs index d896266848..f33a425403 100644 --- a/apps/block_scout_web/test/block_scout_web/features/viewing_tokens_test.exs +++ b/apps/block_scout_web/test/block_scout_web/features/viewing_tokens_test.exs @@ -1,6 +1,7 @@ defmodule BlockScoutWeb.ViewingTokensTest do use BlockScoutWeb.FeatureCase, async: true + alias Explorer.Counters.{TokenHoldersCounter, TokenTransferCounter} alias BlockScoutWeb.TokenPage describe "viewing token holders" do @@ -13,6 +14,12 @@ defmodule BlockScoutWeb.ViewingTokensTest do token_contract_address_hash: token.contract_address_hash ) + start_supervised!(TokenHoldersCounter) + TokenHoldersCounter.consolidate() + + start_supervised!(TokenTransferCounter) + TokenTransferCounter.consolidate() + session |> TokenPage.visit_page(token.contract_address) |> assert_has(TokenPage.token_holders(count: 2)) diff --git a/apps/block_scout_web/test/block_scout_web/features/viewing_transactions_test.exs b/apps/block_scout_web/test/block_scout_web/features/viewing_transactions_test.exs index a485f86957..a63b283fa4 100644 --- a/apps/block_scout_web/test/block_scout_web/features/viewing_transactions_test.exs +++ b/apps/block_scout_web/test/block_scout_web/features/viewing_transactions_test.exs @@ -1,10 +1,13 @@ defmodule BlockScoutWeb.ViewingTransactionsTest do @moduledoc false - use BlockScoutWeb.FeatureCase, async: true + use BlockScoutWeb.FeatureCase, + # ETS tables are shared in `Explorer.Counters.BlockValidationCounter` + async: false - alias Explorer.Chain.Wei alias BlockScoutWeb.{AddressPage, TransactionListPage, TransactionLogsPage, TransactionPage} + alias Explorer.Chain.Wei + alias Explorer.Counters.BlockValidationCounter setup do block = @@ -139,6 +142,8 @@ defmodule BlockScoutWeb.ViewingTransactionsTest do session: session, transaction: transaction } do + start_supervised!(BlockValidationCounter) + session |> TransactionLogsPage.visit_page(transaction) |> TransactionLogsPage.click_address(lincoln) diff --git a/apps/block_scout_web/test/block_scout_web/views/transaction_view_test.exs b/apps/block_scout_web/test/block_scout_web/views/transaction_view_test.exs index 6008640d7f..1139b85a36 100644 --- a/apps/block_scout_web/test/block_scout_web/views/transaction_view_test.exs +++ b/apps/block_scout_web/test/block_scout_web/views/transaction_view_test.exs @@ -94,7 +94,7 @@ defmodule BlockScoutWeb.TransactionViewTest do test "with fee" do {:ok, gas_price} = Wei.cast(3_000_000_000) - transaction = build(:transaction, gas_price: gas_price, gas_used: Decimal.new(1_034_234.0)) + transaction = build(:transaction, gas_price: gas_price, gas_used: Decimal.from_float(1_034_234.0)) expected_value = "0.003102702 POA" assert expected_value == TransactionView.formatted_fee(transaction, denomination: :ether) diff --git a/apps/explorer/config/config.exs b/apps/explorer/config/config.exs index 61c197f876..154f6f93b4 100644 --- a/apps/explorer/config/config.exs +++ b/apps/explorer/config/config.exs @@ -5,37 +5,33 @@ # is restricted to this project. use Mix.Config -config :ecto, json_library: Jason - # General application configuration config :explorer, ecto_repos: [Explorer.Repo], coin: System.get_env("COIN") || "POA", token_functions_reader_max_retries: 3 -config :explorer, Explorer.Integrations.EctoLogger, query_time_ms_threshold: 2_000 +config :explorer, Explorer.Counters.AddressesWithBalanceCounter, enabled: true, enable_consolidation: true + +config :explorer, Explorer.Counters.TokenHoldersCounter, enabled: true, enable_consolidation: true + +config :explorer, Explorer.Counters.TokenTransferCounter, enabled: true, enable_consolidation: true + +config :explorer, Explorer.Counters.BlockValidationCounter, enabled: true, enable_consolidation: true config :explorer, Explorer.ExchangeRates, enabled: true, store: :ets +config :explorer, Explorer.Integrations.EctoLogger, query_time_ms_threshold: 2_000 + config :explorer, Explorer.Market.History.Cataloger, enabled: true -config :explorer, Explorer.Repo, - loggers: [Explorer.Repo.PrometheusLogger, Ecto.LogEntry], - migration_timestamps: [type: :utc_datetime] +config :explorer, Explorer.Repo, migration_timestamps: [type: :utc_datetime_usec] config :explorer, Explorer.Tracer, service: :explorer, adapter: SpandexDatadog.Adapter, trace_key: :blockscout -config :explorer, Explorer.Counters.TokenTransferCounter, enabled: true - -config :explorer, Explorer.Counters.BlockValidationCounter, enabled: true, enable_consolidation: true - -config :explorer, Explorer.Counters.TokenHoldersCounter, enabled: true, enable_consolidation: true - -config :explorer, Explorer.Counters.AddessesWithBalanceCounter, enabled: true, enable_consolidation: true - if System.get_env("SUPPLY_MODULE") == "TransactionAndLog" do config :explorer, supply: Explorer.Chain.Supply.TransactionAndLog end diff --git a/apps/explorer/config/dev.exs b/apps/explorer/config/dev.exs index 2e61bb9124..34e1a357af 100644 --- a/apps/explorer/config/dev.exs +++ b/apps/explorer/config/dev.exs @@ -2,11 +2,9 @@ use Mix.Config # Configure your database config :explorer, Explorer.Repo, - adapter: Ecto.Adapters.Postgres, database: "explorer_dev", hostname: "localhost", pool_size: 20, - pool_timeout: 60_000, timeout: 80_000 config :explorer, Explorer.Tracer, env: "dev", disabled?: true diff --git a/apps/explorer/config/dev.secret.exs.example b/apps/explorer/config/dev.secret.exs.example index f50b3cc042..bde88d33f1 100644 --- a/apps/explorer/config/dev.secret.exs.example +++ b/apps/explorer/config/dev.secret.exs.example @@ -2,12 +2,9 @@ use Mix.Config # Configure your database config :explorer, Explorer.Repo, - adapter: Ecto.Adapters.Postgres, database: "explorer_dev", hostname: "localhost", username: "postgres", password: "", - loggers: [Explorer.Repo.PrometheusLogger], pool_size: 20, - pool_timeout: 60_000, timeout: 80_000 diff --git a/apps/explorer/config/prod.exs b/apps/explorer/config/prod.exs index 4d5fe15c46..29a377d219 100644 --- a/apps/explorer/config/prod.exs +++ b/apps/explorer/config/prod.exs @@ -2,7 +2,6 @@ use Mix.Config # Configures the database config :explorer, Explorer.Repo, - adapter: Ecto.Adapters.Postgres, url: System.get_env("DATABASE_URL"), pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10"), ssl: String.equivalent?(System.get_env("ECTO_USE_SSL") || "true", "true"), diff --git a/apps/explorer/config/test.exs b/apps/explorer/config/test.exs index f2a4c3306d..194b2f2ccc 100644 --- a/apps/explorer/config/test.exs +++ b/apps/explorer/config/test.exs @@ -5,25 +5,27 @@ config :bcrypt_elixir, log_rounds: 4 # Configure your database config :explorer, Explorer.Repo, - adapter: Ecto.Adapters.Postgres, database: "explorer_test", hostname: "localhost", pool: Ecto.Adapters.SQL.Sandbox, # Default of `5_000` was too low for `BlockFetcher` test - pool_timeout: 10_000, ownership_timeout: 60_000 config :explorer, Explorer.ExchangeRates, enabled: false, store: :ets -config :explorer, Explorer.Market.History.Cataloger, enabled: false +config :explorer, Explorer.Counters.AddressesWithBalanceCounter, enabled: false, enable_consolidation: false -config :explorer, Explorer.Tracer, disabled?: false +config :explorer, Explorer.Counters.BlockValidationCounter, enabled: false, enable_consolidation: true + +config :explorer, Explorer.Counters.BlockValidationCounter, enabled: false, enable_consolidation: false -config :explorer, Explorer.Counters.BlockValidationCounter, enabled: true, enable_consolidation: false +config :explorer, Explorer.Counters.TokenHoldersCounter, enabled: false, enable_consolidation: false -config :explorer, Explorer.Counters.TokenHoldersCounter, enabled: true, enable_consolidation: false +config :explorer, Explorer.Counters.TokenTransferCounter, enabled: false, enable_consolidation: false -config :explorer, Explorer.Counters.AddessesWithBalanceCounter, enabled: true, enable_consolidation: false +config :explorer, Explorer.Market.History.Cataloger, enabled: false + +config :explorer, Explorer.Tracer, disabled?: false config :logger, :explorer, level: :warn, diff --git a/apps/explorer/config/test.secret.exs.example b/apps/explorer/config/test.secret.exs.example index 82c2df46cd..77960f69db 100644 --- a/apps/explorer/config/test.secret.exs.example +++ b/apps/explorer/config/test.secret.exs.example @@ -2,7 +2,6 @@ use Mix.Config # Configure your database config :explorer, Explorer.Repo, - adapter: Ecto.Adapters.Postgres, database: "explorer_test", hostname: "localhost", pool: Ecto.Adapters.SQL.Sandbox, diff --git a/apps/explorer/lib/explorer/accounts/user.ex b/apps/explorer/lib/explorer/accounts/user.ex index d96c5b426b..1a3b46456b 100644 --- a/apps/explorer/lib/explorer/accounts/user.ex +++ b/apps/explorer/lib/explorer/accounts/user.ex @@ -3,7 +3,7 @@ defmodule Explorer.Accounts.User do An Explorer user. """ - use Ecto.Schema + use Explorer.Schema import Ecto.Changeset diff --git a/apps/explorer/lib/explorer/accounts/user/authenticate.ex b/apps/explorer/lib/explorer/accounts/user/authenticate.ex index 818dca83e4..08626c18b0 100644 --- a/apps/explorer/lib/explorer/accounts/user/authenticate.ex +++ b/apps/explorer/lib/explorer/accounts/user/authenticate.ex @@ -3,7 +3,7 @@ defmodule Explorer.Accounts.User.Authenticate do Represents the data required to authenticate a user. """ - use Ecto.Schema + use Explorer.Schema import Ecto.Changeset diff --git a/apps/explorer/lib/explorer/accounts/user/registration.ex b/apps/explorer/lib/explorer/accounts/user/registration.ex index 78f74b8cbf..360e6bbb5e 100644 --- a/apps/explorer/lib/explorer/accounts/user/registration.ex +++ b/apps/explorer/lib/explorer/accounts/user/registration.ex @@ -3,7 +3,7 @@ defmodule Explorer.Accounts.User.Registration do Represents the data required to register a new account. """ - use Ecto.Schema + use Explorer.Schema import Ecto.Changeset diff --git a/apps/explorer/lib/explorer/accounts/user_contact.ex b/apps/explorer/lib/explorer/accounts/user_contact.ex index 23fb72a56e..5d6117ef99 100644 --- a/apps/explorer/lib/explorer/accounts/user_contact.ex +++ b/apps/explorer/lib/explorer/accounts/user_contact.ex @@ -6,7 +6,7 @@ defmodule Explorer.Accounts.UserContact do given user. Additionally, a user can only have 1 primary contact at a time. """ - use Ecto.Schema + use Explorer.Schema import Ecto.Changeset diff --git a/apps/explorer/lib/explorer/admin/administrator.ex b/apps/explorer/lib/explorer/admin/administrator.ex index 27dc06512f..20ec8d92b3 100644 --- a/apps/explorer/lib/explorer/admin/administrator.ex +++ b/apps/explorer/lib/explorer/admin/administrator.ex @@ -3,7 +3,7 @@ defmodule Explorer.Admin.Administrator do Represents a user with administrative privileges. """ - use Ecto.Schema + use Explorer.Schema import Ecto.Changeset diff --git a/apps/explorer/lib/explorer/application.ex b/apps/explorer/lib/explorer/application.ex index 8f5438c95f..bf124baa35 100644 --- a/apps/explorer/lib/explorer/application.ex +++ b/apps/explorer/lib/explorer/application.ex @@ -12,6 +12,8 @@ defmodule Explorer.Application do def start(_type, _args) do PrometheusLogger.setup() + Telemetry.attach("prometheus-ecto", [:explorer, :repo, :query], Explorer.Repo.PrometheusLogger, :handle_event, %{}) + # Children to start in all environments base_children = [ Explorer.Repo, @@ -36,7 +38,7 @@ defmodule Explorer.Application do configure(Explorer.Counters.TokenHoldersCounter), configure(Explorer.Counters.TokenTransferCounter), configure(Explorer.Counters.BlockValidationCounter), - configure(Explorer.Counters.AddessesWithBalanceCounter) + configure(Explorer.Counters.AddressesWithBalanceCounter) ] |> List.flatten() end diff --git a/apps/explorer/lib/explorer/chain.ex b/apps/explorer/lib/explorer/chain.ex index 5b5aab9867..d72ac90197 100644 --- a/apps/explorer/lib/explorer/chain.ex +++ b/apps/explorer/lib/explorer/chain.ex @@ -42,13 +42,14 @@ defmodule Explorer.Chain do alias Explorer.{PagingOptions, Repo} alias Explorer.Counters.{ - AddessesWithBalanceCounter, + AddressesWithBalanceCounter, BlockValidationCounter, TokenHoldersCounter, TokenTransferCounter } alias Dataloader.Ecto, as: DataloaderEcto + alias Timex.Duration @default_paging_options %PagingOptions{page_size: 50} @@ -93,7 +94,7 @@ defmodule Explorer.Chain do """ @spec count_addresses_with_balance_from_cache :: non_neg_integer() def count_addresses_with_balance_from_cache do - AddessesWithBalanceCounter.fetch() + AddressesWithBalanceCounter.fetch() end @doc """ @@ -280,7 +281,7 @@ defmodule Explorer.Chain do """ @spec average_block_time :: %Timex.Duration{} def average_block_time do - {:ok, %Postgrex.Result{rows: [[rows]]}} = + {:ok, %Postgrex.Result{rows: [[%Postgrex.Interval{months: 0, days: days, secs: seconds}]]}} = SQL.query( Repo, """ @@ -294,9 +295,10 @@ defmodule Explorer.Chain do [] ) - {:ok, value} = Timex.Ecto.Time.load(rows) - - value + hours = days * 24 + minutes = 0 + microseconds = 0 + Duration.from_clock({hours, minutes, seconds, microseconds}) end @doc """ @@ -1256,24 +1258,24 @@ defmodule Explorer.Chain do missing_block_number_range in fragment( # adapted from https://www.xaprb.com/blog/2006/03/22/find-contiguous-ranges-with-sql/ """ - WITH missing_blocks AS - (SELECT number - FROM generate_series(? :: bigint, ? :: bigint, ? :: bigint) AS number - EXCEPT - SELECT blocks.number - FROM blocks - WHERE blocks.consensus = true) - SELECT no_previous.number AS minimum, - (SELECT MIN(no_next.number) - FROM missing_blocks AS no_next - LEFT OUTER JOIN missing_blocks AS next - ON no_next.number = next.number - 1 - WHERE next.number IS NULL AND - no_next.number >= no_previous.number) AS maximum - FROM missing_blocks as no_previous - LEFT OUTER JOIN missing_blocks AS previous - ON previous.number = no_previous.number - 1 - WHERE previous.number IS NULL + (WITH missing_blocks AS + (SELECT number + FROM generate_series(? :: bigint, ? :: bigint, ? :: bigint) AS number + EXCEPT + SELECT blocks.number + FROM blocks + WHERE blocks.consensus = true) + SELECT no_previous.number AS minimum, + (SELECT MIN(no_next.number) + FROM missing_blocks AS no_next + LEFT OUTER JOIN missing_blocks AS next + ON no_next.number = next.number - 1 + WHERE next.number IS NULL AND + no_next.number >= no_previous.number) AS maximum + FROM missing_blocks as no_previous + LEFT OUTER JOIN missing_blocks AS previous + ON previous.number = no_previous.number - 1 + WHERE previous.number IS NULL) """, ^range_start, ^range_end, @@ -1699,8 +1701,8 @@ defmodule Explorer.Chain do insert_result = Multi.new() |> Multi.insert(:smart_contract, smart_contract_changeset) - |> Multi.run(:clear_primary_address_names, &clear_primary_address_names/1) - |> Multi.run(:insert_address_name, &create_address_name/1) + |> Multi.run(:clear_primary_address_names, &clear_primary_address_names/2) + |> Multi.run(:insert_address_name, &create_address_name/2) |> Repo.transaction() with {:ok, %{smart_contract: smart_contract}} <- insert_result do @@ -1711,7 +1713,7 @@ defmodule Explorer.Chain do end end - defp clear_primary_address_names(%{smart_contract: %SmartContract{address_hash: address_hash}}) do + defp clear_primary_address_names(repo, %{smart_contract: %SmartContract{address_hash: address_hash}}) do clear_primary_query = from( address_name in Address.Name, @@ -1719,12 +1721,12 @@ defmodule Explorer.Chain do update: [set: [primary: false]] ) - Repo.update_all(clear_primary_query, []) + repo.update_all(clear_primary_query, []) {:ok, []} end - defp create_address_name(%{smart_contract: %SmartContract{name: name, address_hash: address_hash}}) do + defp create_address_name(repo, %{smart_contract: %SmartContract{name: name, address_hash: address_hash}}) do params = %{ address_hash: address_hash, name: name, @@ -1733,7 +1735,7 @@ defmodule Explorer.Chain do %Address.Name{} |> Address.Name.changeset(params) - |> Repo.insert(on_conflict: :nothing, conflict_target: [:address_hash, :name]) + |> repo.insert(on_conflict: :nothing, conflict_target: [:address_hash, :name]) end @spec address_hash_to_smart_contract(%Explorer.Chain.Hash{}) :: %Explorer.Chain.SmartContract{} | nil @@ -2030,8 +2032,8 @@ defmodule Explorer.Chain do |> Multi.insert(:token, token_changeset, token_opts) |> Multi.run( :address_name, - fn _ -> - {:ok, Repo.insert(address_name_changeset, address_name_opts)} + fn repo, _ -> + {:ok, repo.insert(address_name_changeset, address_name_opts)} end ) |> Repo.transaction() @@ -2077,19 +2079,12 @@ defmodule Explorer.Chain do defp normalize_balances_by_day(balances_by_day) do balances_by_day - |> Enum.map(fn day -> Map.update(day, :date, nil, &tuple_to_date(&1)) end) |> Enum.map(fn day -> Map.take(day, [:date, :value]) end) |> Enum.filter(fn day -> day.value end) |> Enum.map(fn day -> Map.update!(day, :date, &to_string(&1)) end) |> Enum.map(fn day -> Map.update!(day, :value, &Wei.to(&1, :ether)) end) end - defp tuple_to_date({date_tuple, _time_tuple}) do - case Date.from_erl(date_tuple) do - {:ok, date} -> date - end - end - @spec fetch_token_holders_from_token_hash(Hash.Address.t(), [paging_options]) :: [TokenBalance.t()] def fetch_token_holders_from_token_hash(contract_address_hash, options) do contract_address_hash diff --git a/apps/explorer/lib/explorer/chain/address/coin_balance.ex b/apps/explorer/lib/explorer/chain/address/coin_balance.ex index 783d329b84..af12491247 100644 --- a/apps/explorer/lib/explorer/chain/address/coin_balance.ex +++ b/apps/explorer/lib/explorer/chain/address/coin_balance.ex @@ -40,9 +40,9 @@ defmodule Explorer.Chain.Address.CoinBalance do schema "address_coin_balances" do field(:block_number, :integer) field(:value, Wei) - field(:value_fetched_at, :utc_datetime) + field(:value_fetched_at, :utc_datetime_usec) field(:delta, Wei, virtual: true) - field(:block_timestamp, :utc_datetime, virtual: true) + field(:block_timestamp, :utc_datetime_usec, virtual: true) timestamps() @@ -91,12 +91,12 @@ defmodule Explorer.Chain.Address.CoinBalance do """ def balances_by_day(address_hash) do CoinBalance - |> join(:inner, [cb], b in Block, cb.block_number == b.number) + |> join(:inner, [cb], b in Block, on: cb.block_number == b.number) |> where([cb], cb.address_hash == ^address_hash) |> where([cb, b], b.timestamp >= fragment("date_trunc('day', now()) - interval '90 days'")) |> group_by([cb, b], fragment("date_trunc('day', ?)", b.timestamp)) |> order_by([cb, b], fragment("date_trunc('day', ?)", b.timestamp)) - |> select([cb, b], %{date: fragment("date_trunc('day', ?)", b.timestamp), value: max(cb.value)}) + |> select([cb, b], %{date: type(fragment("date_trunc('day', ?)", b.timestamp), :date), value: max(cb.value)}) end def changeset(%__MODULE__{} = balance, params) do diff --git a/apps/explorer/lib/explorer/chain/address/current_token_balance.ex b/apps/explorer/lib/explorer/chain/address/current_token_balance.ex index 2a89d327a7..82f442b55e 100644 --- a/apps/explorer/lib/explorer/chain/address/current_token_balance.ex +++ b/apps/explorer/lib/explorer/chain/address/current_token_balance.ex @@ -6,7 +6,8 @@ defmodule Explorer.Chain.Address.CurrentTokenBalance do token balances look at the `Address.TokenBalance` instead. """ - use Ecto.Schema + use Explorer.Schema + import Ecto.Changeset import Ecto.Query, only: [from: 2, limit: 2, order_by: 3, preload: 2, where: 3] @@ -37,7 +38,7 @@ defmodule Explorer.Chain.Address.CurrentTokenBalance do schema "address_current_token_balances" do field(:value, :decimal) field(:block_number, :integer) - field(:value_fetched_at, :utc_datetime) + field(:value_fetched_at, :utc_datetime_usec) belongs_to(:address, Address, foreign_key: :address_hash, references: :hash, type: Hash.Address) diff --git a/apps/explorer/lib/explorer/chain/address/name.ex b/apps/explorer/lib/explorer/chain/address/name.ex index ac094e8c45..f2a6489375 100644 --- a/apps/explorer/lib/explorer/chain/address/name.ex +++ b/apps/explorer/lib/explorer/chain/address/name.ex @@ -3,7 +3,7 @@ defmodule Explorer.Chain.Address.Name do Represents a name for an Address. """ - use Ecto.Schema + use Explorer.Schema import Ecto.Changeset diff --git a/apps/explorer/lib/explorer/chain/address/token_balance.ex b/apps/explorer/lib/explorer/chain/address/token_balance.ex index d15c2161ac..4c20f35ddc 100644 --- a/apps/explorer/lib/explorer/chain/address/token_balance.ex +++ b/apps/explorer/lib/explorer/chain/address/token_balance.ex @@ -7,7 +7,8 @@ defmodule Explorer.Chain.Address.TokenBalance do `Address.CurrentTokenBalance` instead. """ - use Ecto.Schema + use Explorer.Schema + import Ecto.Changeset import Ecto.Query, only: [from: 2, subquery: 1] @@ -37,7 +38,7 @@ defmodule Explorer.Chain.Address.TokenBalance do schema "address_token_balances" do field(:value, :decimal) field(:block_number, :integer) - field(:value_fetched_at, :utc_datetime) + field(:value_fetched_at, :utc_datetime_usec) belongs_to(:address, Address, foreign_key: :address_hash, references: :hash, type: Hash.Address) diff --git a/apps/explorer/lib/explorer/chain/block.ex b/apps/explorer/lib/explorer/chain/block.ex index 89fdf8233d..4b194587c9 100644 --- a/apps/explorer/lib/explorer/chain/block.ex +++ b/apps/explorer/lib/explorer/chain/block.ex @@ -71,7 +71,7 @@ defmodule Explorer.Chain.Block do field(:nonce, Hash.Nonce) field(:number, :integer) field(:size, :integer) - field(:timestamp, :utc_datetime) + field(:timestamp, :utc_datetime_usec) field(:total_difficulty, :decimal) timestamps() diff --git a/apps/explorer/lib/explorer/chain/block/second_degree_relation.ex b/apps/explorer/lib/explorer/chain/block/second_degree_relation.ex index 986d4d5e03..ee31ae13c2 100644 --- a/apps/explorer/lib/explorer/chain/block/second_degree_relation.ex +++ b/apps/explorer/lib/explorer/chain/block/second_degree_relation.ex @@ -46,7 +46,7 @@ defmodule Explorer.Chain.Block.SecondDegreeRelation do @primary_key false schema "block_second_degree_relations" do - field(:uncle_fetched_at, :utc_datetime) + field(:uncle_fetched_at, :utc_datetime_usec) belongs_to(:nephew, Block, foreign_key: :nephew_hash, references: :hash, type: Hash.Full) belongs_to(:uncle, Block, foreign_key: :uncle_hash, references: :hash, type: Hash.Full) diff --git a/apps/explorer/lib/explorer/chain/import.ex b/apps/explorer/lib/explorer/chain/import.ex index 308b3f3797..f6b44f46a5 100644 --- a/apps/explorer/lib/explorer/chain/import.ex +++ b/apps/explorer/lib/explorer/chain/import.ex @@ -296,13 +296,13 @@ defmodule Explorer.Chain.Import do end) end - def insert_changes_list(changes_list, options) when is_list(changes_list) do + def insert_changes_list(repo, changes_list, options) when is_atom(repo) and is_list(changes_list) do ecto_schema_module = Keyword.fetch!(options, :for) timestamped_changes_list = timestamp_changes_list(changes_list, Keyword.fetch!(options, :timestamps)) {_, inserted} = - Repo.safe_insert_all( + repo.safe_insert_all( ecto_schema_module, timestamped_changes_list, Keyword.delete(options, :for) diff --git a/apps/explorer/lib/explorer/chain/import/address/coin_balances.ex b/apps/explorer/lib/explorer/chain/import/address/coin_balances.ex index f9b5e3aeac..d938018959 100644 --- a/apps/explorer/lib/explorer/chain/import/address/coin_balances.ex +++ b/apps/explorer/lib/explorer/chain/import/address/coin_balances.ex @@ -7,7 +7,7 @@ defmodule Explorer.Chain.Import.Address.CoinBalances do import Ecto.Query, only: [from: 2] - alias Ecto.{Changeset, Multi} + alias Ecto.{Changeset, Multi, Repo} alias Explorer.Chain.Address.CoinBalance alias Explorer.Chain.{Block, Hash, Import, Wei} @@ -43,8 +43,8 @@ defmodule Explorer.Chain.Import.Address.CoinBalances do |> Map.put_new(:timeout, @timeout) |> Map.put(:timestamps, timestamps) - Multi.run(multi, :address_coin_balances, fn _ -> - insert(changes_list, insert_options) + Multi.run(multi, :address_coin_balances, fn repo, _ -> + insert(repo, changes_list, insert_options) end) end @@ -52,6 +52,7 @@ defmodule Explorer.Chain.Import.Address.CoinBalances do def timeout, do: @timeout @spec insert( + Repo.t(), [ %{ required(:address_hash) => Hash.Address.t(), @@ -67,7 +68,7 @@ defmodule Explorer.Chain.Import.Address.CoinBalances do ) :: {:ok, [%{required(:address_hash) => Hash.Address.t(), required(:block_number) => Block.block_number()}]} | {:error, [Changeset.t()]} - defp insert(changes_list, %{timeout: timeout, timestamps: timestamps} = options) when is_list(changes_list) do + defp insert(repo, changes_list, %{timeout: timeout, timestamps: timestamps} = options) when is_list(changes_list) do on_conflict = Map.get_lazy(options, :on_conflict, &default_on_conflict/0) # order so that row ShareLocks are grabbed in a consistent order @@ -75,6 +76,7 @@ defmodule Explorer.Chain.Import.Address.CoinBalances do {:ok, _} = Import.insert_changes_list( + repo, ordered_changes_list, conflict_target: [:address_hash, :block_number], on_conflict: on_conflict, diff --git a/apps/explorer/lib/explorer/chain/import/address/current_token_balances.ex b/apps/explorer/lib/explorer/chain/import/address/current_token_balances.ex index 11cf8cf460..b1b101e50e 100644 --- a/apps/explorer/lib/explorer/chain/import/address/current_token_balances.ex +++ b/apps/explorer/lib/explorer/chain/import/address/current_token_balances.ex @@ -7,7 +7,7 @@ defmodule Explorer.Chain.Import.Address.CurrentTokenBalances do import Ecto.Query, only: [from: 2] - alias Ecto.{Changeset, Multi} + alias Ecto.{Changeset, Multi, Repo} alias Explorer.Chain.Address.CurrentTokenBalance alias Explorer.Chain.Import @@ -41,26 +41,28 @@ defmodule Explorer.Chain.Import.Address.CurrentTokenBalances do |> Map.put_new(:timeout, @timeout) |> Map.put(:timestamps, timestamps) - Multi.run(multi, :address_current_token_balances, fn _ -> - insert(changes_list, insert_options) + Multi.run(multi, :address_current_token_balances, fn repo, _ -> + insert(repo, changes_list, insert_options) end) end @impl Import.Runner def timeout, do: @timeout - @spec insert([map()], %{ + @spec insert(Repo.t(), [map()], %{ optional(:on_conflict) => Import.Runner.on_conflict(), required(:timeout) => timeout(), required(:timestamps) => Import.timestamps() }) :: {:ok, [CurrentTokenBalance.t()]} | {:error, [Changeset.t()]} - def insert(changes_list, %{timeout: timeout, timestamps: timestamps} = options) when is_list(changes_list) do + def insert(repo, changes_list, %{timeout: timeout, timestamps: timestamps} = options) + when is_atom(repo) and is_list(changes_list) do on_conflict = Map.get_lazy(options, :on_conflict, &default_on_conflict/0) {:ok, _} = Import.insert_changes_list( + repo, unique_token_balances(changes_list), conflict_target: ~w(address_hash token_contract_address_hash)a, on_conflict: on_conflict, diff --git a/apps/explorer/lib/explorer/chain/import/address/token_balances.ex b/apps/explorer/lib/explorer/chain/import/address/token_balances.ex index 207bbeb81b..848a7bb0ac 100644 --- a/apps/explorer/lib/explorer/chain/import/address/token_balances.ex +++ b/apps/explorer/lib/explorer/chain/import/address/token_balances.ex @@ -7,7 +7,7 @@ defmodule Explorer.Chain.Import.Address.TokenBalances do import Ecto.Query, only: [from: 2] - alias Ecto.{Changeset, Multi} + alias Ecto.{Changeset, Multi, Repo} alias Explorer.Chain.Address.TokenBalance alias Explorer.Chain.Import @@ -41,22 +41,22 @@ defmodule Explorer.Chain.Import.Address.TokenBalances do |> Map.put_new(:timeout, @timeout) |> Map.put(:timestamps, timestamps) - Multi.run(multi, :address_token_balances, fn _ -> - insert(changes_list, insert_options) + Multi.run(multi, :address_token_balances, fn repo, _ -> + insert(repo, changes_list, insert_options) end) end @impl Import.Runner def timeout, do: @timeout - @spec insert([map()], %{ + @spec insert(Repo.t(), [map()], %{ optional(:on_conflict) => Import.Runner.on_conflict(), required(:timeout) => timeout(), required(:timestamps) => Import.timestamps() }) :: {:ok, [TokenBalance.t()]} | {:error, [Changeset.t()]} - def insert(changes_list, %{timeout: timeout, timestamps: timestamps} = options) when is_list(changes_list) do + def insert(repo, changes_list, %{timeout: timeout, timestamps: timestamps} = options) when is_list(changes_list) do on_conflict = Map.get_lazy(options, :on_conflict, &default_on_conflict/0) # order so that row ShareLocks are grabbed in a consistent order @@ -64,6 +64,7 @@ defmodule Explorer.Chain.Import.Address.TokenBalances do {:ok, _} = Import.insert_changes_list( + repo, ordered_changes_list, conflict_target: ~w(address_hash token_contract_address_hash block_number)a, on_conflict: on_conflict, diff --git a/apps/explorer/lib/explorer/chain/import/addresses.ex b/apps/explorer/lib/explorer/chain/import/addresses.ex index fd0546ef3a..49ba5d1eb1 100644 --- a/apps/explorer/lib/explorer/chain/import/addresses.ex +++ b/apps/explorer/lib/explorer/chain/import/addresses.ex @@ -5,7 +5,7 @@ defmodule Explorer.Chain.Import.Addresses do require Ecto.Query - alias Ecto.Multi + alias Ecto.{Multi, Repo} alias Explorer.Chain.{Address, Hash, Import} import Ecto.Query, only: [from: 2] @@ -40,8 +40,8 @@ defmodule Explorer.Chain.Import.Addresses do |> Map.put_new(:timeout, @timeout) |> Map.put(:timestamps, timestamps) - Multi.run(multi, :addresses, fn _ -> - insert(changes_list, insert_options) + Multi.run(multi, :addresses, fn repo, _ -> + insert(repo, changes_list, insert_options) end) end @@ -50,18 +50,19 @@ defmodule Explorer.Chain.Import.Addresses do ## Private Functions - @spec insert([%{hash: Hash.Address.t()}], %{ + @spec insert(Repo.t(), [%{hash: Hash.Address.t()}], %{ optional(:on_conflict) => Import.Runner.on_conflict(), required(:timeout) => timeout, required(:timestamps) => Import.timestamps() }) :: {:ok, [Address.t()]} - defp insert(changes_list, %{timeout: timeout, timestamps: timestamps} = options) when is_list(changes_list) do + defp insert(repo, changes_list, %{timeout: timeout, timestamps: timestamps} = options) when is_list(changes_list) do on_conflict = Map.get_lazy(options, :on_conflict, &default_on_conflict/0) # order so that row ShareLocks are grabbed in a consistent order ordered_changes_list = sort_changes_list(changes_list) Import.insert_changes_list( + repo, ordered_changes_list, conflict_target: :hash, on_conflict: on_conflict, diff --git a/apps/explorer/lib/explorer/chain/import/block/second_degree_relations.ex b/apps/explorer/lib/explorer/chain/import/block/second_degree_relations.ex index 3722d8a3cc..a812a4e9f9 100644 --- a/apps/explorer/lib/explorer/chain/import/block/second_degree_relations.ex +++ b/apps/explorer/lib/explorer/chain/import/block/second_degree_relations.ex @@ -7,7 +7,7 @@ defmodule Explorer.Chain.Import.Block.SecondDegreeRelations do import Ecto.Query, only: [from: 2] - alias Ecto.{Changeset, Multi} + alias Ecto.{Changeset, Multi, Repo} alias Explorer.Chain.{Block, Hash, Import} @behaviour Import.Runner @@ -40,23 +40,25 @@ defmodule Explorer.Chain.Import.Block.SecondDegreeRelations do |> Map.take(~w(on_conflict timeout)a) |> Map.put_new(:timeout, @timeout) - Multi.run(multi, :block_second_degree_relations, fn _ -> - insert(changes_list, insert_options) + Multi.run(multi, :block_second_degree_relations, fn repo, _ -> + insert(repo, changes_list, insert_options) end) end @impl Import.Runner def timeout, do: @timeout - @spec insert([map()], %{optional(:on_conflict) => Import.Runner.on_conflict(), required(:timeout) => timeout}) :: - {:ok, %{nephew_hash: Hash.Full.t(), uncle_hash: Hash.Full.t()}} | {:error, [Changeset.t()]} - defp insert(changes_list, %{timeout: timeout} = options) when is_list(changes_list) do + @spec insert(Repo.t(), [map()], %{ + optional(:on_conflict) => Import.Runner.on_conflict(), + required(:timeout) => timeout + }) :: {:ok, %{nephew_hash: Hash.Full.t(), uncle_hash: Hash.Full.t()}} | {:error, [Changeset.t()]} + defp insert(repo, changes_list, %{timeout: timeout} = options) when is_atom(repo) and is_list(changes_list) do on_conflict = Map.get_lazy(options, :on_conflict, &default_on_conflict/0) # order so that row ShareLocks are grabbed in a consistent order ordered_changes_list = Enum.sort_by(changes_list, &{&1.nephew_hash, &1.uncle_hash}) - Import.insert_changes_list(ordered_changes_list, + Import.insert_changes_list(repo, ordered_changes_list, conflict_target: [:nephew_hash, :uncle_hash], on_conflict: on_conflict, for: Block.SecondDegreeRelation, diff --git a/apps/explorer/lib/explorer/chain/import/block_rewards.ex b/apps/explorer/lib/explorer/chain/import/block_rewards.ex index 7eb4c2ddca..40f42c7358 100644 --- a/apps/explorer/lib/explorer/chain/import/block_rewards.ex +++ b/apps/explorer/lib/explorer/chain/import/block_rewards.ex @@ -5,7 +5,7 @@ defmodule Explorer.Chain.Import.Block.Rewards do import Ecto.Query, only: [from: 2] - alias Ecto.{Changeset, Multi} + alias Ecto.{Changeset, Multi, Repo} alias Explorer.Chain.Block.Reward alias Explorer.Chain.Import @@ -37,19 +37,20 @@ defmodule Explorer.Chain.Import.Block.Rewards do |> Map.put_new(:timeout, @timeout) |> Map.put(:timestamps, timestamps) - Multi.run(multi, option_key(), fn _ -> insert(changes_list, insert_options) end) + Multi.run(multi, option_key(), fn repo, _ -> insert(repo, changes_list, insert_options) end) end @impl Import.Runner def timeout, do: @timeout - @spec insert([map()], %{ + @spec insert(Repo.t(), [map()], %{ required(:timeout) => timeout, required(:timestamps) => Import.timestamps() }) :: {:ok, [Reward.t()]} | {:error, [Changeset.t()]} - defp insert(changes_list, %{timeout: timeout, timestamps: timestamps}) + defp insert(repo, changes_list, %{timeout: timeout, timestamps: timestamps}) when is_list(changes_list) do Import.insert_changes_list( + repo, changes_list, conflict_target: [:address_hash, :address_type, :block_hash], on_conflict: on_conflict(), diff --git a/apps/explorer/lib/explorer/chain/import/blocks.ex b/apps/explorer/lib/explorer/chain/import/blocks.ex index 6c7b046cab..2552eea1f5 100644 --- a/apps/explorer/lib/explorer/chain/import/blocks.ex +++ b/apps/explorer/lib/explorer/chain/import/blocks.ex @@ -5,12 +5,11 @@ defmodule Explorer.Chain.Import.Blocks do require Ecto.Query - import Ecto.Query, only: [from: 2, update: 2] + import Ecto.Query, only: [from: 2, select: 2, update: 2] alias Ecto.Adapters.SQL - alias Ecto.{Changeset, Multi} + alias Ecto.{Changeset, Multi, Repo} alias Explorer.Chain.{Block, Import, InternalTransaction, Transaction} - alias Explorer.Repo @behaviour Import.Runner @@ -45,29 +44,32 @@ defmodule Explorer.Chain.Import.Blocks do where_forked = where_forked(changes_list) multi - |> Multi.run(:derive_transaction_forks, fn _ -> + |> Multi.run(:derive_transaction_forks, fn repo, _ -> derive_transaction_forks(%{ + repo: repo, timeout: options[Import.Transaction.Forks.option_key()][:timeout] || Import.Transaction.Forks.timeout(), timestamps: timestamps, where_forked: where_forked }) end) # MUST be after `:derive_transaction_forks`, which depends on values in `transactions` table - |> Multi.run(:fork_transactions, fn _ -> + |> Multi.run(:fork_transactions, fn repo, _ -> fork_transactions(%{ + repo: repo, timeout: options[Import.Transactions.option_key()][:timeout] || Import.Transactions.timeout(), timestamps: timestamps, where_forked: where_forked }) end) - |> Multi.run(:lose_consenus, fn _ -> - lose_consensus(changes_list, insert_options) + |> Multi.run(:lose_consenus, fn repo, _ -> + lose_consensus(repo, changes_list, insert_options) end) - |> Multi.run(:blocks, fn _ -> - insert(changes_list, insert_options) + |> Multi.run(:blocks, fn repo, _ -> + insert(repo, changes_list, insert_options) end) - |> Multi.run(:uncle_fetched_block_second_degree_relations, fn %{blocks: blocks} when is_list(blocks) -> + |> Multi.run(:uncle_fetched_block_second_degree_relations, fn repo, %{blocks: blocks} when is_list(blocks) -> update_block_second_degree_relations( + repo, blocks, %{ timeout: @@ -79,7 +81,7 @@ defmodule Explorer.Chain.Import.Blocks do end) |> Multi.run( :internal_transaction_transaction_block_number, - fn %{blocks: blocks} -> + fn repo, %{blocks: blocks} -> blocks_hashes = Enum.map(blocks, & &1.hash) query = @@ -97,7 +99,7 @@ defmodule Explorer.Chain.Import.Blocks do ] ) - {total, _} = Repo.update_all(query, []) + {total, _} = repo.update_all(query, []) {:ok, total} end @@ -109,6 +111,7 @@ defmodule Explorer.Chain.Import.Blocks do # sobelow_skip ["SQL.Query"] defp derive_transaction_forks(%{ + repo: repo, timeout: timeout, timestamps: %{inserted_at: inserted_at, updated_at: updated_at}, where_forked: where_forked @@ -124,7 +127,7 @@ defmodule Explorer.Chain.Import.Blocks do ] ) - {select_sql, parameters} = SQL.to_sql(:all, Repo, query) + {select_sql, parameters} = SQL.to_sql(:all, repo, query) insert_sql = """ INSERT INTO transaction_forks (uncle_hash, index, hash, inserted_at, updated_at) @@ -134,7 +137,7 @@ defmodule Explorer.Chain.Import.Blocks do with {:ok, %Postgrex.Result{columns: ["uncle_hash", "hash"], command: :insert, rows: rows}} <- SQL.query( - Repo, + repo, insert_sql, parameters, timeout: timeout @@ -145,7 +148,12 @@ defmodule Explorer.Chain.Import.Blocks do end end - defp fork_transactions(%{timeout: timeout, timestamps: %{updated_at: updated_at}, where_forked: where_forked}) do + defp fork_transactions(%{ + repo: repo, + timeout: timeout, + timestamps: %{updated_at: updated_at}, + where_forked: where_forked + }) do query = where_forked |> update( @@ -161,9 +169,10 @@ defmodule Explorer.Chain.Import.Blocks do updated_at: ^updated_at ] ) + |> select([:hash]) try do - {_, result} = Repo.update_all(query, [], timeout: timeout, returning: [:hash]) + {_, result} = repo.update_all(query, [], timeout: timeout) {:ok, result} rescue @@ -172,18 +181,19 @@ defmodule Explorer.Chain.Import.Blocks do end end - @spec insert([map()], %{ + @spec insert(Repo.t(), [map()], %{ optional(:on_conflict) => Import.Runner.on_conflict(), required(:timeout) => timeout, required(:timestamps) => Import.timestamps() }) :: {:ok, [Block.t()]} | {:error, [Changeset.t()]} - defp insert(changes_list, %{timeout: timeout, timestamps: timestamps} = options) when is_list(changes_list) do + defp insert(repo, changes_list, %{timeout: timeout, timestamps: timestamps} = options) when is_list(changes_list) do on_conflict = Map.get_lazy(options, :on_conflict, &default_on_conflict/0) # order so that row ShareLocks are grabbed in a consistent order ordered_changes_list = Enum.sort_by(changes_list, &{&1.number, &1.hash}) Import.insert_changes_list( + repo, ordered_changes_list, conflict_target: :hash, on_conflict: on_conflict, @@ -218,7 +228,7 @@ defmodule Explorer.Chain.Import.Blocks do ) end - defp lose_consensus(blocks_changes, %{timeout: timeout, timestamps: %{updated_at: updated_at}}) + defp lose_consensus(repo, blocks_changes, %{timeout: timeout, timestamps: %{updated_at: updated_at}}) when is_list(blocks_changes) do ordered_consensus_block_number = blocks_changes @@ -240,11 +250,12 @@ defmodule Explorer.Chain.Import.Blocks do consensus: false, updated_at: ^updated_at ] - ] + ], + select: [:hash, :number] ) try do - {_, result} = Repo.update_all(query, [], timeout: timeout, returning: [:hash, :number]) + {_, result} = repo.update_all(query, [], timeout: timeout) {:ok, result} rescue @@ -253,7 +264,7 @@ defmodule Explorer.Chain.Import.Blocks do end end - defp update_block_second_degree_relations(blocks, %{timeout: timeout, timestamps: %{updated_at: updated_at}}) + defp update_block_second_degree_relations(repo, blocks, %{timeout: timeout, timestamps: %{updated_at: updated_at}}) when is_list(blocks) do ordered_uncle_hashes = blocks @@ -272,7 +283,7 @@ defmodule Explorer.Chain.Import.Blocks do ) try do - {_, result} = Repo.update_all(query, [], timeout: timeout) + {_, result} = repo.update_all(query, [], timeout: timeout) {:ok, result} rescue diff --git a/apps/explorer/lib/explorer/chain/import/internal_transactions.ex b/apps/explorer/lib/explorer/chain/import/internal_transactions.ex index cf80852831..7e8ea25a92 100644 --- a/apps/explorer/lib/explorer/chain/import/internal_transactions.ex +++ b/apps/explorer/lib/explorer/chain/import/internal_transactions.ex @@ -5,9 +5,8 @@ defmodule Explorer.Chain.Import.InternalTransactions do require Ecto.Query - alias Ecto.{Changeset, Multi} + alias Ecto.{Changeset, Multi, Repo} alias Explorer.Chain.{Hash, Import, InternalTransaction, Transaction} - alias Explorer.Repo import Ecto.Query, only: [from: 2] @@ -48,26 +47,27 @@ defmodule Explorer.Chain.Import.InternalTransactions do update_transactions_options = %{timeout: transactions_timeout, timestamps: timestamps} multi - |> Multi.run(:internal_transactions, fn _ -> - insert(changes_list, insert_options) + |> Multi.run(:internal_transactions, fn repo, _ -> + insert(repo, changes_list, insert_options) end) - |> Multi.run(:internal_transactions_indexed_at_transactions, fn %{internal_transactions: internal_transactions} + |> Multi.run(:internal_transactions_indexed_at_transactions, fn repo, + %{internal_transactions: internal_transactions} when is_list(internal_transactions) -> - update_transactions(internal_transactions, update_transactions_options) + update_transactions(repo, internal_transactions, update_transactions_options) end) end @impl Import.Runner def timeout, do: @timeout - @spec insert([map], %{ + @spec insert(Repo.t(), [map], %{ optional(:on_conflict) => Import.Runner.on_conflict(), required(:timeout) => timeout, required(:timestamps) => Import.timestamps() }) :: {:ok, [%{index: non_neg_integer, transaction_hash: Hash.t()}]} | {:error, [Changeset.t()]} - defp insert(changes_list, %{timeout: timeout, timestamps: timestamps} = options) + defp insert(repo, changes_list, %{timeout: timeout, timestamps: timestamps} = options) when is_list(changes_list) do on_conflict = Map.get_lazy(options, :on_conflict, &default_on_conflict/0) @@ -76,6 +76,7 @@ defmodule Explorer.Chain.Import.InternalTransactions do {:ok, internal_transactions} = Import.insert_changes_list( + repo, ordered_changes_list, conflict_target: [:transaction_hash, :index], for: InternalTransaction, @@ -122,7 +123,7 @@ defmodule Explorer.Chain.Import.InternalTransactions do ) end - defp update_transactions(internal_transactions, %{ + defp update_transactions(repo, internal_transactions, %{ timeout: timeout, timestamps: timestamps }) @@ -164,7 +165,7 @@ defmodule Explorer.Chain.Import.InternalTransactions do transaction_count = Enum.count(ordered_transaction_hashes) try do - {^transaction_count, result} = Repo.update_all(query, [], timeout: timeout) + {^transaction_count, result} = repo.update_all(query, [], timeout: timeout) {:ok, result} rescue diff --git a/apps/explorer/lib/explorer/chain/import/logs.ex b/apps/explorer/lib/explorer/chain/import/logs.ex index 077bfd9c1e..438e00fc8e 100644 --- a/apps/explorer/lib/explorer/chain/import/logs.ex +++ b/apps/explorer/lib/explorer/chain/import/logs.ex @@ -5,7 +5,7 @@ defmodule Explorer.Chain.Import.Logs do require Ecto.Query - alias Ecto.{Changeset, Multi} + alias Ecto.{Changeset, Multi, Repo} alias Explorer.Chain.{Import, Log} import Ecto.Query, only: [from: 2] @@ -40,22 +40,22 @@ defmodule Explorer.Chain.Import.Logs do |> Map.put_new(:timeout, @timeout) |> Map.put(:timestamps, timestamps) - Multi.run(multi, :logs, fn _ -> - insert(changes_list, insert_options) + Multi.run(multi, :logs, fn repo, _ -> + insert(repo, changes_list, insert_options) end) end @impl Import.Runner def timeout, do: @timeout - @spec insert([map()], %{ + @spec insert(Repo.t(), [map()], %{ optional(:on_conflict) => Import.Runner.on_conflict(), required(:timeout) => timeout, required(:timestamps) => Import.timestamps() }) :: {:ok, [Log.t()]} | {:error, [Changeset.t()]} - defp insert(changes_list, %{timeout: timeout, timestamps: timestamps} = options) when is_list(changes_list) do + defp insert(repo, changes_list, %{timeout: timeout, timestamps: timestamps} = options) when is_list(changes_list) do on_conflict = Map.get_lazy(options, :on_conflict, &default_on_conflict/0) # order so that row ShareLocks are grabbed in a consistent order @@ -63,6 +63,7 @@ defmodule Explorer.Chain.Import.Logs do {:ok, _} = Import.insert_changes_list( + repo, ordered_changes_list, conflict_target: [:transaction_hash, :index], on_conflict: on_conflict, diff --git a/apps/explorer/lib/explorer/chain/import/token_transfers.ex b/apps/explorer/lib/explorer/chain/import/token_transfers.ex index 5fc622223e..afecbb7b97 100644 --- a/apps/explorer/lib/explorer/chain/import/token_transfers.ex +++ b/apps/explorer/lib/explorer/chain/import/token_transfers.ex @@ -7,7 +7,7 @@ defmodule Explorer.Chain.Import.TokenTransfers do import Ecto.Query, only: [from: 2] - alias Ecto.{Changeset, Multi} + alias Ecto.{Changeset, Multi, Repo} alias Explorer.Chain.{Import, TokenTransfer} @behaviour Import.Runner @@ -40,18 +40,18 @@ defmodule Explorer.Chain.Import.TokenTransfers do |> Map.put_new(:timeout, @timeout) |> Map.put(:timestamps, timestamps) - Multi.run(multi, :token_transfers, fn _ -> - insert(changes_list, insert_options) + Multi.run(multi, :token_transfers, fn repo, _ -> + insert(repo, changes_list, insert_options) end) end @impl Import.Runner def timeout, do: @timeout - @spec insert([map()], %{required(:timeout) => timeout(), required(:timestamps) => Import.timestamps()}) :: + @spec insert(Repo.t(), [map()], %{required(:timeout) => timeout(), required(:timestamps) => Import.timestamps()}) :: {:ok, [TokenTransfer.t()]} | {:error, [Changeset.t()]} - def insert(changes_list, %{timeout: timeout, timestamps: timestamps} = options) when is_list(changes_list) do + def insert(repo, changes_list, %{timeout: timeout, timestamps: timestamps} = options) when is_list(changes_list) do on_conflict = Map.get_lazy(options, :on_conflict, &default_on_conflict/0) # order so that row ShareLocks are grabbed in a consistent order @@ -59,6 +59,7 @@ defmodule Explorer.Chain.Import.TokenTransfers do {:ok, _} = Import.insert_changes_list( + repo, ordered_changes_list, conflict_target: [:transaction_hash, :log_index], on_conflict: on_conflict, diff --git a/apps/explorer/lib/explorer/chain/import/tokens.ex b/apps/explorer/lib/explorer/chain/import/tokens.ex index b400224aed..d377f50784 100644 --- a/apps/explorer/lib/explorer/chain/import/tokens.ex +++ b/apps/explorer/lib/explorer/chain/import/tokens.ex @@ -7,7 +7,7 @@ defmodule Explorer.Chain.Import.Tokens do import Ecto.Query, only: [from: 2] - alias Ecto.Multi + alias Ecto.{Multi, Repo} alias Explorer.Chain.{Import, Token} @behaviour Import.Runner @@ -40,26 +40,27 @@ defmodule Explorer.Chain.Import.Tokens do |> Map.put_new(:timeout, @timeout) |> Map.put(:timestamps, timestamps) - Multi.run(multi, :tokens, fn _ -> - insert(changes_list, insert_options) + Multi.run(multi, :tokens, fn repo, _ -> + insert(repo, changes_list, insert_options) end) end @impl Import.Runner def timeout, do: @timeout - @spec insert([map()], %{ + @spec insert(Repo.t(), [map()], %{ required(:on_conflict) => Import.Runner.on_conflict(), required(:timeout) => timeout(), required(:timestamps) => Import.timestamps() }) :: {:ok, [Token.t()]} - def insert(changes_list, %{timeout: timeout, timestamps: timestamps} = options) when is_list(changes_list) do + def insert(repo, changes_list, %{timeout: timeout, timestamps: timestamps} = options) when is_list(changes_list) do on_conflict = Map.get_lazy(options, :on_conflict, &default_on_conflict/0) # order so that row ShareLocks are grabbed in a consistent order ordered_changes_list = Enum.sort_by(changes_list, & &1.contract_address_hash) {:ok, _} = Import.insert_changes_list( + repo, ordered_changes_list, conflict_target: :contract_address_hash, on_conflict: on_conflict, diff --git a/apps/explorer/lib/explorer/chain/import/transaction/forks.ex b/apps/explorer/lib/explorer/chain/import/transaction/forks.ex index ce2ef782f7..b9571a39ab 100644 --- a/apps/explorer/lib/explorer/chain/import/transaction/forks.ex +++ b/apps/explorer/lib/explorer/chain/import/transaction/forks.ex @@ -7,7 +7,7 @@ defmodule Explorer.Chain.Import.Transaction.Forks do import Ecto.Query, only: [from: 2] - alias Ecto.Multi + alias Ecto.{Multi, Repo} alias Explorer.Chain.{Hash, Import, Transaction} @behaviour Import.Runner @@ -42,26 +42,27 @@ defmodule Explorer.Chain.Import.Transaction.Forks do |> Map.put_new(:timeout, @timeout) |> Map.put(:timestamps, timestamps) - Multi.run(multi, :transaction_forks, fn _ -> - insert(changes_list, insert_options) + Multi.run(multi, :transaction_forks, fn repo, _ -> + insert(repo, changes_list, insert_options) end) end @impl Import.Runner def timeout, do: @timeout - @spec insert([map()], %{ + @spec insert(Repo.t(), [map()], %{ optional(:on_conflict) => Import.Runner.on_conflict(), required(:timeout) => timeout, required(:timestamps) => Import.timestamps() }) :: {:ok, [%{uncle_hash: Hash.t(), hash: Hash.t()}]} - defp insert(changes_list, %{timeout: timeout, timestamps: timestamps} = options) when is_list(changes_list) do + defp insert(repo, changes_list, %{timeout: timeout, timestamps: timestamps} = options) when is_list(changes_list) do on_conflict = Map.get_lazy(options, :on_conflict, &default_on_conflict/0) # order so that row ShareLocks are grabbed in a consistent order ordered_changes_list = Enum.sort_by(changes_list, &{&1.uncle_hash, &1.hash}) Import.insert_changes_list( + repo, ordered_changes_list, conflict_target: [:uncle_hash, :index], on_conflict: on_conflict, diff --git a/apps/explorer/lib/explorer/chain/import/transactions.ex b/apps/explorer/lib/explorer/chain/import/transactions.ex index a1d788e6ae..3c8fb83e77 100644 --- a/apps/explorer/lib/explorer/chain/import/transactions.ex +++ b/apps/explorer/lib/explorer/chain/import/transactions.ex @@ -7,7 +7,7 @@ defmodule Explorer.Chain.Import.Transactions do import Ecto.Query, only: [from: 2] - alias Ecto.Multi + alias Ecto.{Multi, Repo} alias Explorer.Chain.{Hash, Import, Transaction} @behaviour Import.Runner @@ -40,20 +40,20 @@ defmodule Explorer.Chain.Import.Transactions do |> Map.put_new(:timeout, @timeout) |> Map.put(:timestamps, timestamps) - Multi.run(multi, :transactions, fn _ -> - insert(changes_list, insert_options) + Multi.run(multi, :transactions, fn repo, _ -> + insert(repo, changes_list, insert_options) end) end @impl Import.Runner def timeout, do: @timeout - @spec insert([map()], %{ + @spec insert(Repo.t(), [map()], %{ optional(:on_conflict) => Import.Runner.on_conflict(), required(:timeout) => timeout, required(:timestamps) => Import.timestamps() }) :: {:ok, [Hash.t()]} - defp insert(changes_list, %{timeout: timeout, timestamps: timestamps} = options) + defp insert(repo, changes_list, %{timeout: timeout, timestamps: timestamps} = options) when is_list(changes_list) do on_conflict = Map.get_lazy(options, :on_conflict, &default_on_conflict/0) @@ -62,6 +62,7 @@ defmodule Explorer.Chain.Import.Transactions do {:ok, transactions} = Import.insert_changes_list( + repo, ordered_changes_list, conflict_target: :hash, on_conflict: on_conflict, diff --git a/apps/explorer/lib/explorer/chain/token.ex b/apps/explorer/lib/explorer/chain/token.ex index 22ba6d2504..65a03caf52 100644 --- a/apps/explorer/lib/explorer/chain/token.ex +++ b/apps/explorer/lib/explorer/chain/token.ex @@ -17,7 +17,7 @@ defmodule Explorer.Chain.Token do * [ERC-1155](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1155.md) """ - use Ecto.Schema + use Explorer.Schema import Ecto.{Changeset, Query} diff --git a/apps/explorer/lib/explorer/chain/token_transfer.ex b/apps/explorer/lib/explorer/chain/token_transfer.ex index 65ecc2332b..c7fe0bc867 100644 --- a/apps/explorer/lib/explorer/chain/token_transfer.ex +++ b/apps/explorer/lib/explorer/chain/token_transfer.ex @@ -22,7 +22,7 @@ defmodule Explorer.Chain.TokenTransfer do | `:index` | `:log_index` | Index of log in transaction | """ - use Ecto.Schema + use Explorer.Schema import Ecto.Changeset import Ecto.Query, only: [from: 2, limit: 2, where: 3] diff --git a/apps/explorer/lib/explorer/chain/transaction.ex b/apps/explorer/lib/explorer/chain/transaction.ex index 5ba65a5b43..19a80baa27 100644 --- a/apps/explorer/lib/explorer/chain/transaction.ex +++ b/apps/explorer/lib/explorer/chain/transaction.ex @@ -151,7 +151,7 @@ defmodule Explorer.Chain.Transaction do field(:gas_price, Wei) field(:gas_used, :decimal) field(:index, :integer) - field(:internal_transactions_indexed_at, :utc_datetime) + field(:internal_transactions_indexed_at, :utc_datetime_usec) field(:input, Data) field(:nonce, :integer) field(:r, :decimal) diff --git a/apps/explorer/lib/explorer/counters/addresses_with_balance_counter.ex b/apps/explorer/lib/explorer/counters/addresses_with_balance_counter.ex index 914df2301f..adbeb6e6f2 100644 --- a/apps/explorer/lib/explorer/counters/addresses_with_balance_counter.ex +++ b/apps/explorer/lib/explorer/counters/addresses_with_balance_counter.ex @@ -1,4 +1,4 @@ -defmodule Explorer.Counters.AddessesWithBalanceCounter do +defmodule Explorer.Counters.AddressesWithBalanceCounter do @moduledoc """ Caches the number of addresses with fetched coin balance > 0. @@ -26,7 +26,7 @@ defmodule Explorer.Counters.AddessesWithBalanceCounter do # finish before a test ends, that test will fail. This way, hundreds of # tests were failing before disabling the consolidation and the scheduler in # the test env. - config = Application.get_env(:explorer, Explorer.Counters.AddessesWithBalanceCounter) + config = Application.get_env(:explorer, Explorer.Counters.AddressesWithBalanceCounter) @enable_consolidation Keyword.get(config, :enable_consolidation) @doc """ diff --git a/apps/explorer/lib/explorer/counters/token_transfer_counter.ex b/apps/explorer/lib/explorer/counters/token_transfer_counter.ex index e165023ed5..6cbf267abe 100644 --- a/apps/explorer/lib/explorer/counters/token_transfer_counter.ex +++ b/apps/explorer/lib/explorer/counters/token_transfer_counter.ex @@ -11,6 +11,27 @@ defmodule Explorer.Counters.TokenTransferCounter do @table :token_transfer_counter + # It is undesirable to automatically start the consolidation in all environments. + # Consider the test environment: if the consolidation initiates but does not + # finish before a test ends, that test will fail. This way, hundreds of + # tests were failing before disabling the consolidation and the scheduler in + # the test env. + config = Application.get_env(:explorer, Explorer.Counters.TokenHoldersCounter) + @enable_consolidation Keyword.get(config, :enable_consolidation) + + @doc """ + Returns a boolean that indicates whether consolidation is enabled + + In order to choose whether or not to enable the initial consolidation, change the following Explorer config: + + `config :explorer, Explorer.Counters.TokenTransferCounter, enable_consolidation: true` + + to: + + `config :explorer, Explorer.Counters.TokenTransferCounter, enable_consolidation: false` + """ + def enable_consolidation?, do: @enable_consolidation + def table_name do @table end @@ -28,7 +49,9 @@ defmodule Explorer.Counters.TokenTransferCounter do def init(args) do create_table() - Task.start_link(&consolidate/0) + if enable_consolidation?() do + Task.start_link(&consolidate/0) + end Chain.subscribe_to_events(:token_transfers) diff --git a/apps/explorer/lib/explorer/exchange_rates/source.ex b/apps/explorer/lib/explorer/exchange_rates/source.ex index 30255815e9..7401d27a0d 100644 --- a/apps/explorer/lib/explorer/exchange_rates/source.ex +++ b/apps/explorer/lib/explorer/exchange_rates/source.ex @@ -43,7 +43,11 @@ defmodule Explorer.ExchangeRates.Source do def to_decimal(nil), do: nil - def to_decimal(value) do + def to_decimal(value) when is_float(value) do + Decimal.from_float(value) + end + + def to_decimal(value) when is_integer(value) or is_binary(value) do Decimal.new(value) end diff --git a/apps/explorer/lib/explorer/market/history/source/crypto_compare.ex b/apps/explorer/lib/explorer/market/history/source/crypto_compare.ex index 06c196d24e..82bf3714d5 100644 --- a/apps/explorer/lib/explorer/market/history/source/crypto_compare.ex +++ b/apps/explorer/lib/explorer/market/history/source/crypto_compare.ex @@ -50,9 +50,9 @@ defmodule Explorer.Market.History.Source.CryptoCompare do for item <- json["Data"] do %{ - closing_price: Decimal.new(item["close"]), + closing_price: Decimal.new(to_string(item["close"])), date: date(item["time"]), - opening_price: Decimal.new(item["open"]) + opening_price: Decimal.new(to_string(item["open"])) } end end diff --git a/apps/explorer/lib/explorer/market/market_history.ex b/apps/explorer/lib/explorer/market/market_history.ex index deb00d00f9..10850177b7 100644 --- a/apps/explorer/lib/explorer/market/market_history.ex +++ b/apps/explorer/lib/explorer/market/market_history.ex @@ -2,7 +2,8 @@ defmodule Explorer.Market.MarketHistory do @moduledoc """ Represents market history of configured coin to USD. """ - use Ecto.Schema + + use Explorer.Schema schema "market_history" do field(:closing_price, :decimal) diff --git a/apps/explorer/lib/explorer/repo.ex b/apps/explorer/lib/explorer/repo.ex index e5fb373f3f..90bb70cdcd 100644 --- a/apps/explorer/lib/explorer/repo.ex +++ b/apps/explorer/lib/explorer/repo.ex @@ -1,5 +1,7 @@ defmodule Explorer.Repo do - use Ecto.Repo, otp_app: :explorer + use Ecto.Repo, + otp_app: :explorer, + adapter: Ecto.Adapters.Postgres require Logger diff --git a/apps/explorer/lib/explorer/schema.ex b/apps/explorer/lib/explorer/schema.ex index 68ae7ef8d4..b59631550f 100644 --- a/apps/explorer/lib/explorer/schema.ex +++ b/apps/explorer/lib/explorer/schema.ex @@ -7,10 +7,7 @@ defmodule Explorer.Schema do import Ecto.{Changeset, Query} - @timestamps_opts [ - type: :utc_datetime, - usec: true - ] + @timestamps_opts [type: :utc_datetime_usec] end end end diff --git a/apps/explorer/mix.exs b/apps/explorer/mix.exs index e7b0a6263f..8fd71cabf6 100644 --- a/apps/explorer/mix.exs +++ b/apps/explorer/mix.exs @@ -71,8 +71,10 @@ defmodule Explorer.Mixfile do {:dataloader, "~> 1.0.0"}, {:decimal, "~> 1.0"}, {:dialyxir, "~> 0.5", only: [:dev, :test], runtime: false}, - # Casting Ethereum-native types to Elixir-native types - {:ecto, "~> 2.2"}, + # `override: true` for `ex_machina` compatibility + {:ecto, "~> 3.0", override: true}, + # Storing blockchain data and derived data in PostgreSQL. + {:ecto_sql, "~> 3.0"}, # JSONRPC access to query smart contracts {:ethereum_jsonrpc, in_umbrella: true}, # Data factory for testing @@ -92,7 +94,12 @@ defmodule Explorer.Mixfile do # For compatibility with `prometheus_process_collector`, which hasn't been updated yet {:prometheus, "~> 4.0", override: true}, # Prometheus metrics for query duration - {:prometheus_ecto, "~> 1.3"}, + { + :prometheus_ecto, + "~> 1.3", + # Ecto 3.0 compatibility + github: "deadtrickster/prometheus-ecto", ref: "650a403183f6a2fb6b682d7fbcba8bf9d24fe1e4" + }, # bypass optional dependency {:plug_cowboy, "~> 1.0", only: :test}, {:sobelow, ">= 0.7.0", only: [:dev, :test], runtime: false}, @@ -102,9 +109,10 @@ defmodule Explorer.Mixfile do {:spandex_datadog, "~> 0.3.1"}, # `:spandex` tracing of `:ecto` {:spandex_ecto, "~> 0.4.0"}, - {:timex, "~> 3.4"}, + # Attach `:prometheus_ecto` to `:ecto` + {:telemetry, "~> 0.2.0"}, # `Timex.Duration` for `Explorer.Chain.average_block_time/0` - {:timex_ecto, "~> 3.3"} + {:timex, "~> 3.4"} ] end diff --git a/apps/explorer/priv/repo/migrations/20180117221921_create_address.exs b/apps/explorer/priv/repo/migrations/20180117221921_create_address.exs index 7216bd338e..aabe0d9369 100644 --- a/apps/explorer/priv/repo/migrations/20180117221921_create_address.exs +++ b/apps/explorer/priv/repo/migrations/20180117221921_create_address.exs @@ -8,7 +8,7 @@ defmodule Explorer.Repo.Migrations.CreateAddress do add(:hash, :bytea, null: false, primary_key: true) add(:contract_code, :bytea, null: true) - timestamps(null: false, type: :utc_datetime) + timestamps(null: false, type: :utc_datetime_usec) end end end diff --git a/apps/explorer/priv/repo/migrations/20180117221922_create_blocks.exs b/apps/explorer/priv/repo/migrations/20180117221922_create_blocks.exs index faacee0d13..b9157dc9a4 100644 --- a/apps/explorer/priv/repo/migrations/20180117221922_create_blocks.exs +++ b/apps/explorer/priv/repo/migrations/20180117221922_create_blocks.exs @@ -16,10 +16,10 @@ defmodule Explorer.Repo.Migrations.CreateBlocks do add(:parent_hash, :bytea, null: false) add(:size, :integer, null: false) - add(:timestamp, :utc_datetime, null: false) + add(:timestamp, :utc_datetime_usec, null: false) add(:total_difficulty, :numeric, precision: 50) - timestamps(null: false, type: :utc_datetime) + timestamps(null: false, type: :utc_datetime_usec) end create(index(:blocks, [:timestamp])) diff --git a/apps/explorer/priv/repo/migrations/20180117221923_create_transactions.exs b/apps/explorer/priv/repo/migrations/20180117221923_create_transactions.exs index 50d2b72c80..92dc197f37 100644 --- a/apps/explorer/priv/repo/migrations/20180117221923_create_transactions.exs +++ b/apps/explorer/priv/repo/migrations/20180117221923_create_transactions.exs @@ -23,7 +23,7 @@ defmodule Explorer.Repo.Migrations.CreateTransactions do add(:input, :bytea, null: false) # `null` when `internal_transactions` has never been fetched - add(:internal_transactions_indexed_at, :utc_datetime, null: true) + add(:internal_transactions_indexed_at, :utc_datetime_usec, null: true) add(:nonce, :integer, null: false) add(:r, :numeric, precision: 100, null: false) @@ -35,7 +35,7 @@ defmodule Explorer.Repo.Migrations.CreateTransactions do add(:v, :integer, null: false) add(:value, :numeric, precision: 100, null: false) - timestamps(null: false, type: :utc_datetime) + timestamps(null: false, type: :utc_datetime_usec) # `null` when a pending transaction add(:block_hash, references(:blocks, column: :hash, on_delete: :delete_all, type: :bytea), null: true) diff --git a/apps/explorer/priv/repo/migrations/20180212222309_create_logs.exs b/apps/explorer/priv/repo/migrations/20180212222309_create_logs.exs index 738ec2c786..b6dc879204 100644 --- a/apps/explorer/priv/repo/migrations/20180212222309_create_logs.exs +++ b/apps/explorer/priv/repo/migrations/20180212222309_create_logs.exs @@ -14,7 +14,7 @@ defmodule Explorer.Repo.Migrations.CreateLogs do add(:third_topic, :string, null: true) add(:fourth_topic, :string, null: true) - timestamps(null: false, type: :utc_datetime) + timestamps(null: false, type: :utc_datetime_usec) add(:address_hash, references(:addresses, column: :hash, on_delete: :delete_all, type: :bytea), null: true) diff --git a/apps/explorer/priv/repo/migrations/20180221001948_create_internal_transactions.exs b/apps/explorer/priv/repo/migrations/20180221001948_create_internal_transactions.exs index 8a9c4bf276..cb7c64c7c2 100644 --- a/apps/explorer/priv/repo/migrations/20180221001948_create_internal_transactions.exs +++ b/apps/explorer/priv/repo/migrations/20180221001948_create_internal_transactions.exs @@ -21,7 +21,7 @@ defmodule Explorer.Repo.Migrations.CreateInternalTransactions do add(:type, :string, null: false) add(:value, :numeric, precision: 100, null: false) - timestamps(null: false, type: :utc_datetime) + timestamps(null: false, type: :utc_datetime_usec) # Nullability controlled by create_has_created constraint below add(:created_contract_address_hash, references(:addresses, column: :hash, type: :bytea), null: true) diff --git a/apps/explorer/priv/repo/migrations/20180717204948_create_address_coin_balances.exs b/apps/explorer/priv/repo/migrations/20180717204948_create_address_coin_balances.exs index a62ab70b17..7001f3b8b0 100644 --- a/apps/explorer/priv/repo/migrations/20180717204948_create_address_coin_balances.exs +++ b/apps/explorer/priv/repo/migrations/20180717204948_create_address_coin_balances.exs @@ -8,9 +8,9 @@ defmodule Explorer.Repo.Migrations.CreateCoinBalances do # null until fetched add(:value, :numeric, precision: 100, default: fragment("NULL"), null: true) - add(:value_fetched_at, :utc_datetime, default: fragment("NULL"), null: true) + add(:value_fetched_at, :utc_datetime_usec, default: fragment("NULL"), null: true) - timestamps(null: false, type: :utc_datetime) + timestamps(null: false, type: :utc_datetime_usec) end create(unique_index(:address_coin_balances, [:address_hash, :block_number])) diff --git a/apps/explorer/priv/repo/migrations/20180817021704_create_address_token_balances.exs b/apps/explorer/priv/repo/migrations/20180817021704_create_address_token_balances.exs index 9a73ed7e3e..94902f5593 100644 --- a/apps/explorer/priv/repo/migrations/20180817021704_create_address_token_balances.exs +++ b/apps/explorer/priv/repo/migrations/20180817021704_create_address_token_balances.exs @@ -13,9 +13,9 @@ defmodule Explorer.Repo.Migrations.CreateAddressTokenBalances do ) add(:value, :decimal, null: true) - add(:value_fetched_at, :utc_datetime, default: fragment("NULL"), null: true) + add(:value_fetched_at, :utc_datetime_usec, default: fragment("NULL"), null: true) - timestamps(null: false, type: :utc_datetime) + timestamps(null: false, type: :utc_datetime_usec) end create(unique_index(:address_token_balances, ~w(address_hash token_contract_address_hash block_number)a)) diff --git a/apps/explorer/priv/repo/migrations/20180917182319_create_block_second_degree_relations.exs b/apps/explorer/priv/repo/migrations/20180917182319_create_block_second_degree_relations.exs index b6477a3aae..ed77cdb309 100644 --- a/apps/explorer/priv/repo/migrations/20180917182319_create_block_second_degree_relations.exs +++ b/apps/explorer/priv/repo/migrations/20180917182319_create_block_second_degree_relations.exs @@ -5,7 +5,7 @@ defmodule Explorer.Repo.Migrations.CreateBlockSecondDegreeRelations do create table(:block_second_degree_relations, primary_key: false) do add(:nephew_hash, references(:blocks, column: :hash, type: :bytea), null: false) add(:uncle_hash, :bytea, null: false) - add(:uncle_fetched_at, :utc_datetime, default: fragment("NULL"), null: true) + add(:uncle_fetched_at, :utc_datetime_usec, default: fragment("NULL"), null: true) end create(unique_index(:block_second_degree_relations, [:nephew_hash, :uncle_hash], name: :nephew_hash_to_uncle_hash)) diff --git a/apps/explorer/priv/repo/migrations/20181026180921_create_address_current_token_balances.exs b/apps/explorer/priv/repo/migrations/20181026180921_create_address_current_token_balances.exs index d497d1feda..f2fb477a2a 100644 --- a/apps/explorer/priv/repo/migrations/20181026180921_create_address_current_token_balances.exs +++ b/apps/explorer/priv/repo/migrations/20181026180921_create_address_current_token_balances.exs @@ -13,9 +13,9 @@ defmodule Explorer.Repo.Migrations.CreateAddressCurrentTokenBalances do ) add(:value, :decimal, null: true) - add(:value_fetched_at, :utc_datetime, default: fragment("NULL"), null: true) + add(:value_fetched_at, :utc_datetime_usec, default: fragment("NULL"), null: true) - timestamps(null: false, type: :utc_datetime) + timestamps(null: false, type: :utc_datetime_usec) end create(unique_index(:address_current_token_balances, ~w(address_hash token_contract_address_hash)a)) diff --git a/apps/explorer/test/explorer/chain/address/coin_balance_test.exs b/apps/explorer/test/explorer/chain/address/coin_balance_test.exs index 28de26433a..87ed80a94c 100644 --- a/apps/explorer/test/explorer/chain/address/coin_balance_test.exs +++ b/apps/explorer/test/explorer/chain/address/coin_balance_test.exs @@ -2,8 +2,8 @@ defmodule Explorer.Chain.Address.CoinBalanceTest do use Explorer.DataCase alias Ecto.Changeset + alias Explorer.Chain.{Block, Wei} alias Explorer.Chain.Address.CoinBalance - alias Explorer.Chain.Wei alias Explorer.PagingOptions describe "changeset/2" do @@ -183,7 +183,7 @@ defmodule Explorer.Chain.Address.CoinBalanceTest do test "returns dates at midnight" do address = insert(:address) noon = Timex.now() |> Timex.beginning_of_day() |> Timex.set(hour: 12) - block = insert(:block, timestamp: noon) + block = %Block{timestamp: noon_with_usec} = insert(:block, timestamp: noon) block_one_day_ago = insert(:block, timestamp: Timex.shift(noon, days: -1)) insert(:fetched_balance, address_hash: address.hash, value: 1000, block_number: block.number) insert(:fetched_balance, address_hash: address.hash, value: 2000, block_number: block_one_day_ago.number) @@ -195,13 +195,17 @@ defmodule Explorer.Chain.Address.CoinBalanceTest do assert(length(result) == 2) - dates = result |> Enum.map(& &1.date) |> Enum.map(&Ecto.DateTime.cast!/1) + dates = Enum.map(result, & &1.date) - today = Timex.beginning_of_day(noon) + today = Timex.beginning_of_day(noon_with_usec) yesterday = today |> Timex.shift(days: -1) - expected_dates = [yesterday, today] |> Enum.map(&Ecto.DateTime.cast!/1) + expected_dates = Enum.map([yesterday, today], &DateTime.to_date/1) - assert(dates == expected_dates) + dates + |> Stream.zip(expected_dates) + |> Enum.each(fn {date, expected_date} -> + assert Date.compare(date, expected_date) == :eq + end) end test "gets the max value of the day (value is at the beginning)" do diff --git a/apps/explorer/test/explorer/chain/block_test.exs b/apps/explorer/test/explorer/chain/block_test.exs index 90baac8657..5f6bfc426e 100644 --- a/apps/explorer/test/explorer/chain/block_test.exs +++ b/apps/explorer/test/explorer/chain/block_test.exs @@ -20,31 +20,26 @@ defmodule Explorer.Chain.BlockTest do test "with duplicate information" do %Block{hash: hash, miner_hash: miner_hash} = insert(:block) - assert {:error, %Changeset{errors: errors, valid?: false}} = + assert {:error, %Changeset{valid?: false, errors: [hash: {"has already been taken", _}]}} = %Block{} |> Block.changeset(params_for(:block, hash: hash, miner_hash: miner_hash)) |> Repo.insert() - - assert errors == [hash: {"has already been taken", []}] end test "rejects duplicate blocks with mixed case" do %Block{miner_hash: miner_hash} = insert(:block, hash: "0xef95f2f1ed3ca60b048b4bf67cde2195961e0bba6f70bcbea9a2c4e133e34b46") - {:error, changeset} = - %Block{} - |> Block.changeset( - params_for( - :block, - hash: "0xeF95f2f1ed3ca60b048b4bf67cde2195961e0bba6f70bcbea9a2c4e133e34b46", - miner_hash: miner_hash - ) - ) - |> Repo.insert() - - refute changeset.valid? - assert changeset.errors == [hash: {"has already been taken", []}] + assert {:error, %Changeset{valid?: false, errors: [hash: {"has already been taken", _}]}} = + %Block{} + |> Block.changeset( + params_for( + :block, + hash: "0xeF95f2f1ed3ca60b048b4bf67cde2195961e0bba6f70bcbea9a2c4e133e34b46", + miner_hash: miner_hash + ) + ) + |> Repo.insert() end end end diff --git a/apps/explorer/test/explorer/chain/import/address/address/current_token_balances_test.exs b/apps/explorer/test/explorer/chain/import/address/address/current_token_balances_test.exs index a78b7046ef..b9e89c92ec 100644 --- a/apps/explorer/test/explorer/chain/import/address/address/current_token_balances_test.exs +++ b/apps/explorer/test/explorer/chain/import/address/address/current_token_balances_test.exs @@ -1,9 +1,9 @@ defmodule Explorer.Chain.Import.Address.CurrentTokenBalancesTest do use Explorer.DataCase + alias Explorer.Chain.Address.CurrentTokenBalance alias Explorer.Chain.Import.Address.CurrentTokenBalances - - alias Explorer.Chain.{Address.CurrentTokenBalance} + alias Explorer.Repo describe "insert/2" do setup do @@ -28,11 +28,11 @@ defmodule Explorer.Chain.Import.Address.CurrentTokenBalancesTest do } ] - CurrentTokenBalances.insert(changes, insert_options) + CurrentTokenBalances.insert(Repo, changes, insert_options) current_token_balances = CurrentTokenBalance - |> Explorer.Repo.all() + |> Repo.all() |> Enum.count() assert current_token_balances == 1 @@ -56,9 +56,9 @@ defmodule Explorer.Chain.Import.Address.CurrentTokenBalancesTest do } ] - CurrentTokenBalances.insert(changes, insert_options) + CurrentTokenBalances.insert(Repo, changes, insert_options) - current_token_balance = Explorer.Repo.get_by(CurrentTokenBalance, address_hash: address.hash) + current_token_balance = Repo.get_by(CurrentTokenBalance, address_hash: address.hash) assert current_token_balance.block_number == 2 assert current_token_balance.value == Decimal.new(200) @@ -84,9 +84,9 @@ defmodule Explorer.Chain.Import.Address.CurrentTokenBalancesTest do } ] - CurrentTokenBalances.insert(changes, insert_options) + CurrentTokenBalances.insert(Repo, changes, insert_options) - current_token_balance = Explorer.Repo.get_by(CurrentTokenBalance, address_hash: address.hash) + current_token_balance = Repo.get_by(CurrentTokenBalance, address_hash: address.hash) assert current_token_balance.block_number == 4 assert current_token_balance.value == Decimal.new(200) diff --git a/apps/explorer/test/explorer/chain/transaction/fork_test.exs b/apps/explorer/test/explorer/chain/transaction/fork_test.exs index d5028af6ab..f0ad0b1c43 100644 --- a/apps/explorer/test/explorer/chain/transaction/fork_test.exs +++ b/apps/explorer/test/explorer/chain/transaction/fork_test.exs @@ -9,7 +9,7 @@ defmodule Explorer.Chain.Transaction.ForkTest do test "a transaction fork cannot be inserted if the corresponding transaction does not exist" do assert %Changeset{valid?: true} = changeset = Fork.changeset(%Fork{}, params_for(:transaction_fork)) - assert {:error, %Changeset{errors: [transaction: {"does not exist", []}]}} = Repo.insert(changeset) + assert {:error, %Changeset{errors: [transaction: {"does not exist", _}]}} = Repo.insert(changeset) end test "a transaction fork cannot be inserted if the corresponding uncle does not exist" do @@ -18,6 +18,6 @@ defmodule Explorer.Chain.Transaction.ForkTest do assert %Changeset{valid?: true} = changeset = Fork.changeset(%Fork{}, %{hash: transaction.hash, index: 0, uncle_hash: block_hash()}) - assert {:error, %Changeset{errors: [uncle: {"does not exist", []}]}} = Repo.insert(changeset) + assert {:error, %Changeset{errors: [uncle: {"does not exist", _}]}} = Repo.insert(changeset) end end diff --git a/apps/explorer/test/explorer/chain_test.exs b/apps/explorer/test/explorer/chain_test.exs index c3cfcb2e42..c102ba7e64 100644 --- a/apps/explorer/test/explorer/chain_test.exs +++ b/apps/explorer/test/explorer/chain_test.exs @@ -24,7 +24,7 @@ defmodule Explorer.ChainTest do alias Explorer.Chain.Supply.ProofOfAuthority - alias Explorer.Counters.{AddessesWithBalanceCounter, TokenHoldersCounter} + alias Explorer.Counters.{AddressesWithBalanceCounter, TokenHoldersCounter} doctest Explorer.Chain @@ -34,7 +34,8 @@ defmodule Explorer.ChainTest do insert(:address, fetched_coin_balance: 1) insert(:address, fetched_coin_balance: 2) - AddessesWithBalanceCounter.consolidate() + start_supervised!(AddressesWithBalanceCounter) + AddressesWithBalanceCounter.consolidate() addresses_with_balance = Chain.count_addresses_with_balance_from_cache() @@ -3002,6 +3003,7 @@ defmodule Explorer.ChainTest do value: 1000 ) + start_supervised!(TokenHoldersCounter) TokenHoldersCounter.consolidate() assert Chain.count_token_holders_from_token_hash(contract_address_hash) == 2 diff --git a/apps/explorer/test/explorer/counters/addresses_with_balance_counter_test.exs b/apps/explorer/test/explorer/counters/addresses_with_balance_counter_test.exs index e9ce98b42c..127c447969 100644 --- a/apps/explorer/test/explorer/counters/addresses_with_balance_counter_test.exs +++ b/apps/explorer/test/explorer/counters/addresses_with_balance_counter_test.exs @@ -1,15 +1,16 @@ -defmodule Explorer.Counters.AddessesWithBalanceCounterTest do +defmodule Explorer.Counters.AddressesWithBalanceCounterTest do use Explorer.DataCase - alias Explorer.Counters.AddessesWithBalanceCounter + alias Explorer.Counters.AddressesWithBalanceCounter test "populates the cache with the number of addresses with fetched coin balance greater than 0" do insert(:address, fetched_coin_balance: 0) insert(:address, fetched_coin_balance: 1) insert(:address, fetched_coin_balance: 2) - AddessesWithBalanceCounter.consolidate() + start_supervised!(AddressesWithBalanceCounter) + AddressesWithBalanceCounter.consolidate() - assert AddessesWithBalanceCounter.fetch() == 2 + assert AddressesWithBalanceCounter.fetch() == 2 end end diff --git a/apps/explorer/test/explorer/counters/block_validation_counter_test.exs b/apps/explorer/test/explorer/counters/block_validation_counter_test.exs index 28f54f1c05..ac1345e2a8 100644 --- a/apps/explorer/test/explorer/counters/block_validation_counter_test.exs +++ b/apps/explorer/test/explorer/counters/block_validation_counter_test.exs @@ -3,6 +3,12 @@ defmodule Explorer.Counters.BlockValidationCounterTest do alias Explorer.Counters.BlockValidationCounter + setup do + start_supervised!(BlockValidationCounter) + + :ok + end + describe "consolidate/0" do test "loads the address' validations consolidated info" do address = insert(:address) diff --git a/apps/explorer/test/explorer/counters/token_holders_counter_test.exs b/apps/explorer/test/explorer/counters/token_holders_counter_test.exs index beaa05b136..8f1e584676 100644 --- a/apps/explorer/test/explorer/counters/token_holders_counter_test.exs +++ b/apps/explorer/test/explorer/counters/token_holders_counter_test.exs @@ -4,6 +4,12 @@ defmodule Explorer.Counters.TokenHoldersCounterTest do alias Explorer.Chain.Token alias Explorer.Counters.TokenHoldersCounter + setup do + start_supervised!(TokenHoldersCounter) + + :ok + end + describe "consolidate/0" do test "consolidates the token holders info with the most current database info" do address_a = insert(:address, hash: "0xe49fedd93960a0267b3c3b2c1e2d66028e013fee") diff --git a/apps/explorer/test/explorer/counters/token_transfer_counter_test.exs b/apps/explorer/test/explorer/counters/token_transfer_counter_test.exs index c5ba0d1fb1..3378b69553 100644 --- a/apps/explorer/test/explorer/counters/token_transfer_counter_test.exs +++ b/apps/explorer/test/explorer/counters/token_transfer_counter_test.exs @@ -3,6 +3,12 @@ defmodule Explorer.Counters.TokenTransferCounterTest do alias Explorer.Counters.TokenTransferCounter + setup do + start_supervised!(TokenTransferCounter) + + :ok + end + describe "consolidate/0" do test "loads the token's transfers consolidate info" do token_contract_address = insert(:contract_address) @@ -36,7 +42,7 @@ defmodule Explorer.Counters.TokenTransferCounterTest do end describe "fetch/1" do - test "fetchs the total token transfers by token contract address hash" do + test "fetches the total token transfers by token contract address hash" do token_contract_address = insert(:contract_address) token = insert(:token, contract_address: token_contract_address) diff --git a/apps/explorer/test/explorer/market/history/source/crypto_compare_test.exs b/apps/explorer/test/explorer/market/history/source/crypto_compare_test.exs index 7b29c84a9f..9b662549c2 100644 --- a/apps/explorer/test/explorer/market/history/source/crypto_compare_test.exs +++ b/apps/explorer/test/explorer/market/history/source/crypto_compare_test.exs @@ -61,19 +61,19 @@ defmodule Explorer.Market.History.Source.CryptoCompareTest do expected = [ %{ - closing_price: Decimal.new(9655.77), + closing_price: Decimal.from_float(9655.77), date: ~D[2018-04-24], - opening_price: Decimal.new(8967.86) + opening_price: Decimal.from_float(8967.86) }, %{ - closing_price: Decimal.new(8873.62), + closing_price: Decimal.from_float(8873.62), date: ~D[2018-04-25], - opening_price: Decimal.new(9657.69) + opening_price: Decimal.from_float(9657.69) }, %{ - closing_price: Decimal.new(8804.32), + closing_price: Decimal.from_float(8804.32), date: ~D[2018-04-26], - opening_price: Decimal.new(8873.57) + opening_price: Decimal.from_float(8873.57) } ] diff --git a/apps/explorer/test/explorer/repo_test.exs b/apps/explorer/test/explorer/repo_test.exs index 81e3325a70..e761bdfd23 100644 --- a/apps/explorer/test/explorer/repo_test.exs +++ b/apps/explorer/test/explorer/repo_test.exs @@ -45,7 +45,7 @@ defmodule Explorer.RepoTest do assert log =~ "Options:\n\n[conflict_target: [:transaction_hash, :index], on_conflict: :replace_all]\n\n" assert log =~ - "Exception:\n\n** (Postgrex.Error) ERROR 21000 (cardinality_violation): ON CONFLICT DO UPDATE command cannot affect row a second time\n" + "Exception:\n\n** (Postgrex.Error) ERROR 21000 (cardinality_violation) ON CONFLICT DO UPDATE command cannot affect row a second time\n" end end end diff --git a/apps/explorer/test/support/data_case.ex b/apps/explorer/test/support/data_case.ex index 807a8c9da6..4f775ef3d4 100644 --- a/apps/explorer/test/support/data_case.ex +++ b/apps/explorer/test/support/data_case.ex @@ -45,18 +45,7 @@ defmodule Explorer.DataCase do def wait_for_results(producer) do producer.() rescue - Ecto.NoResultsError -> - Process.sleep(100) - wait_for_results(producer) - catch - :exit, - {:timeout, - {GenServer, :call, - [ - _, - {:checkout, _, _, _}, - _ - ]}} -> + [DBConnection.ConnectionError, Ecto.NoResultsError] -> Process.sleep(100) wait_for_results(producer) end diff --git a/apps/explorer/test/support/factory.ex b/apps/explorer/test/support/factory.ex index 5781ca16c5..4572797e65 100644 --- a/apps/explorer/test/support/factory.ex +++ b/apps/explorer/test/support/factory.ex @@ -512,18 +512,6 @@ defmodule Explorer.Factory do } end - defmacrop left + right do - quote do - fragment("? + ?", unquote(left), unquote(right)) - end - end - - defmacrop coalesce(left, right) do - quote do - fragment("coalesce(?, ?)", unquote(left), unquote(right)) - end - end - defp block_hash_to_next_transaction_index(block_hash) do import Kernel, except: [+: 2] diff --git a/mix.lock b/mix.lock index 40ab29439d..2568614718 100644 --- a/mix.lock +++ b/mix.lock @@ -23,21 +23,22 @@ "credo": {:hex, :credo, "0.10.2", "03ad3a1eff79a16664ed42fc2975b5e5d0ce243d69318060c626c34720a49512", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm"}, "csv": {:hex, :csv, "2.1.1", "a4c1a7c30d2151b6e4976cb2f52c0a1d49ec965afb737ed84a684bc4284d1627", [:mix], [{:parallel_stream, "~> 1.0.4", [hex: :parallel_stream, optional: false]}]}, "dataloader": {:hex, :dataloader, "1.0.4", "7c2345c53c9e5b61420013fc53c8463ba347a938b61f66677eb47d9c4a53ac5d", [:mix], [{:ecto, ">= 0.0.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm"}, - "db_connection": {:hex, :db_connection, "1.1.3", "89b30ca1ef0a3b469b1c779579590688561d586694a3ce8792985d4d7e575a61", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, optional: false]}, {:poolboy, "~> 1.5", [hex: :poolboy, optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, optional: true]}]}, - "decimal": {:hex, :decimal, "1.5.0", "b0433a36d0e2430e3d50291b1c65f53c37d56f83665b43d79963684865beab68", [:mix], []}, + "db_connection": {:hex, :db_connection, "2.0.3", "b4e8aa43c100e16f122ccd6798cd51c48c79fd391c39d411f42b3cd765daccb0", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}], "hexpm"}, + "decimal": {:hex, :decimal, "1.6.0", "bfd84d90ff966e1f5d4370bdd3943432d8f65f07d3bab48001aebd7030590dcc", [:mix], [], "hexpm"}, "decorator": {:hex, :decorator, "1.2.4", "31dfff6143d37f0b68d0bffb3b9f18ace14fea54d4f1b5e4f86ead6f00d9ff6e", [:mix], [], "hexpm"}, "deep_merge": {:hex, :deep_merge, "0.2.0", "c1050fa2edf4848b9f556fba1b75afc66608a4219659e3311d9c9427b5b680b3", [:mix], [], "hexpm"}, "dialyxir": {:hex, :dialyxir, "0.5.1", "b331b091720fd93e878137add264bac4f644e1ddae07a70bf7062c7862c4b952", [:mix], []}, "distillery": {:hex, :distillery, "2.0.12", "6e78fe042df82610ac3fa50bd7d2d8190ad287d120d3cd1682d83a44e8b34dfb", [:mix], [{:artificery, "~> 0.2", [hex: :artificery, repo: "hexpm", optional: false]}], "hexpm"}, "earmark": {:hex, :earmark, "1.2.6", "b6da42b3831458d3ecc57314dff3051b080b9b2be88c2e5aa41cd642a5b044ed", [:mix], [], "hexpm"}, - "ecto": {:hex, :ecto, "2.2.11", "4bb8f11718b72ba97a2696f65d247a379e739a0ecabf6a13ad1face79844791c", [:mix], [{:db_connection, "~> 1.1", [hex: :db_connection, repo: "hexpm", optional: true]}, {:decimal, "~> 1.2", [hex: :decimal, repo: "hexpm", optional: false]}, {:mariaex, "~> 0.8.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: true]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.13.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, repo: "hexpm", optional: true]}], "hexpm"}, + "ecto": {:hex, :ecto, "3.0.5", "bf9329b56f781a67fdb19e92e6d9ed79c5c8b31d41653b79dafb7ceddfbe87e0", [:mix], [{:decimal, "~> 1.6", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: true]}], "hexpm"}, + "ecto_sql": {:hex, :ecto_sql, "3.0.3", "dd17f2401a69bb2ec91d5564bd259ad0bc63ee32c2cb2e616d04f1559801dba6", [:mix], [{:db_connection, "~> 2.0", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.0.4", [hex: :ecto, repo: "hexpm", optional: false]}, {:mariaex, "~> 0.9.1", [hex: :mariaex, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.14.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.2.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"}, "elixir_make": {:hex, :elixir_make, "0.4.2", "332c649d08c18bc1ecc73b1befc68c647136de4f340b548844efc796405743bf", [:mix], [], "hexpm"}, "ex_abi": {:hex, :ex_abi, "0.1.18", "19db9bffdd201edbdff97d7dd5849291218b17beda045c1b76bff5248964f37d", [:mix], [{:exth_crypto, "~> 0.1.4", [hex: :exth_crypto, repo: "hexpm", optional: false]}], "hexpm"}, "ex_cldr": {:hex, :ex_cldr, "1.3.2", "8f4a00c99d1c537b8e8db7e7903f4bd78d82a7289502d080f70365392b13921b", [:mix], [{:abnf2, "~> 0.1", [hex: :abnf2, optional: false]}, {:decimal, "~> 1.4", [hex: :decimal, optional: false]}, {:gettext, "~> 0.13", [hex: :gettext, optional: true]}, {:poison, "~> 2.1 or ~> 3.0", [hex: :poison, optional: true]}]}, "ex_cldr_numbers": {:hex, :ex_cldr_numbers, "1.2.0", "ef27299922da913ffad1ed296cacf28b6452fc1243b77301dc17c03276c6ee34", [:mix], [{:decimal, "~> 1.4", [hex: :decimal, optional: false]}, {:ex_cldr, "~> 1.3", [hex: :ex_cldr, optional: false]}, {:poison, "~> 2.1 or ~> 3.1", [hex: :poison, optional: false]}]}, "ex_cldr_units": {:hex, :ex_cldr_units, "1.1.1", "b3c7256709bdeb3740a5f64ce2bce659eb9cf4cc1afb4cf94aba033b4a18bc5f", [:mix], [{:ex_cldr, "~> 1.0", [hex: :ex_cldr, optional: false]}, {:ex_cldr_numbers, "~> 1.0", [hex: :ex_cldr_numbers, optional: false]}]}, "ex_doc": {:hex, :ex_doc, "0.19.1", "519bb9c19526ca51d326c060cb1778d4a9056b190086a8c6c115828eaccea6cf", [:mix], [{:earmark, "~> 1.1", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.7", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm"}, - "ex_machina": {:hex, :ex_machina, "2.2.1", "df84d0b23487aaa8570c35e586d7f9f197a7787e1121344a41d8832a7ea41edf", [:mix], [{:ecto, "~> 2.1", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm"}, + "ex_machina": {:hex, :ex_machina, "2.2.2", "d84217a6fb7840ff771d2561b8aa6d74a0d8968e4b10ecc0d7e9890dc8fb1c6a", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_sql, "~> 3.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}], "hexpm"}, "ex_rlp": {:hex, :ex_rlp, "0.3.1", "190554f7b26f79734fc5a772241eec14a71b2e83576e43f451479feb017013e9", [:mix], [], "hexpm"}, "exactor": {:hex, :exactor, "2.2.4", "5efb4ddeb2c48d9a1d7c9b465a6fffdd82300eb9618ece5d34c3334d5d7245b1", [:mix], []}, "excoveralls": {:git, "https://github.com/KronicDeth/excoveralls.git", "0a859b68851eeba9b43eba59fbc8f9098299cfe1", [branch: "circle-workflows"]}, @@ -85,9 +86,9 @@ "plug_crypto": {:hex, :plug_crypto, "1.0.0", "18e49317d3fa343f24620ed22795ec29d4a5e602d52d1513ccea0b07d8ea7d4d", [:mix], [], "hexpm"}, "poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], []}, "poolboy": {:hex, :poolboy, "1.5.1", "6b46163901cfd0a1b43d692657ed9d7e599853b3b21b95ae5ae0a777cf9b6ca8", [:rebar], []}, - "postgrex": {:hex, :postgrex, "0.13.5", "3d931aba29363e1443da167a4b12f06dcd171103c424de15e5f3fc2ba3e6d9c5", [:mix], [{:connection, "~> 1.0", [hex: :connection, optional: false]}, {:db_connection, "~> 1.1", [hex: :db_connection, optional: false]}, {:decimal, "~> 1.0", [hex: :decimal, optional: false]}]}, + "postgrex": {:hex, :postgrex, "0.14.1", "63247d4a5ad6b9de57a0bac5d807e1c32d41e39c04b8a4156a26c63bcd8a2e49", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.0", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"}, "prometheus": {:hex, :prometheus, "4.2.0", "06c58bfdfe28d3168b926da614cb9a6d39593deebde648a5480e32dfa3c370e9", [:mix, :rebar3], [], "hexpm"}, - "prometheus_ecto": {:hex, :prometheus_ecto, "1.3.0", "fe65de16bcfdd6e3c5455194368cd2c7a7034f734a12c12cb9471f4d5e7690c9", [:mix], [{:ecto, "~> 2.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.1 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}], "hexpm"}, + "prometheus_ecto": {:git, "https://github.com/deadtrickster/prometheus-ecto.git", "650a403183f6a2fb6b682d7fbcba8bf9d24fe1e4", [ref: "650a403183f6a2fb6b682d7fbcba8bf9d24fe1e4"]}, "prometheus_ex": {:hex, :prometheus_ex, "3.0.3", "5d722263bb1f7a9b1d02554de42e61ea672b4e3c07c3f74e23ce35ab5e111cfa", [:mix], [{:prometheus, "~> 4.0", [hex: :prometheus, repo: "hexpm", optional: false]}], "hexpm"}, "prometheus_phoenix": {:hex, :prometheus_phoenix, "1.2.1", "964a74dfbc055f781d3a75631e06ce3816a2913976d1df7830283aa3118a797a", [:mix], [{:phoenix, "~> 1.3", [hex: :phoenix, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.3 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}], "hexpm"}, "prometheus_plugs": {:hex, :prometheus_plugs, "1.1.5", "25933d48f8af3a5941dd7b621c889749894d8a1082a6ff7c67cc99dec26377c5", [:mix], [{:accept, "~> 0.1", [hex: :accept, repo: "hexpm", optional: false]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.1 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}, {:prometheus_process_collector, "~> 1.1", [hex: :prometheus_process_collector, repo: "hexpm", optional: true]}], "hexpm"}, @@ -101,8 +102,8 @@ "spandex_ecto": {:hex, :spandex_ecto, "0.4.0", "deaeaddc11a35f1c551206c53d09bb93a0da5808dbef751430e465c8c7de01d3", [:mix], [{:spandex, "~> 2.2", [hex: :spandex, repo: "hexpm", optional: false]}], "hexpm"}, "spandex_phoenix": {:hex, :spandex_phoenix, "0.3.0", "48b0a426bbe4eea3e579bbea77d5eb5a8d4b83d33c95616f9ba64b3ce2faef6c", [:mix], [{:plug, "~> 1.3", [hex: :plug, repo: "hexpm", optional: false]}, {:spandex, "~> 2.2", [hex: :spandex, repo: "hexpm", optional: false]}], "hexpm"}, "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.4", "f0eafff810d2041e93f915ef59899c923f4568f4585904d010387ed74988e77b", [:make, :mix, :rebar3], [], "hexpm"}, + "telemetry": {:hex, :telemetry, "0.2.0", "5b40caa3efe4deb30fb12d7cd8ed4f556f6d6bd15c374c2366772161311ce377", [:mix], [], "hexpm"}, "timex": {:hex, :timex, "3.4.1", "e63fc1a37453035e534c3febfe9b6b9e18583ec7b37fd9c390efdef97397d70b", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 0.1.8 or ~> 0.5", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm"}, - "timex_ecto": {:hex, :timex_ecto, "3.3.0", "d5bdef09928e7a60f10a0baa47ce653f29b43d6fee87b30b236b216d0e36b98d", [:mix], [{:ecto, "~> 2.2", [hex: :ecto, repo: "hexpm", optional: false]}, {:timex, "~> 3.1", [hex: :timex, repo: "hexpm", optional: false]}], "hexpm"}, "tzdata": {:hex, :tzdata, "0.5.19", "7962a3997bf06303b7d1772988ede22260f3dae1bf897408ebdac2b4435f4e6a", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"}, "unicode_util_compat": {:hex, :unicode_util_compat, "0.4.1", "d869e4c68901dd9531385bb0c8c40444ebf624e60b6962d95952775cac5e90cd", [:rebar3], [], "hexpm"}, "wallaby": {:hex, :wallaby, "0.20.0", "cc6663555ff7b05afbebb2a8b461d18a5b321658b9017f7bc77d494b7063266a", [:mix], [{:httpoison, "~> 0.12", [hex: :httpoison, optional: false]}, {:poison, ">= 1.4.0", [hex: :poison, optional: false]}, {:poolboy, "~> 1.5", [hex: :poolboy, optional: false]}]},