Merge pull request #1229 from poanetwork/ecto-3.0

Update to Ecto 3.0
pull/1230/head
Luke Imhoff 6 years ago committed by GitHub
commit 24e81e28df
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 132
      apps/block_scout_web/assets/package-lock.json
  2. 5
      apps/block_scout_web/lib/block_scout_web/chain.ex
  3. 3
      apps/block_scout_web/mix.exs
  4. 15
      apps/block_scout_web/test/block_scout_web/channels/address_channel_test.exs
  5. 7
      apps/block_scout_web/test/block_scout_web/controllers/address_contract_controller_test.exs
  6. 16
      apps/block_scout_web/test/block_scout_web/controllers/address_controller_test.exs
  7. 7
      apps/block_scout_web/test/block_scout_web/controllers/address_internal_transaction_controller_test.exs
  8. 8
      apps/block_scout_web/test/block_scout_web/controllers/address_read_contract_controller_test.exs
  9. 13
      apps/block_scout_web/test/block_scout_web/controllers/address_token_controller_test.exs
  10. 11
      apps/block_scout_web/test/block_scout_web/controllers/address_transaction_controller_test.exs
  11. 28
      apps/block_scout_web/test/block_scout_web/controllers/chain_controller_test.exs
  12. 9
      apps/block_scout_web/test/block_scout_web/controllers/pending_transaction_controller_test.exs
  13. 11
      apps/block_scout_web/test/block_scout_web/controllers/tokens/holder_controller_test.exs
  14. 30
      apps/block_scout_web/test/block_scout_web/controllers/tokens/inventory_controller_test.exs
  15. 12
      apps/block_scout_web/test/block_scout_web/controllers/tokens/read_contract_controller_test.exs
  16. 3
      apps/block_scout_web/test/block_scout_web/controllers/transaction_controller_test.exs
  17. 8
      apps/block_scout_web/test/block_scout_web/features/address_contract_verification_test.exs
  18. 54
      apps/block_scout_web/test/block_scout_web/features/viewing_addresses_test.exs
  19. 16
      apps/block_scout_web/test/block_scout_web/features/viewing_app_test.exs
  20. 32
      apps/block_scout_web/test/block_scout_web/features/viewing_chain_test.exs
  21. 7
      apps/block_scout_web/test/block_scout_web/features/viewing_tokens_test.exs
  22. 9
      apps/block_scout_web/test/block_scout_web/features/viewing_transactions_test.exs
  23. 2
      apps/block_scout_web/test/block_scout_web/views/transaction_view_test.exs
  24. 24
      apps/explorer/config/config.exs
  25. 2
      apps/explorer/config/dev.exs
  26. 3
      apps/explorer/config/dev.secret.exs.example
  27. 1
      apps/explorer/config/prod.exs
  28. 16
      apps/explorer/config/test.exs
  29. 1
      apps/explorer/config/test.secret.exs.example
  30. 2
      apps/explorer/lib/explorer/accounts/user.ex
  31. 2
      apps/explorer/lib/explorer/accounts/user/authenticate.ex
  32. 2
      apps/explorer/lib/explorer/accounts/user/registration.ex
  33. 2
      apps/explorer/lib/explorer/accounts/user_contact.ex
  34. 2
      apps/explorer/lib/explorer/admin/administrator.ex
  35. 4
      apps/explorer/lib/explorer/application.ex
  36. 73
      apps/explorer/lib/explorer/chain.ex
  37. 8
      apps/explorer/lib/explorer/chain/address/coin_balance.ex
  38. 5
      apps/explorer/lib/explorer/chain/address/current_token_balance.ex
  39. 2
      apps/explorer/lib/explorer/chain/address/name.ex
  40. 5
      apps/explorer/lib/explorer/chain/address/token_balance.ex
  41. 2
      apps/explorer/lib/explorer/chain/block.ex
  42. 2
      apps/explorer/lib/explorer/chain/block/second_degree_relation.ex
  43. 4
      apps/explorer/lib/explorer/chain/import.ex
  44. 10
      apps/explorer/lib/explorer/chain/import/address/coin_balances.ex
  45. 12
      apps/explorer/lib/explorer/chain/import/address/current_token_balances.ex
  46. 11
      apps/explorer/lib/explorer/chain/import/address/token_balances.ex
  47. 11
      apps/explorer/lib/explorer/chain/import/addresses.ex
  48. 16
      apps/explorer/lib/explorer/chain/import/block/second_degree_relations.ex
  49. 9
      apps/explorer/lib/explorer/chain/import/block_rewards.ex
  50. 57
      apps/explorer/lib/explorer/chain/import/blocks.ex
  51. 21
      apps/explorer/lib/explorer/chain/import/internal_transactions.ex
  52. 11
      apps/explorer/lib/explorer/chain/import/logs.ex
  53. 11
      apps/explorer/lib/explorer/chain/import/token_transfers.ex
  54. 11
      apps/explorer/lib/explorer/chain/import/tokens.ex
  55. 11
      apps/explorer/lib/explorer/chain/import/transaction/forks.ex
  56. 11
      apps/explorer/lib/explorer/chain/import/transactions.ex
  57. 2
      apps/explorer/lib/explorer/chain/token.ex
  58. 2
      apps/explorer/lib/explorer/chain/token_transfer.ex
  59. 2
      apps/explorer/lib/explorer/chain/transaction.ex
  60. 4
      apps/explorer/lib/explorer/counters/addresses_with_balance_counter.ex
  61. 25
      apps/explorer/lib/explorer/counters/token_transfer_counter.ex
  62. 6
      apps/explorer/lib/explorer/exchange_rates/source.ex
  63. 4
      apps/explorer/lib/explorer/market/history/source/crypto_compare.ex
  64. 3
      apps/explorer/lib/explorer/market/market_history.ex
  65. 4
      apps/explorer/lib/explorer/repo.ex
  66. 5
      apps/explorer/lib/explorer/schema.ex
  67. 18
      apps/explorer/mix.exs
  68. 2
      apps/explorer/priv/repo/migrations/20180117221921_create_address.exs
  69. 4
      apps/explorer/priv/repo/migrations/20180117221922_create_blocks.exs
  70. 4
      apps/explorer/priv/repo/migrations/20180117221923_create_transactions.exs
  71. 2
      apps/explorer/priv/repo/migrations/20180212222309_create_logs.exs
  72. 2
      apps/explorer/priv/repo/migrations/20180221001948_create_internal_transactions.exs
  73. 4
      apps/explorer/priv/repo/migrations/20180717204948_create_address_coin_balances.exs
  74. 4
      apps/explorer/priv/repo/migrations/20180817021704_create_address_token_balances.exs
  75. 2
      apps/explorer/priv/repo/migrations/20180917182319_create_block_second_degree_relations.exs
  76. 4
      apps/explorer/priv/repo/migrations/20181026180921_create_address_current_token_balances.exs
  77. 16
      apps/explorer/test/explorer/chain/address/coin_balance_test.exs
  78. 27
      apps/explorer/test/explorer/chain/block_test.exs
  79. 16
      apps/explorer/test/explorer/chain/import/address/address/current_token_balances_test.exs
  80. 4
      apps/explorer/test/explorer/chain/transaction/fork_test.exs
  81. 6
      apps/explorer/test/explorer/chain_test.exs
  82. 9
      apps/explorer/test/explorer/counters/addresses_with_balance_counter_test.exs
  83. 6
      apps/explorer/test/explorer/counters/block_validation_counter_test.exs
  84. 6
      apps/explorer/test/explorer/counters/token_holders_counter_test.exs
  85. 8
      apps/explorer/test/explorer/counters/token_transfer_counter_test.exs
  86. 12
      apps/explorer/test/explorer/market/history/source/crypto_compare_test.exs
  87. 2
      apps/explorer/test/explorer/repo_test.exs
  88. 13
      apps/explorer/test/support/data_case.ex
  89. 12
      apps/explorer/test/support/factory.ex
  90. 15
      mix.lock

@ -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
}

@ -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

@ -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]},

@ -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."

@ -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)

@ -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

@ -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

@ -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,

@ -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

@ -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)

@ -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

@ -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"}))

@ -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,

@ -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

@ -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)

@ -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

@ -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()

@ -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

@ -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

@ -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))

@ -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))

@ -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)

@ -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)

@ -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

@ -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

@ -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: "<REPLACE WITH THE PASSWORD YOU CHOSE>",
loggers: [Explorer.Repo.PrometheusLogger],
pool_size: 20,
pool_timeout: 60_000,
timeout: 80_000

@ -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"),

@ -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,

@ -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,

@ -3,7 +3,7 @@ defmodule Explorer.Accounts.User do
An Explorer user.
"""
use Ecto.Schema
use Explorer.Schema
import Ecto.Changeset

@ -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

@ -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

@ -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

@ -3,7 +3,7 @@ defmodule Explorer.Admin.Administrator do
Represents a user with administrative privileges.
"""
use Ecto.Schema
use Explorer.Schema
import Ecto.Changeset

@ -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

@ -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

@ -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

@ -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)

@ -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

@ -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)

@ -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()

@ -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)

@ -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)

@ -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,

@ -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,

@ -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,

@ -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,

@ -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,

@ -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(),

@ -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

@ -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

@ -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,

@ -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,

@ -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,

@ -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,

@ -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,

@ -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}

@ -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]

@ -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)

@ -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 """

@ -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)

@ -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

@ -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

@ -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)

@ -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

@ -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

@ -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

@ -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

@ -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]))

@ -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)

@ -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)

@ -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)

@ -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]))

@ -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))

@ -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))

@ -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))

@ -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

@ -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

@ -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)

@ -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

@ -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

@ -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

@ -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)

@ -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")

@ -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)

@ -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)
}
]

@ -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

@ -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

@ -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]

@ -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]}]},

Loading…
Cancel
Save