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": { "dependencies": {
"abbrev": { "abbrev": {
"version": "1.1.1", "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==", "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"ansi-regex": { "ansi-regex": {
"version": "2.1.1", "version": "2.1.1",
"resolved": false, "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
"dev": true "dev": true
}, },
"aproba": { "aproba": {
"version": "1.2.0", "version": "1.2.0",
"resolved": false, "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
"integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==",
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"are-we-there-yet": { "are-we-there-yet": {
"version": "1.1.4", "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=", "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=",
"dev": true, "dev": true,
"optional": true, "optional": true,
@ -3838,13 +3838,13 @@
}, },
"balanced-match": { "balanced-match": {
"version": "1.0.0", "version": "1.0.0",
"resolved": false, "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
"dev": true "dev": true
}, },
"brace-expansion": { "brace-expansion": {
"version": "1.1.11", "version": "1.1.11",
"resolved": false, "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true, "dev": true,
"requires": { "requires": {
@ -3854,39 +3854,39 @@
}, },
"chownr": { "chownr": {
"version": "1.0.1", "version": "1.0.1",
"resolved": false, "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.0.1.tgz",
"integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=", "integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=",
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"code-point-at": { "code-point-at": {
"version": "1.1.0", "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=", "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
"dev": true "dev": true
}, },
"concat-map": { "concat-map": {
"version": "0.0.1", "version": "0.0.1",
"resolved": false, "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
"dev": true "dev": true
}, },
"console-control-strings": { "console-control-strings": {
"version": "1.1.0", "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=", "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
"dev": true "dev": true
}, },
"core-util-is": { "core-util-is": {
"version": "1.0.2", "version": "1.0.2",
"resolved": false, "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"debug": { "debug": {
"version": "2.6.9", "version": "2.6.9",
"resolved": false, "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"dev": true, "dev": true,
"optional": true, "optional": true,
@ -3896,28 +3896,28 @@
}, },
"deep-extend": { "deep-extend": {
"version": "0.5.1", "version": "0.5.1",
"resolved": false, "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.5.1.tgz",
"integrity": "sha512-N8vBdOa+DF7zkRrDCsaOXoCs/E2fJfx9B9MrKnnSiHNh4ws7eSys6YQE4KvT1cecKmOASYQBhbKjeuDD9lT81w==", "integrity": "sha512-N8vBdOa+DF7zkRrDCsaOXoCs/E2fJfx9B9MrKnnSiHNh4ws7eSys6YQE4KvT1cecKmOASYQBhbKjeuDD9lT81w==",
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"delegates": { "delegates": {
"version": "1.0.0", "version": "1.0.0",
"resolved": false, "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
"integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=",
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"detect-libc": { "detect-libc": {
"version": "1.0.3", "version": "1.0.3",
"resolved": false, "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
"integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=",
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"fs-minipass": { "fs-minipass": {
"version": "1.2.5", "version": "1.2.5",
"resolved": false, "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz",
"integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==", "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==",
"dev": true, "dev": true,
"optional": true, "optional": true,
@ -3927,14 +3927,14 @@
}, },
"fs.realpath": { "fs.realpath": {
"version": "1.0.0", "version": "1.0.0",
"resolved": false, "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"gauge": { "gauge": {
"version": "2.7.4", "version": "2.7.4",
"resolved": false, "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
"integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
"dev": true, "dev": true,
"optional": true, "optional": true,
@ -3951,7 +3951,7 @@
}, },
"glob": { "glob": {
"version": "7.1.2", "version": "7.1.2",
"resolved": false, "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
"integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
"dev": true, "dev": true,
"optional": true, "optional": true,
@ -3966,14 +3966,14 @@
}, },
"has-unicode": { "has-unicode": {
"version": "2.0.1", "version": "2.0.1",
"resolved": false, "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
"integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=",
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"iconv-lite": { "iconv-lite": {
"version": "0.4.21", "version": "0.4.21",
"resolved": false, "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.21.tgz",
"integrity": "sha512-En5V9za5mBt2oUA03WGD3TwDv0MKAruqsuxstbMUZaj9W9k/m1CV/9py3l0L5kw9Bln8fdHQmzHSYtvpvTLpKw==", "integrity": "sha512-En5V9za5mBt2oUA03WGD3TwDv0MKAruqsuxstbMUZaj9W9k/m1CV/9py3l0L5kw9Bln8fdHQmzHSYtvpvTLpKw==",
"dev": true, "dev": true,
"optional": true, "optional": true,
@ -3983,7 +3983,7 @@
}, },
"ignore-walk": { "ignore-walk": {
"version": "3.0.1", "version": "3.0.1",
"resolved": false, "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz",
"integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==",
"dev": true, "dev": true,
"optional": true, "optional": true,
@ -3993,7 +3993,7 @@
}, },
"inflight": { "inflight": {
"version": "1.0.6", "version": "1.0.6",
"resolved": false, "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"dev": true, "dev": true,
"optional": true, "optional": true,
@ -4004,20 +4004,20 @@
}, },
"inherits": { "inherits": {
"version": "2.0.3", "version": "2.0.3",
"resolved": false, "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
"dev": true "dev": true
}, },
"ini": { "ini": {
"version": "1.3.5", "version": "1.3.5",
"resolved": false, "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"is-fullwidth-code-point": { "is-fullwidth-code-point": {
"version": "1.0.0", "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=", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
"dev": true, "dev": true,
"requires": { "requires": {
@ -4026,14 +4026,14 @@
}, },
"isarray": { "isarray": {
"version": "1.0.0", "version": "1.0.0",
"resolved": false, "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"minimatch": { "minimatch": {
"version": "3.0.4", "version": "3.0.4",
"resolved": false, "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"dev": true, "dev": true,
"requires": { "requires": {
@ -4042,13 +4042,13 @@
}, },
"minimist": { "minimist": {
"version": "0.0.8", "version": "0.0.8",
"resolved": false, "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
"dev": true "dev": true
}, },
"minipass": { "minipass": {
"version": "2.2.4", "version": "2.2.4",
"resolved": false, "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.2.4.tgz",
"integrity": "sha512-hzXIWWet/BzWhYs2b+u7dRHlruXhwdgvlTMDKC6Cb1U7ps6Ac6yQlR39xsbjWJE377YTCtKwIXIpJ5oP+j5y8g==", "integrity": "sha512-hzXIWWet/BzWhYs2b+u7dRHlruXhwdgvlTMDKC6Cb1U7ps6Ac6yQlR39xsbjWJE377YTCtKwIXIpJ5oP+j5y8g==",
"dev": true, "dev": true,
"requires": { "requires": {
@ -4058,7 +4058,7 @@
}, },
"minizlib": { "minizlib": {
"version": "1.1.0", "version": "1.1.0",
"resolved": false, "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.1.0.tgz",
"integrity": "sha512-4T6Ur/GctZ27nHfpt9THOdRZNgyJ9FZchYO1ceg5S8Q3DNLCKYy44nCZzgCJgcvx2UM8czmqak5BCxJMrq37lA==", "integrity": "sha512-4T6Ur/GctZ27nHfpt9THOdRZNgyJ9FZchYO1ceg5S8Q3DNLCKYy44nCZzgCJgcvx2UM8czmqak5BCxJMrq37lA==",
"dev": true, "dev": true,
"optional": true, "optional": true,
@ -4068,7 +4068,7 @@
}, },
"mkdirp": { "mkdirp": {
"version": "0.5.1", "version": "0.5.1",
"resolved": false, "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"dev": true, "dev": true,
"requires": { "requires": {
@ -4077,14 +4077,14 @@
}, },
"ms": { "ms": {
"version": "2.0.0", "version": "2.0.0",
"resolved": false, "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"needle": { "needle": {
"version": "2.2.0", "version": "2.2.0",
"resolved": false, "resolved": "https://registry.npmjs.org/needle/-/needle-2.2.0.tgz",
"integrity": "sha512-eFagy6c+TYayorXw/qtAdSvaUpEbBsDwDyxYFgLZ0lTojfH7K+OdBqAF7TAFwDokJaGpubpSGG0wO3iC0XPi8w==", "integrity": "sha512-eFagy6c+TYayorXw/qtAdSvaUpEbBsDwDyxYFgLZ0lTojfH7K+OdBqAF7TAFwDokJaGpubpSGG0wO3iC0XPi8w==",
"dev": true, "dev": true,
"optional": true, "optional": true,
@ -4096,7 +4096,7 @@
}, },
"node-pre-gyp": { "node-pre-gyp": {
"version": "0.10.0", "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==", "integrity": "sha512-G7kEonQLRbcA/mOoFoxvlMrw6Q6dPf92+t/l0DFSMuSlDoWaI9JWIyPwK0jyE1bph//CUEL65/Fz1m2vJbmjQQ==",
"dev": true, "dev": true,
"optional": true, "optional": true,
@ -4115,7 +4115,7 @@
}, },
"nopt": { "nopt": {
"version": "4.0.1", "version": "4.0.1",
"resolved": false, "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz",
"integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=",
"dev": true, "dev": true,
"optional": true, "optional": true,
@ -4126,14 +4126,14 @@
}, },
"npm-bundled": { "npm-bundled": {
"version": "1.0.3", "version": "1.0.3",
"resolved": false, "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.3.tgz",
"integrity": "sha512-ByQ3oJ/5ETLyglU2+8dBObvhfWXX8dtPZDMePCahptliFX2iIuhyEszyFk401PZUNQH20vvdW5MLjJxkwU80Ow==", "integrity": "sha512-ByQ3oJ/5ETLyglU2+8dBObvhfWXX8dtPZDMePCahptliFX2iIuhyEszyFk401PZUNQH20vvdW5MLjJxkwU80Ow==",
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"npm-packlist": { "npm-packlist": {
"version": "1.1.10", "version": "1.1.10",
"resolved": false, "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.1.10.tgz",
"integrity": "sha512-AQC0Dyhzn4EiYEfIUjCdMl0JJ61I2ER9ukf/sLxJUcZHfo+VyEfz2rMJgLZSS1v30OxPQe1cN0LZA1xbcaVfWA==", "integrity": "sha512-AQC0Dyhzn4EiYEfIUjCdMl0JJ61I2ER9ukf/sLxJUcZHfo+VyEfz2rMJgLZSS1v30OxPQe1cN0LZA1xbcaVfWA==",
"dev": true, "dev": true,
"optional": true, "optional": true,
@ -4144,7 +4144,7 @@
}, },
"npmlog": { "npmlog": {
"version": "4.1.2", "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==", "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
"dev": true, "dev": true,
"optional": true, "optional": true,
@ -4157,20 +4157,20 @@
}, },
"number-is-nan": { "number-is-nan": {
"version": "1.0.1", "version": "1.0.1",
"resolved": false, "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
"dev": true "dev": true
}, },
"object-assign": { "object-assign": {
"version": "4.1.1", "version": "4.1.1",
"resolved": false, "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"once": { "once": {
"version": "1.4.0", "version": "1.4.0",
"resolved": false, "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"dev": true, "dev": true,
"requires": { "requires": {
@ -4179,21 +4179,21 @@
}, },
"os-homedir": { "os-homedir": {
"version": "1.0.2", "version": "1.0.2",
"resolved": false, "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
"integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"os-tmpdir": { "os-tmpdir": {
"version": "1.0.2", "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=", "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"osenv": { "osenv": {
"version": "0.1.5", "version": "0.1.5",
"resolved": false, "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz",
"integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
"dev": true, "dev": true,
"optional": true, "optional": true,
@ -4204,21 +4204,21 @@
}, },
"path-is-absolute": { "path-is-absolute": {
"version": "1.0.1", "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=", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"process-nextick-args": { "process-nextick-args": {
"version": "2.0.0", "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==", "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"rc": { "rc": {
"version": "1.2.7", "version": "1.2.7",
"resolved": false, "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.7.tgz",
"integrity": "sha512-LdLD8xD4zzLsAT5xyushXDNscEjB7+2ulnl8+r1pnESlYtlJtVSoCMBGr30eDRJ3+2Gq89jK9P9e4tCEH1+ywA==", "integrity": "sha512-LdLD8xD4zzLsAT5xyushXDNscEjB7+2ulnl8+r1pnESlYtlJtVSoCMBGr30eDRJ3+2Gq89jK9P9e4tCEH1+ywA==",
"dev": true, "dev": true,
"optional": true, "optional": true,
@ -4231,7 +4231,7 @@
"dependencies": { "dependencies": {
"minimist": { "minimist": {
"version": "1.2.0", "version": "1.2.0",
"resolved": false, "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
"dev": true, "dev": true,
"optional": true "optional": true
@ -4240,7 +4240,7 @@
}, },
"readable-stream": { "readable-stream": {
"version": "2.3.6", "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==", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true, "dev": true,
"optional": true, "optional": true,
@ -4256,7 +4256,7 @@
}, },
"rimraf": { "rimraf": {
"version": "2.6.2", "version": "2.6.2",
"resolved": false, "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
"integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==",
"dev": true, "dev": true,
"optional": true, "optional": true,
@ -4266,48 +4266,48 @@
}, },
"safe-buffer": { "safe-buffer": {
"version": "5.1.1", "version": "5.1.1",
"resolved": false, "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
"integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==",
"dev": true "dev": true
}, },
"safer-buffer": { "safer-buffer": {
"version": "2.1.2", "version": "2.1.2",
"resolved": false, "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"sax": { "sax": {
"version": "1.2.4", "version": "1.2.4",
"resolved": false, "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"semver": { "semver": {
"version": "5.5.0", "version": "5.5.0",
"resolved": false, "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz",
"integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==",
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"set-blocking": { "set-blocking": {
"version": "2.0.0", "version": "2.0.0",
"resolved": false, "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"signal-exit": { "signal-exit": {
"version": "3.0.2", "version": "3.0.2",
"resolved": false, "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
"integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"string-width": { "string-width": {
"version": "1.0.2", "version": "1.0.2",
"resolved": false, "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
"dev": true, "dev": true,
"requires": { "requires": {
@ -4318,7 +4318,7 @@
}, },
"string_decoder": { "string_decoder": {
"version": "1.1.1", "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==", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dev": true, "dev": true,
"optional": true, "optional": true,
@ -4328,7 +4328,7 @@
}, },
"strip-ansi": { "strip-ansi": {
"version": "3.0.1", "version": "3.0.1",
"resolved": false, "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"dev": true, "dev": true,
"requires": { "requires": {
@ -4337,14 +4337,14 @@
}, },
"strip-json-comments": { "strip-json-comments": {
"version": "2.0.1", "version": "2.0.1",
"resolved": false, "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
"integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"tar": { "tar": {
"version": "4.4.1", "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==", "integrity": "sha512-O+v1r9yN4tOsvl90p5HAP4AEqbYhx4036AGMm075fH9F8Qwi3oJ+v4u50FkT/KkvywNGtwkk0zRI+8eYm1X/xg==",
"dev": true, "dev": true,
"optional": true, "optional": true,
@ -4360,14 +4360,14 @@
}, },
"util-deprecate": { "util-deprecate": {
"version": "1.0.2", "version": "1.0.2",
"resolved": false, "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"wide-align": { "wide-align": {
"version": "1.1.2", "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==", "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==",
"dev": true, "dev": true,
"optional": true, "optional": true,
@ -4377,13 +4377,13 @@
}, },
"wrappy": { "wrappy": {
"version": "1.0.2", "version": "1.0.2",
"resolved": false, "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
"dev": true "dev": true
}, },
"yallist": { "yallist": {
"version": "3.0.2", "version": "3.0.2",
"resolved": false, "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.2.tgz",
"integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=", "integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=",
"dev": true "dev": true
} }

@ -183,10 +183,7 @@ defmodule BlockScoutWeb.Chain do
end end
defp paging_params(%Address.Token{name: name, type: type, inserted_at: inserted_at}) do defp paging_params(%Address.Token{name: name, type: type, inserted_at: inserted_at}) do
inserted_at_datetime = inserted_at_datetime = DateTime.to_iso8601(inserted_at)
inserted_at
|> DateTime.from_naive!("Etc/UTC")
|> DateTime.to_iso8601()
%{"token_name" => name, "token_type" => type, "token_inserted_at" => inserted_at_datetime} %{"token_name" => name, "token_type" => type, "token_inserted_at" => inserted_at_datetime}
end end

@ -74,6 +74,9 @@ defmodule BlockScoutWeb.Mixfile do
# For Absinthe to load data in batches # For Absinthe to load data in batches
{:dataloader, "~> 1.0.0"}, {:dataloader, "~> 1.0.0"},
{:dialyxir, "~> 0.5", only: [:dev, :test], runtime: false}, {: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_numbers, "~> 1.0"},
{:ex_cldr_units, "~> 1.0"}, {:ex_cldr_units, "~> 1.0"},
{:ex_machina, "~> 2.1", only: [:test]}, {:ex_machina, "~> 2.1", only: [:test]},

@ -1,7 +1,10 @@
defmodule BlockScoutWeb.AddressChannelTest do defmodule BlockScoutWeb.AddressChannelTest do
use BlockScoutWeb.ChannelCase use BlockScoutWeb.ChannelCase,
# ETS tables are shared in `Explorer.Counters.AddressesWithBalanceCounter`
async: false
alias BlockScoutWeb.Notifier alias BlockScoutWeb.Notifier
alias Explorer.Counters.AddressesWithBalanceCounter
test "subscribed user is notified of new_address count event" do test "subscribed user is notified of new_address count event" do
topic = "addresses:new_address" topic = "addresses:new_address"
@ -9,6 +12,9 @@ defmodule BlockScoutWeb.AddressChannelTest do
address = insert(:address) address = insert(:address)
start_supervised!(AddressesWithBalanceCounter)
AddressesWithBalanceCounter.consolidate()
Notifier.handle_event({:chain_event, :addresses, :realtime, [address]}) Notifier.handle_event({:chain_event, :addresses, :realtime, [address]})
assert_receive %Phoenix.Socket.Broadcast{topic: ^topic, event: "count", payload: %{count: _}}, 5_000 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 test "notified of balance_update for matching address", %{address: address, topic: topic} do
address_with_balance = %{address | fetched_coin_balance: 1} address_with_balance = %{address | fetched_coin_balance: 1}
start_supervised!(AddressesWithBalanceCounter)
AddressesWithBalanceCounter.consolidate()
Notifier.handle_event({:chain_event, :addresses, :realtime, [address_with_balance]}) Notifier.handle_event({:chain_event, :addresses, :realtime, [address_with_balance]})
assert_receive %Phoenix.Socket.Broadcast{topic: ^topic, event: "balance_update", payload: payload}, 5_000 assert_receive %Phoenix.Socket.Broadcast{topic: ^topic, event: "balance_update", payload: payload}, 5_000
@ -31,6 +41,9 @@ defmodule BlockScoutWeb.AddressChannelTest do
end end
test "not notified of balance_update if fetched_coin_balance is nil", %{address: address} do 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]}) Notifier.handle_event({:chain_event, :addresses, :realtime, [address]})
refute_receive _, 100, "Message was broadcast for nil fetched_coin_balance." refute_receive _, 100, "Message was broadcast for nil fetched_coin_balance."

@ -1,9 +1,12 @@
defmodule BlockScoutWeb.AddressContractControllerTest do 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] import BlockScoutWeb.Router.Helpers, only: [address_contract_path: 3]
alias Explorer.Chain.Hash alias Explorer.Chain.Hash
alias Explorer.Counters.BlockValidationCounter
alias Explorer.ExchangeRates.Token alias Explorer.ExchangeRates.Token
alias Explorer.Factory alias Explorer.Factory
@ -44,6 +47,8 @@ defmodule BlockScoutWeb.AddressContractControllerTest do
created_contract_address: address created_contract_address: address
) )
start_supervised!(BlockValidationCounter)
conn = get(conn, address_contract_path(BlockScoutWeb.Endpoint, :index, address)) conn = get(conn, address_contract_path(BlockScoutWeb.Endpoint, :index, address))
assert html_response(conn, 200) assert html_response(conn, 200)

@ -1,5 +1,9 @@
defmodule BlockScoutWeb.AddressControllerTest do 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 describe "GET index/2" do
test "returns top addresses", %{conn: conn} 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(&insert(:address, fetched_coin_balance: &1))
|> Enum.map(& &1.hash) |> Enum.map(& &1.hash)
start_supervised!(AddressesWithBalanceCounter)
AddressesWithBalanceCounter.consolidate()
start_supervised!(BlockValidationCounter)
conn = get(conn, address_path(conn, :index)) conn = get(conn, address_path(conn, :index))
assert conn.assigns.address_tx_count_pairs assert conn.assigns.address_tx_count_pairs
@ -19,6 +28,11 @@ defmodule BlockScoutWeb.AddressControllerTest do
address = insert(:address, fetched_coin_balance: 1) address = insert(:address, fetched_coin_balance: 1)
address_name = insert(:address_name, address: address, primary: true, name: "POA Wallet") 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)) conn = get(conn, address_path(conn, :index))
assert html_response(conn, 200) =~ address_name.name assert html_response(conn, 200) =~ address_name.name

@ -1,10 +1,13 @@
defmodule BlockScoutWeb.AddressInternalTransactionControllerTest do defmodule BlockScoutWeb.AddressInternalTransactionControllerTest do
use BlockScoutWeb.ConnCase use BlockScoutWeb.ConnCase,
# ETS table is shared in `Explorer.Counters.BlockValidationCounter`
async: false
import BlockScoutWeb.Router.Helpers, import BlockScoutWeb.Router.Helpers,
only: [address_internal_transaction_path: 3, address_internal_transaction_path: 4] only: [address_internal_transaction_path: 3, address_internal_transaction_path: 4]
alias Explorer.Chain.{Block, InternalTransaction, Transaction} alias Explorer.Chain.{Block, InternalTransaction, Transaction}
alias Explorer.Counters.BlockValidationCounter
alias Explorer.ExchangeRates.Token alias Explorer.ExchangeRates.Token
describe "GET index/3" do 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 test "includes USD exchange rate value for address in assigns", %{conn: conn} do
address = insert(:address) address = insert(:address)
start_supervised!(BlockValidationCounter)
conn = get(conn, address_internal_transaction_path(BlockScoutWeb.Endpoint, :index, address.hash)) conn = get(conn, address_internal_transaction_path(BlockScoutWeb.Endpoint, :index, address.hash))
assert %Token{} = conn.assigns.exchange_rate assert %Token{} = conn.assigns.exchange_rate

@ -1,6 +1,9 @@
defmodule BlockScoutWeb.AddressReadContractControllerTest do 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 alias Explorer.ExchangeRates.Token
describe "GET index/3" do describe "GET index/3" do
@ -23,6 +26,9 @@ defmodule BlockScoutWeb.AddressReadContractControllerTest do
transaction = insert(:transaction, from_address: contract_address) transaction = insert(:transaction, from_address: contract_address)
start_supervised!(BlockValidationCounter)
BlockValidationCounter.consolidate_blocks()
insert( insert(
:internal_transaction_create, :internal_transaction_create,
index: 0, index: 0,

@ -1,9 +1,12 @@
defmodule BlockScoutWeb.AddressTokenControllerTest do 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] import BlockScoutWeb.Router.Helpers, only: [address_token_path: 3]
alias Explorer.Chain.{Token} alias Explorer.Chain.{Token}
alias Explorer.Counters.BlockValidationCounter
describe "GET index/2" do describe "GET index/2" do
test "with invalid address hash", %{conn: conn} do test "with invalid address hash", %{conn: conn} do
@ -57,6 +60,8 @@ defmodule BlockScoutWeb.AddressTokenControllerTest do
to_address: address to_address: address
) )
start_supervised!(BlockValidationCounter)
conn = get(conn, address_token_path(conn, :index, address)) conn = get(conn, address_token_path(conn, :index, address))
actual_token_hashes = actual_token_hashes =
@ -100,6 +105,8 @@ defmodule BlockScoutWeb.AddressTokenControllerTest do
insert(:token_transfer, token: token, from_address: address) insert(:token_transfer, token: token, from_address: address)
%Token{name: name, type: type} = token %Token{name: name, type: type} = token
start_supervised!(BlockValidationCounter)
conn = conn =
get(conn, address_token_path(BlockScoutWeb.Endpoint, :index, address.hash), %{ get(conn, address_token_path(BlockScoutWeb.Endpoint, :index, address.hash), %{
"name" => name, "name" => name,
@ -130,6 +137,8 @@ defmodule BlockScoutWeb.AddressTokenControllerTest do
insert(:token_transfer, token_contract_address: token.contract_address, from_address: address) insert(:token_transfer, token_contract_address: token.contract_address, from_address: address)
end) end)
start_supervised!(BlockValidationCounter)
conn = get(conn, address_token_path(BlockScoutWeb.Endpoint, :index, address.hash)) conn = get(conn, address_token_path(BlockScoutWeb.Endpoint, :index, address.hash))
assert conn.assigns.next_page_params assert conn.assigns.next_page_params
@ -140,6 +149,8 @@ defmodule BlockScoutWeb.AddressTokenControllerTest do
token = insert(:token) token = insert(:token)
insert(:token_transfer, token_contract_address: token.contract_address, from_address: address) 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)) conn = get(conn, address_token_path(BlockScoutWeb.Endpoint, :index, address.hash))
refute conn.assigns.next_page_params refute conn.assigns.next_page_params

@ -1,9 +1,12 @@
defmodule BlockScoutWeb.AddressTransactionControllerTest do 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] 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 alias Explorer.ExchangeRates.Token
describe "GET index/2" do 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 test "includes USD exchange rate value for address in assigns", %{conn: conn} do
address = insert(:address) address = insert(:address)
start_supervised!(BlockValidationCounter)
conn = get(conn, address_transaction_path(BlockScoutWeb.Endpoint, :index, address.hash)) conn = get(conn, address_transaction_path(BlockScoutWeb.Endpoint, :index, address.hash))
assert %Token{} = conn.assigns.exchange_rate 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 test "next_page_params exist if not on last page", %{conn: conn} do
address = insert(:address) address = insert(:address)
block = %Block{number: number} = insert(:block) block = insert(:block)
60 60
|> insert_list(:transaction, from_address: address) |> insert_list(:transaction, from_address: address)

@ -1,12 +1,18 @@
defmodule BlockScoutWeb.ChainControllerTest do 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] import BlockScoutWeb.Router.Helpers, only: [chain_path: 2, block_path: 3, transaction_path: 3, address_path: 3]
alias Explorer.Chain.Block alias Explorer.Chain.Block
alias Explorer.Counters.AddressesWithBalanceCounter
describe "GET index/2" do describe "GET index/2" do
test "returns a welcome message", %{conn: conn} do test "returns a welcome message", %{conn: conn} do
start_supervised!(AddressesWithBalanceCounter)
AddressesWithBalanceCounter.consolidate()
conn = get(conn, chain_path(BlockScoutWeb.Endpoint, :show)) conn = get(conn, chain_path(BlockScoutWeb.Endpoint, :show))
assert(html_response(conn, 200) =~ "POA") assert(html_response(conn, 200) =~ "POA")
@ -14,6 +20,10 @@ defmodule BlockScoutWeb.ChainControllerTest do
test "returns a block", %{conn: conn} do test "returns a block", %{conn: conn} do
insert(:block, %{number: 23}) insert(:block, %{number: 23})
start_supervised!(AddressesWithBalanceCounter)
AddressesWithBalanceCounter.consolidate()
conn = get(conn, "/") conn = get(conn, "/")
assert(List.first(conn.assigns.blocks).number == 23) 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 test "excludes all but the most recent five blocks", %{conn: conn} do
old_block = insert(:block) old_block = insert(:block)
insert_list(5, :block) insert_list(5, :block)
start_supervised!(AddressesWithBalanceCounter)
AddressesWithBalanceCounter.consolidate()
conn = get(conn, "/") conn = get(conn, "/")
refute(Enum.member?(conn.assigns.blocks, old_block)) refute(Enum.member?(conn.assigns.blocks, old_block))
@ -35,6 +49,9 @@ defmodule BlockScoutWeb.ChainControllerTest do
unassociated = insert(:transaction) unassociated = insert(:transaction)
start_supervised!(AddressesWithBalanceCounter)
AddressesWithBalanceCounter.consolidate()
conn = get(conn, "/") conn = get(conn, "/")
transaction_hashes = Enum.map(conn.assigns.transactions, fn transaction -> transaction.hash end) transaction_hashes = Enum.map(conn.assigns.transactions, fn transaction -> transaction.hash end)
@ -49,6 +66,9 @@ defmodule BlockScoutWeb.ChainControllerTest do
|> insert() |> insert()
|> with_block() |> with_block()
start_supervised!(AddressesWithBalanceCounter)
AddressesWithBalanceCounter.consolidate()
conn = get(conn, "/") conn = get(conn, "/")
assert(List.first(conn.assigns.transactions).hash == transaction.hash) assert(List.first(conn.assigns.transactions).hash == transaction.hash)
@ -58,6 +78,9 @@ defmodule BlockScoutWeb.ChainControllerTest do
today = Date.utc_today() today = Date.utc_today()
for day <- -40..0, do: insert(:market_history, date: Date.add(today, day)) for day <- -40..0, do: insert(:market_history, date: Date.add(today, day))
start_supervised!(AddressesWithBalanceCounter)
AddressesWithBalanceCounter.consolidate()
conn = get(conn, "/") conn = get(conn, "/")
assert Map.has_key?(conn.assigns, :market_history_data) 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) insert(:block, miner: miner_address, miner_hash: nil)
start_supervised!(AddressesWithBalanceCounter)
AddressesWithBalanceCounter.consolidate()
conn = get(conn, chain_path(conn, :show)) conn = get(conn, chain_path(conn, :show))
assert html_response(conn, 200) =~ miner_name assert html_response(conn, 200) =~ miner_name
end end

@ -59,12 +59,9 @@ defmodule BlockScoutWeb.PendingTransactionControllerTest do
end end
test "next_page_path exist if not on last page", %{conn: conn} do test "next_page_path exist if not on last page", %{conn: conn} do
%Transaction{inserted_at: inserted_at, hash: hash} = 60
60 |> insert_list(:transaction)
|> insert_list(:transaction) |> Enum.fetch!(10)
|> Enum.fetch!(10)
converted_date = DateTime.to_iso8601(inserted_at)
conn = get(conn, pending_transaction_path(BlockScoutWeb.Endpoint, :index, %{"type" => "JSON"})) conn = get(conn, pending_transaction_path(BlockScoutWeb.Endpoint, :index, %{"type" => "JSON"}))

@ -1,7 +1,10 @@
defmodule BlockScoutWeb.Tokens.HolderControllerTest do 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.Chain.Hash
alias Explorer.Counters.{TokenHoldersCounter, TokenTransferCounter}
describe "GET index/3" do describe "GET index/3" do
test "with invalid address hash", %{conn: conn} 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 token_contract_address_hash: token.contract_address_hash
) )
start_supervised!(TokenHoldersCounter)
TokenHoldersCounter.consolidate()
start_supervised!(TokenTransferCounter)
TokenTransferCounter.consolidate()
conn = conn =
get( get(
conn, conn,

@ -1,5 +1,9 @@
defmodule BlockScoutWeb.Tokens.InventoryControllerTest do 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 describe "GET index/3" do
test "with invalid address hash", %{conn: conn} do test "with invalid address hash", %{conn: conn} do
@ -31,6 +35,12 @@ defmodule BlockScoutWeb.Tokens.InventoryControllerTest do
token: token token: token
) )
start_supervised!(TokenHoldersCounter)
TokenHoldersCounter.consolidate()
start_supervised!(TokenTransferCounter)
TokenTransferCounter.consolidate()
conn = conn =
get( get(
conn, conn,
@ -60,6 +70,12 @@ defmodule BlockScoutWeb.Tokens.InventoryControllerTest do
) )
) )
start_supervised!(TokenHoldersCounter)
TokenHoldersCounter.consolidate()
start_supervised!(TokenTransferCounter)
TokenTransferCounter.consolidate()
conn = conn =
get(conn, token_inventory_path(conn, :index, token.contract_address_hash), %{ get(conn, token_inventory_path(conn, :index, token.contract_address_hash), %{
"token_id" => "999" "token_id" => "999"
@ -92,6 +108,12 @@ defmodule BlockScoutWeb.Tokens.InventoryControllerTest do
"unique_token" => 1050 "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)) conn = get(conn, token_inventory_path(conn, :index, token.contract_address_hash))
assert conn.assigns.next_page_params == expected_next_page_params assert conn.assigns.next_page_params == expected_next_page_params
@ -113,6 +135,12 @@ defmodule BlockScoutWeb.Tokens.InventoryControllerTest do
token_id: 1000 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)) conn = get(conn, token_inventory_path(conn, :index, token.contract_address_hash))
refute conn.assigns.next_page_params refute conn.assigns.next_page_params

@ -1,5 +1,9 @@
defmodule BlockScoutWeb.Tokens.ReadContractControllerTest do 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 describe "GET index/3" do
test "with invalid address hash", %{conn: conn} do test "with invalid address hash", %{conn: conn} do
@ -26,6 +30,12 @@ defmodule BlockScoutWeb.Tokens.ReadContractControllerTest do
token: token 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)) conn = get(conn, token_read_contract_path(BlockScoutWeb.Endpoint, :index, token.contract_address_hash))
assert html_response(conn, 200) assert html_response(conn, 200)

@ -1,10 +1,11 @@
defmodule BlockScoutWeb.TransactionControllerTest do defmodule BlockScoutWeb.TransactionControllerTest do
use BlockScoutWeb.ConnCase use BlockScoutWeb.ConnCase
alias Explorer.Chain.{Block, Transaction}
import BlockScoutWeb.Router.Helpers, import BlockScoutWeb.Router.Helpers,
only: [transaction_path: 3, transaction_internal_transaction_path: 3, transaction_token_transfer_path: 3] only: [transaction_path: 3, transaction_internal_transaction_path: 3, transaction_token_transfer_path: 3]
alias Explorer.Chain.Transaction
describe "GET index/2" do describe "GET index/2" do
test "returns a collated transactions", %{conn: conn} do test "returns a collated transactions", %{conn: conn} do
:transaction :transaction

@ -1,9 +1,10 @@
defmodule BlockScoutWeb.AddressContractVerificationTest do defmodule BlockScoutWeb.AddressContractVerificationTest do
use BlockScoutWeb.FeatureCase, async: true use BlockScoutWeb.FeatureCase, async: true
alias Plug.Conn
alias Explorer.Factory
alias BlockScoutWeb.{AddressContractPage, ContractVerifyPage} alias BlockScoutWeb.{AddressContractPage, ContractVerifyPage}
alias Explorer.Counters.BlockValidationCounter
alias Explorer.Factory
alias Plug.Conn
setup do setup do
bypass = Bypass.open() bypass = Bypass.open()
@ -29,6 +30,9 @@ defmodule BlockScoutWeb.AddressContractVerificationTest do
transaction: transaction transaction: transaction
) )
start_supervised!(BlockValidationCounter)
BlockValidationCounter.consolidate_blocks()
session session
|> AddressContractPage.visit_page(address) |> AddressContractPage.visit_page(address)
|> AddressContractPage.click_verify_and_publish() |> AddressContractPage.click_verify_and_publish()

@ -1,6 +1,9 @@
defmodule BlockScoutWeb.ViewingAddressesTest do 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} alias BlockScoutWeb.{AddressPage, AddressView, Notifier}
setup do setup do
@ -38,6 +41,12 @@ defmodule BlockScoutWeb.ViewingAddressesTest do
[first_address | _] = addresses [first_address | _] = addresses
[last_address | _] = Enum.reverse(addresses) [last_address | _] = Enum.reverse(addresses)
start_supervised!(BlockValidationCounter)
BlockValidationCounter.consolidate_blocks()
start_supervised!(AddressesWithBalanceCounter)
AddressesWithBalanceCounter.consolidate()
session session
|> AddressPage.visit_page() |> AddressPage.visit_page()
|> assert_has(AddressPage.address(first_address)) |> assert_has(AddressPage.address(first_address))
@ -48,6 +57,9 @@ defmodule BlockScoutWeb.ViewingAddressesTest do
test "viewing address overview information", %{session: session} do test "viewing address overview information", %{session: session} do
address = insert(:address, fetched_coin_balance: 500) address = insert(:address, fetched_coin_balance: 500)
start_supervised!(BlockValidationCounter)
BlockValidationCounter.consolidate_blocks()
session session
|> AddressPage.visit_page(address) |> AddressPage.visit_page(address)
|> assert_text(AddressPage.balance(), "0.0000000000000005 POA") |> assert_text(AddressPage.balance(), "0.0000000000000005 POA")
@ -68,6 +80,9 @@ defmodule BlockScoutWeb.ViewingAddressesTest do
created_contract_address: contract created_contract_address: contract
) )
start_supervised!(BlockValidationCounter)
BlockValidationCounter.consolidate_blocks()
address_hash = AddressView.trimmed_hash(address.hash) address_hash = AddressView.trimmed_hash(address.hash)
transaction_hash = AddressView.trimmed_hash(transaction.hash) transaction_hash = AddressView.trimmed_hash(transaction.hash)
@ -101,6 +116,9 @@ defmodule BlockScoutWeb.ViewingAddressesTest do
created_contract_address: another_contract created_contract_address: another_contract
) )
start_supervised!(BlockValidationCounter)
BlockValidationCounter.consolidate_blocks()
contract_hash = AddressView.trimmed_hash(contract.hash) contract_hash = AddressView.trimmed_hash(contract.hash)
transaction_hash = AddressView.trimmed_hash(transaction.hash) transaction_hash = AddressView.trimmed_hash(transaction.hash)
@ -111,6 +129,13 @@ defmodule BlockScoutWeb.ViewingAddressesTest do
end end
describe "viewing transactions" do describe "viewing transactions" do
setup do
start_supervised!(BlockValidationCounter)
BlockValidationCounter.consolidate_blocks()
:ok
end
test "sees all addresses transactions by default", %{ test "sees all addresses transactions by default", %{
addresses: addresses, addresses: addresses,
session: session, session: session,
@ -189,6 +214,9 @@ defmodule BlockScoutWeb.ViewingAddressesTest do
internal_transaction_lincoln_to_address: internal_transaction, internal_transaction_lincoln_to_address: internal_transaction,
session: session session: session
} do } do
start_supervised!(BlockValidationCounter)
BlockValidationCounter.consolidate_blocks()
session session
|> AddressPage.visit_page(addresses.lincoln) |> AddressPage.visit_page(addresses.lincoln)
|> AddressPage.click_internal_transactions() |> AddressPage.click_internal_transactions()
@ -202,6 +230,9 @@ defmodule BlockScoutWeb.ViewingAddressesTest do
|> insert(from_address: addresses.lincoln) |> insert(from_address: addresses.lincoln)
|> with_block(insert(:block, number: 7000)) |> with_block(insert(:block, number: 7000))
start_supervised!(BlockValidationCounter)
BlockValidationCounter.consolidate_blocks()
session session
|> AddressPage.visit_page(addresses.lincoln) |> AddressPage.visit_page(addresses.lincoln)
|> AddressPage.click_internal_transactions() |> AddressPage.click_internal_transactions()
@ -249,6 +280,9 @@ defmodule BlockScoutWeb.ViewingAddressesTest do
token_contract_address: contract_address token_contract_address: contract_address
) )
start_supervised!(BlockValidationCounter)
BlockValidationCounter.consolidate_blocks()
session session
|> AddressPage.visit_page(lincoln) |> AddressPage.visit_page(lincoln)
|> assert_has(AddressPage.token_transfers(transaction, count: 1)) |> assert_has(AddressPage.token_transfers(transaction, count: 1))
@ -290,6 +324,9 @@ defmodule BlockScoutWeb.ViewingAddressesTest do
token_contract_address: contract_address token_contract_address: contract_address
) )
start_supervised!(BlockValidationCounter)
BlockValidationCounter.consolidate_blocks()
session session
|> AddressPage.visit_page(morty) |> AddressPage.visit_page(morty)
|> assert_has(AddressPage.token_transfers(transaction, count: 1)) |> assert_has(AddressPage.token_transfers(transaction, count: 1))
@ -324,6 +361,9 @@ defmodule BlockScoutWeb.ViewingAddressesTest do
token_contract_address: contract_address token_contract_address: contract_address
) )
start_supervised!(BlockValidationCounter)
BlockValidationCounter.consolidate_blocks()
session session
|> AddressPage.visit_page(lincoln) |> AddressPage.visit_page(lincoln)
|> assert_has(AddressPage.token_transfers(transaction, count: 1)) |> assert_has(AddressPage.token_transfers(transaction, count: 1))
@ -354,6 +394,9 @@ defmodule BlockScoutWeb.ViewingAddressesTest do
token_contract_address: contract_address token_contract_address: contract_address
) )
start_supervised!(BlockValidationCounter)
BlockValidationCounter.consolidate_blocks()
session session
|> AddressPage.visit_page(lincoln) |> AddressPage.visit_page(lincoln)
|> click(AddressPage.token_transfers_expansion(transaction)) |> 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) insert(:token_balance, address: lincoln, token_contract_address_hash: contract_address.hash)
start_supervised!(BlockValidationCounter)
BlockValidationCounter.consolidate_blocks()
session session
|> AddressPage.visit_page(lincoln) |> AddressPage.visit_page(lincoln)
|> AddressPage.click_tokens() |> 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) insert(:address_current_token_balance, address: lincoln, token_contract_address_hash: contract_address_2.hash)
start_supervised!(BlockValidationCounter)
BlockValidationCounter.consolidate_blocks()
{:ok, lincoln: lincoln} {:ok, lincoln: lincoln}
end 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: 5, block_number: block.number)
insert(:fetched_balance, address_hash: address.hash, value: 10, block_number: block_one_day_ago.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} {:ok, address: address}
end end

@ -4,6 +4,7 @@ defmodule BlockScoutWeb.ViewingAppTest do
use BlockScoutWeb.FeatureCase, async: true use BlockScoutWeb.FeatureCase, async: true
alias BlockScoutWeb.{AppPage, Notifier} alias BlockScoutWeb.{AppPage, Notifier}
alias Explorer.Counters.AddressesWithBalanceCounter
describe "loading bar when indexing" do describe "loading bar when indexing" do
test "shows blocks indexed percentage", %{session: session} do test "shows blocks indexed percentage", %{session: session} do
@ -11,6 +12,9 @@ defmodule BlockScoutWeb.ViewingAppTest do
insert(:block, number: index) insert(:block, number: index)
end end
start_supervised!(AddressesWithBalanceCounter)
AddressesWithBalanceCounter.consolidate()
assert Explorer.Chain.indexed_ratio() == 0.5 assert Explorer.Chain.indexed_ratio() == 0.5
session session
@ -23,6 +27,9 @@ defmodule BlockScoutWeb.ViewingAppTest do
insert(:block, number: index) insert(:block, number: index)
end end
start_supervised!(AddressesWithBalanceCounter)
AddressesWithBalanceCounter.consolidate()
assert Explorer.Chain.indexed_ratio() == 1.0 assert Explorer.Chain.indexed_ratio() == 1.0
session session
@ -35,6 +42,9 @@ defmodule BlockScoutWeb.ViewingAppTest do
insert(:block, number: index) insert(:block, number: index)
end end
start_supervised!(AddressesWithBalanceCounter)
AddressesWithBalanceCounter.consolidate()
assert Explorer.Chain.indexed_ratio() == 0.5 assert Explorer.Chain.indexed_ratio() == 0.5
session session
@ -52,6 +62,9 @@ defmodule BlockScoutWeb.ViewingAppTest do
insert(:block, number: index) insert(:block, number: index)
end end
start_supervised!(AddressesWithBalanceCounter)
AddressesWithBalanceCounter.consolidate()
assert Explorer.Chain.indexed_ratio() == 0.9 assert Explorer.Chain.indexed_ratio() == 0.9
session session
@ -70,6 +83,9 @@ defmodule BlockScoutWeb.ViewingAppTest do
insert(:block, number: index) insert(:block, number: index)
end end
start_supervised!(AddressesWithBalanceCounter)
AddressesWithBalanceCounter.consolidate()
assert Explorer.Chain.indexed_ratio() == 1.0 assert Explorer.Chain.indexed_ratio() == 1.0
session session

@ -1,10 +1,13 @@
defmodule BlockScoutWeb.ViewingChainTest do defmodule BlockScoutWeb.ViewingChainTest do
@moduledoc false @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 BlockScoutWeb.{AddressPage, BlockPage, ChainPage, TransactionPage}
alias Explorer.Chain.Block alias Explorer.Chain.Block
alias Explorer.Counters.{AddressesWithBalanceCounter, BlockValidationCounter}
setup do setup do
Enum.map(401..404, &insert(:block, number: &1)) Enum.map(401..404, &insert(:block, number: &1))
@ -29,6 +32,12 @@ defmodule BlockScoutWeb.ViewingChainTest do
test "search for address", %{session: session} do test "search for address", %{session: session} do
address = insert(:address) address = insert(:address)
start_supervised!(AddressesWithBalanceCounter)
AddressesWithBalanceCounter.consolidate()
start_supervised!(BlockValidationCounter)
BlockValidationCounter.consolidate_blocks()
session session
|> ChainPage.visit_page() |> ChainPage.visit_page()
|> ChainPage.search(to_string(address.hash)) |> ChainPage.search(to_string(address.hash))
@ -40,6 +49,9 @@ defmodule BlockScoutWeb.ViewingChainTest do
test "search for blocks from chain page", %{session: session} do test "search for blocks from chain page", %{session: session} do
block = insert(:block, number: 6) block = insert(:block, number: 6)
start_supervised!(AddressesWithBalanceCounter)
AddressesWithBalanceCounter.consolidate()
session session
|> ChainPage.visit_page() |> ChainPage.visit_page()
|> ChainPage.search(to_string(block.number)) |> ChainPage.search(to_string(block.number))
@ -47,6 +59,9 @@ defmodule BlockScoutWeb.ViewingChainTest do
end end
test "blocks list", %{session: session} do test "blocks list", %{session: session} do
start_supervised!(AddressesWithBalanceCounter)
AddressesWithBalanceCounter.consolidate()
session session
|> ChainPage.visit_page() |> ChainPage.visit_page()
|> assert_has(ChainPage.blocks(count: 4)) |> 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 test "inserts place holder blocks on render for out of order blocks", %{session: session} do
insert(:block, number: 409) insert(:block, number: 409)
start_supervised!(AddressesWithBalanceCounter)
AddressesWithBalanceCounter.consolidate()
session session
|> ChainPage.visit_page() |> ChainPage.visit_page()
|> assert_has(ChainPage.block(%Block{number: 408})) |> assert_has(ChainPage.block(%Block{number: 408}))
@ -66,6 +84,9 @@ defmodule BlockScoutWeb.ViewingChainTest do
test "search for transactions", %{session: session} do test "search for transactions", %{session: session} do
transaction = insert(:transaction) transaction = insert(:transaction)
start_supervised!(AddressesWithBalanceCounter)
AddressesWithBalanceCounter.consolidate()
session session
|> ChainPage.visit_page() |> ChainPage.visit_page()
|> ChainPage.search(to_string(transaction.hash)) |> ChainPage.search(to_string(transaction.hash))
@ -73,6 +94,9 @@ defmodule BlockScoutWeb.ViewingChainTest do
end end
test "transactions list", %{session: session} do test "transactions list", %{session: session} do
start_supervised!(AddressesWithBalanceCounter)
AddressesWithBalanceCounter.consolidate()
session session
|> ChainPage.visit_page() |> ChainPage.visit_page()
|> assert_has(ChainPage.transactions(count: 5)) |> assert_has(ChainPage.transactions(count: 5))
@ -87,6 +111,9 @@ defmodule BlockScoutWeb.ViewingChainTest do
|> with_contract_creation(contract_address) |> with_contract_creation(contract_address)
|> with_block(block) |> with_block(block)
start_supervised!(AddressesWithBalanceCounter)
AddressesWithBalanceCounter.consolidate()
session session
|> ChainPage.visit_page() |> ChainPage.visit_page()
|> assert_has(ChainPage.contract_creation(transaction)) |> assert_has(ChainPage.contract_creation(transaction))
@ -111,6 +138,9 @@ defmodule BlockScoutWeb.ViewingChainTest do
token_contract_address: contract_token_address token_contract_address: contract_token_address
) )
start_supervised!(AddressesWithBalanceCounter)
AddressesWithBalanceCounter.consolidate()
session session
|> ChainPage.visit_page() |> ChainPage.visit_page()
|> assert_has(ChainPage.token_transfers(transaction, count: 1)) |> assert_has(ChainPage.token_transfers(transaction, count: 1))

@ -1,6 +1,7 @@
defmodule BlockScoutWeb.ViewingTokensTest do defmodule BlockScoutWeb.ViewingTokensTest do
use BlockScoutWeb.FeatureCase, async: true use BlockScoutWeb.FeatureCase, async: true
alias Explorer.Counters.{TokenHoldersCounter, TokenTransferCounter}
alias BlockScoutWeb.TokenPage alias BlockScoutWeb.TokenPage
describe "viewing token holders" do describe "viewing token holders" do
@ -13,6 +14,12 @@ defmodule BlockScoutWeb.ViewingTokensTest do
token_contract_address_hash: token.contract_address_hash token_contract_address_hash: token.contract_address_hash
) )
start_supervised!(TokenHoldersCounter)
TokenHoldersCounter.consolidate()
start_supervised!(TokenTransferCounter)
TokenTransferCounter.consolidate()
session session
|> TokenPage.visit_page(token.contract_address) |> TokenPage.visit_page(token.contract_address)
|> assert_has(TokenPage.token_holders(count: 2)) |> assert_has(TokenPage.token_holders(count: 2))

@ -1,10 +1,13 @@
defmodule BlockScoutWeb.ViewingTransactionsTest do defmodule BlockScoutWeb.ViewingTransactionsTest do
@moduledoc false @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 BlockScoutWeb.{AddressPage, TransactionListPage, TransactionLogsPage, TransactionPage}
alias Explorer.Chain.Wei
alias Explorer.Counters.BlockValidationCounter
setup do setup do
block = block =
@ -139,6 +142,8 @@ defmodule BlockScoutWeb.ViewingTransactionsTest do
session: session, session: session,
transaction: transaction transaction: transaction
} do } do
start_supervised!(BlockValidationCounter)
session session
|> TransactionLogsPage.visit_page(transaction) |> TransactionLogsPage.visit_page(transaction)
|> TransactionLogsPage.click_address(lincoln) |> TransactionLogsPage.click_address(lincoln)

@ -94,7 +94,7 @@ defmodule BlockScoutWeb.TransactionViewTest do
test "with fee" do test "with fee" do
{:ok, gas_price} = Wei.cast(3_000_000_000) {: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" expected_value = "0.003102702 POA"
assert expected_value == TransactionView.formatted_fee(transaction, denomination: :ether) assert expected_value == TransactionView.formatted_fee(transaction, denomination: :ether)

@ -5,37 +5,33 @@
# is restricted to this project. # is restricted to this project.
use Mix.Config use Mix.Config
config :ecto, json_library: Jason
# General application configuration # General application configuration
config :explorer, config :explorer,
ecto_repos: [Explorer.Repo], ecto_repos: [Explorer.Repo],
coin: System.get_env("COIN") || "POA", coin: System.get_env("COIN") || "POA",
token_functions_reader_max_retries: 3 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.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.Market.History.Cataloger, enabled: true
config :explorer, Explorer.Repo, config :explorer, Explorer.Repo, migration_timestamps: [type: :utc_datetime_usec]
loggers: [Explorer.Repo.PrometheusLogger, Ecto.LogEntry],
migration_timestamps: [type: :utc_datetime]
config :explorer, Explorer.Tracer, config :explorer, Explorer.Tracer,
service: :explorer, service: :explorer,
adapter: SpandexDatadog.Adapter, adapter: SpandexDatadog.Adapter,
trace_key: :blockscout 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 if System.get_env("SUPPLY_MODULE") == "TransactionAndLog" do
config :explorer, supply: Explorer.Chain.Supply.TransactionAndLog config :explorer, supply: Explorer.Chain.Supply.TransactionAndLog
end end

@ -2,11 +2,9 @@ use Mix.Config
# Configure your database # Configure your database
config :explorer, Explorer.Repo, config :explorer, Explorer.Repo,
adapter: Ecto.Adapters.Postgres,
database: "explorer_dev", database: "explorer_dev",
hostname: "localhost", hostname: "localhost",
pool_size: 20, pool_size: 20,
pool_timeout: 60_000,
timeout: 80_000 timeout: 80_000
config :explorer, Explorer.Tracer, env: "dev", disabled?: true config :explorer, Explorer.Tracer, env: "dev", disabled?: true

@ -2,12 +2,9 @@ use Mix.Config
# Configure your database # Configure your database
config :explorer, Explorer.Repo, config :explorer, Explorer.Repo,
adapter: Ecto.Adapters.Postgres,
database: "explorer_dev", database: "explorer_dev",
hostname: "localhost", hostname: "localhost",
username: "postgres", username: "postgres",
password: "<REPLACE WITH THE PASSWORD YOU CHOSE>", password: "<REPLACE WITH THE PASSWORD YOU CHOSE>",
loggers: [Explorer.Repo.PrometheusLogger],
pool_size: 20, pool_size: 20,
pool_timeout: 60_000,
timeout: 80_000 timeout: 80_000

@ -2,7 +2,6 @@ use Mix.Config
# Configures the database # Configures the database
config :explorer, Explorer.Repo, config :explorer, Explorer.Repo,
adapter: Ecto.Adapters.Postgres,
url: System.get_env("DATABASE_URL"), url: System.get_env("DATABASE_URL"),
pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10"), pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10"),
ssl: String.equivalent?(System.get_env("ECTO_USE_SSL") || "true", "true"), ssl: String.equivalent?(System.get_env("ECTO_USE_SSL") || "true", "true"),

@ -5,25 +5,27 @@ config :bcrypt_elixir, log_rounds: 4
# Configure your database # Configure your database
config :explorer, Explorer.Repo, config :explorer, Explorer.Repo,
adapter: Ecto.Adapters.Postgres,
database: "explorer_test", database: "explorer_test",
hostname: "localhost", hostname: "localhost",
pool: Ecto.Adapters.SQL.Sandbox, pool: Ecto.Adapters.SQL.Sandbox,
# Default of `5_000` was too low for `BlockFetcher` test # Default of `5_000` was too low for `BlockFetcher` test
pool_timeout: 10_000,
ownership_timeout: 60_000 ownership_timeout: 60_000
config :explorer, Explorer.ExchangeRates, enabled: false, store: :ets 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, config :logger, :explorer,
level: :warn, level: :warn,

@ -2,7 +2,6 @@ use Mix.Config
# Configure your database # Configure your database
config :explorer, Explorer.Repo, config :explorer, Explorer.Repo,
adapter: Ecto.Adapters.Postgres,
database: "explorer_test", database: "explorer_test",
hostname: "localhost", hostname: "localhost",
pool: Ecto.Adapters.SQL.Sandbox, pool: Ecto.Adapters.SQL.Sandbox,

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

@ -3,7 +3,7 @@ defmodule Explorer.Accounts.User.Authenticate do
Represents the data required to authenticate a user. Represents the data required to authenticate a user.
""" """
use Ecto.Schema use Explorer.Schema
import Ecto.Changeset import Ecto.Changeset

@ -3,7 +3,7 @@ defmodule Explorer.Accounts.User.Registration do
Represents the data required to register a new account. Represents the data required to register a new account.
""" """
use Ecto.Schema use Explorer.Schema
import Ecto.Changeset 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. given user. Additionally, a user can only have 1 primary contact at a time.
""" """
use Ecto.Schema use Explorer.Schema
import Ecto.Changeset import Ecto.Changeset

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

@ -12,6 +12,8 @@ defmodule Explorer.Application do
def start(_type, _args) do def start(_type, _args) do
PrometheusLogger.setup() PrometheusLogger.setup()
Telemetry.attach("prometheus-ecto", [:explorer, :repo, :query], Explorer.Repo.PrometheusLogger, :handle_event, %{})
# Children to start in all environments # Children to start in all environments
base_children = [ base_children = [
Explorer.Repo, Explorer.Repo,
@ -36,7 +38,7 @@ defmodule Explorer.Application do
configure(Explorer.Counters.TokenHoldersCounter), configure(Explorer.Counters.TokenHoldersCounter),
configure(Explorer.Counters.TokenTransferCounter), configure(Explorer.Counters.TokenTransferCounter),
configure(Explorer.Counters.BlockValidationCounter), configure(Explorer.Counters.BlockValidationCounter),
configure(Explorer.Counters.AddessesWithBalanceCounter) configure(Explorer.Counters.AddressesWithBalanceCounter)
] ]
|> List.flatten() |> List.flatten()
end end

@ -42,13 +42,14 @@ defmodule Explorer.Chain do
alias Explorer.{PagingOptions, Repo} alias Explorer.{PagingOptions, Repo}
alias Explorer.Counters.{ alias Explorer.Counters.{
AddessesWithBalanceCounter, AddressesWithBalanceCounter,
BlockValidationCounter, BlockValidationCounter,
TokenHoldersCounter, TokenHoldersCounter,
TokenTransferCounter TokenTransferCounter
} }
alias Dataloader.Ecto, as: DataloaderEcto alias Dataloader.Ecto, as: DataloaderEcto
alias Timex.Duration
@default_paging_options %PagingOptions{page_size: 50} @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() @spec count_addresses_with_balance_from_cache :: non_neg_integer()
def count_addresses_with_balance_from_cache do def count_addresses_with_balance_from_cache do
AddessesWithBalanceCounter.fetch() AddressesWithBalanceCounter.fetch()
end end
@doc """ @doc """
@ -280,7 +281,7 @@ defmodule Explorer.Chain do
""" """
@spec average_block_time :: %Timex.Duration{} @spec average_block_time :: %Timex.Duration{}
def average_block_time do def average_block_time do
{:ok, %Postgrex.Result{rows: [[rows]]}} = {:ok, %Postgrex.Result{rows: [[%Postgrex.Interval{months: 0, days: days, secs: seconds}]]}} =
SQL.query( SQL.query(
Repo, Repo,
""" """
@ -294,9 +295,10 @@ defmodule Explorer.Chain do
[] []
) )
{:ok, value} = Timex.Ecto.Time.load(rows) hours = days * 24
minutes = 0
value microseconds = 0
Duration.from_clock({hours, minutes, seconds, microseconds})
end end
@doc """ @doc """
@ -1256,24 +1258,24 @@ defmodule Explorer.Chain do
missing_block_number_range in fragment( missing_block_number_range in fragment(
# adapted from https://www.xaprb.com/blog/2006/03/22/find-contiguous-ranges-with-sql/ # adapted from https://www.xaprb.com/blog/2006/03/22/find-contiguous-ranges-with-sql/
""" """
WITH missing_blocks AS (WITH missing_blocks AS
(SELECT number (SELECT number
FROM generate_series(? :: bigint, ? :: bigint, ? :: bigint) AS number FROM generate_series(? :: bigint, ? :: bigint, ? :: bigint) AS number
EXCEPT EXCEPT
SELECT blocks.number SELECT blocks.number
FROM blocks FROM blocks
WHERE blocks.consensus = true) WHERE blocks.consensus = true)
SELECT no_previous.number AS minimum, SELECT no_previous.number AS minimum,
(SELECT MIN(no_next.number) (SELECT MIN(no_next.number)
FROM missing_blocks AS no_next FROM missing_blocks AS no_next
LEFT OUTER JOIN missing_blocks AS next LEFT OUTER JOIN missing_blocks AS next
ON no_next.number = next.number - 1 ON no_next.number = next.number - 1
WHERE next.number IS NULL AND WHERE next.number IS NULL AND
no_next.number >= no_previous.number) AS maximum no_next.number >= no_previous.number) AS maximum
FROM missing_blocks as no_previous FROM missing_blocks as no_previous
LEFT OUTER JOIN missing_blocks AS previous LEFT OUTER JOIN missing_blocks AS previous
ON previous.number = no_previous.number - 1 ON previous.number = no_previous.number - 1
WHERE previous.number IS NULL WHERE previous.number IS NULL)
""", """,
^range_start, ^range_start,
^range_end, ^range_end,
@ -1699,8 +1701,8 @@ defmodule Explorer.Chain do
insert_result = insert_result =
Multi.new() Multi.new()
|> Multi.insert(:smart_contract, smart_contract_changeset) |> Multi.insert(:smart_contract, smart_contract_changeset)
|> Multi.run(:clear_primary_address_names, &clear_primary_address_names/1) |> Multi.run(:clear_primary_address_names, &clear_primary_address_names/2)
|> Multi.run(:insert_address_name, &create_address_name/1) |> Multi.run(:insert_address_name, &create_address_name/2)
|> Repo.transaction() |> Repo.transaction()
with {:ok, %{smart_contract: smart_contract}} <- insert_result do with {:ok, %{smart_contract: smart_contract}} <- insert_result do
@ -1711,7 +1713,7 @@ defmodule Explorer.Chain do
end end
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 = clear_primary_query =
from( from(
address_name in Address.Name, address_name in Address.Name,
@ -1719,12 +1721,12 @@ defmodule Explorer.Chain do
update: [set: [primary: false]] update: [set: [primary: false]]
) )
Repo.update_all(clear_primary_query, []) repo.update_all(clear_primary_query, [])
{:ok, []} {:ok, []}
end 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 = %{ params = %{
address_hash: address_hash, address_hash: address_hash,
name: name, name: name,
@ -1733,7 +1735,7 @@ defmodule Explorer.Chain do
%Address.Name{} %Address.Name{}
|> Address.Name.changeset(params) |> 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 end
@spec address_hash_to_smart_contract(%Explorer.Chain.Hash{}) :: %Explorer.Chain.SmartContract{} | nil @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.insert(:token, token_changeset, token_opts)
|> Multi.run( |> Multi.run(
:address_name, :address_name,
fn _ -> fn repo, _ ->
{:ok, Repo.insert(address_name_changeset, address_name_opts)} {:ok, repo.insert(address_name_changeset, address_name_opts)}
end end
) )
|> Repo.transaction() |> Repo.transaction()
@ -2077,19 +2079,12 @@ defmodule Explorer.Chain do
defp normalize_balances_by_day(balances_by_day) do defp normalize_balances_by_day(balances_by_day) do
balances_by_day 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.map(fn day -> Map.take(day, [:date, :value]) end)
|> Enum.filter(fn day -> day.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, :date, &to_string(&1)) end)
|> Enum.map(fn day -> Map.update!(day, :value, &Wei.to(&1, :ether)) end) |> Enum.map(fn day -> Map.update!(day, :value, &Wei.to(&1, :ether)) end)
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()] @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 def fetch_token_holders_from_token_hash(contract_address_hash, options) do
contract_address_hash contract_address_hash

@ -40,9 +40,9 @@ defmodule Explorer.Chain.Address.CoinBalance do
schema "address_coin_balances" do schema "address_coin_balances" do
field(:block_number, :integer) field(:block_number, :integer)
field(:value, Wei) field(:value, Wei)
field(:value_fetched_at, :utc_datetime) field(:value_fetched_at, :utc_datetime_usec)
field(:delta, Wei, virtual: true) field(:delta, Wei, virtual: true)
field(:block_timestamp, :utc_datetime, virtual: true) field(:block_timestamp, :utc_datetime_usec, virtual: true)
timestamps() timestamps()
@ -91,12 +91,12 @@ defmodule Explorer.Chain.Address.CoinBalance do
""" """
def balances_by_day(address_hash) do def balances_by_day(address_hash) do
CoinBalance 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], cb.address_hash == ^address_hash)
|> where([cb, b], b.timestamp >= fragment("date_trunc('day', now()) - interval '90 days'")) |> where([cb, b], b.timestamp >= fragment("date_trunc('day', now()) - interval '90 days'"))
|> group_by([cb, b], fragment("date_trunc('day', ?)", b.timestamp)) |> group_by([cb, b], fragment("date_trunc('day', ?)", b.timestamp))
|> order_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 end
def changeset(%__MODULE__{} = balance, params) do def changeset(%__MODULE__{} = balance, params) do

@ -6,7 +6,8 @@ defmodule Explorer.Chain.Address.CurrentTokenBalance do
token balances look at the `Address.TokenBalance` instead. token balances look at the `Address.TokenBalance` instead.
""" """
use Ecto.Schema use Explorer.Schema
import Ecto.Changeset import Ecto.Changeset
import Ecto.Query, only: [from: 2, limit: 2, order_by: 3, preload: 2, where: 3] 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 schema "address_current_token_balances" do
field(:value, :decimal) field(:value, :decimal)
field(:block_number, :integer) 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) 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. Represents a name for an Address.
""" """
use Ecto.Schema use Explorer.Schema
import Ecto.Changeset import Ecto.Changeset

@ -7,7 +7,8 @@ defmodule Explorer.Chain.Address.TokenBalance do
`Address.CurrentTokenBalance` instead. `Address.CurrentTokenBalance` instead.
""" """
use Ecto.Schema use Explorer.Schema
import Ecto.Changeset import Ecto.Changeset
import Ecto.Query, only: [from: 2, subquery: 1] import Ecto.Query, only: [from: 2, subquery: 1]
@ -37,7 +38,7 @@ defmodule Explorer.Chain.Address.TokenBalance do
schema "address_token_balances" do schema "address_token_balances" do
field(:value, :decimal) field(:value, :decimal)
field(:block_number, :integer) 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) 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(:nonce, Hash.Nonce)
field(:number, :integer) field(:number, :integer)
field(:size, :integer) field(:size, :integer)
field(:timestamp, :utc_datetime) field(:timestamp, :utc_datetime_usec)
field(:total_difficulty, :decimal) field(:total_difficulty, :decimal)
timestamps() timestamps()

@ -46,7 +46,7 @@ defmodule Explorer.Chain.Block.SecondDegreeRelation do
@primary_key false @primary_key false
schema "block_second_degree_relations" do 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(:nephew, Block, foreign_key: :nephew_hash, references: :hash, type: Hash.Full)
belongs_to(:uncle, Block, foreign_key: :uncle_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)
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) ecto_schema_module = Keyword.fetch!(options, :for)
timestamped_changes_list = timestamp_changes_list(changes_list, Keyword.fetch!(options, :timestamps)) timestamped_changes_list = timestamp_changes_list(changes_list, Keyword.fetch!(options, :timestamps))
{_, inserted} = {_, inserted} =
Repo.safe_insert_all( repo.safe_insert_all(
ecto_schema_module, ecto_schema_module,
timestamped_changes_list, timestamped_changes_list,
Keyword.delete(options, :for) Keyword.delete(options, :for)

@ -7,7 +7,7 @@ defmodule Explorer.Chain.Import.Address.CoinBalances do
import Ecto.Query, only: [from: 2] import Ecto.Query, only: [from: 2]
alias Ecto.{Changeset, Multi} alias Ecto.{Changeset, Multi, Repo}
alias Explorer.Chain.Address.CoinBalance alias Explorer.Chain.Address.CoinBalance
alias Explorer.Chain.{Block, Hash, Import, Wei} 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_new(:timeout, @timeout)
|> Map.put(:timestamps, timestamps) |> Map.put(:timestamps, timestamps)
Multi.run(multi, :address_coin_balances, fn _ -> Multi.run(multi, :address_coin_balances, fn repo, _ ->
insert(changes_list, insert_options) insert(repo, changes_list, insert_options)
end) end)
end end
@ -52,6 +52,7 @@ defmodule Explorer.Chain.Import.Address.CoinBalances do
def timeout, do: @timeout def timeout, do: @timeout
@spec insert( @spec insert(
Repo.t(),
[ [
%{ %{
required(:address_hash) => Hash.Address.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()}]} {:ok, [%{required(:address_hash) => Hash.Address.t(), required(:block_number) => Block.block_number()}]}
| {:error, [Changeset.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) on_conflict = Map.get_lazy(options, :on_conflict, &default_on_conflict/0)
# order so that row ShareLocks are grabbed in a consistent order # order so that row ShareLocks are grabbed in a consistent order
@ -75,6 +76,7 @@ defmodule Explorer.Chain.Import.Address.CoinBalances do
{:ok, _} = {:ok, _} =
Import.insert_changes_list( Import.insert_changes_list(
repo,
ordered_changes_list, ordered_changes_list,
conflict_target: [:address_hash, :block_number], conflict_target: [:address_hash, :block_number],
on_conflict: on_conflict, on_conflict: on_conflict,

@ -7,7 +7,7 @@ defmodule Explorer.Chain.Import.Address.CurrentTokenBalances do
import Ecto.Query, only: [from: 2] import Ecto.Query, only: [from: 2]
alias Ecto.{Changeset, Multi} alias Ecto.{Changeset, Multi, Repo}
alias Explorer.Chain.Address.CurrentTokenBalance alias Explorer.Chain.Address.CurrentTokenBalance
alias Explorer.Chain.Import alias Explorer.Chain.Import
@ -41,26 +41,28 @@ defmodule Explorer.Chain.Import.Address.CurrentTokenBalances do
|> Map.put_new(:timeout, @timeout) |> Map.put_new(:timeout, @timeout)
|> Map.put(:timestamps, timestamps) |> Map.put(:timestamps, timestamps)
Multi.run(multi, :address_current_token_balances, fn _ -> Multi.run(multi, :address_current_token_balances, fn repo, _ ->
insert(changes_list, insert_options) insert(repo, changes_list, insert_options)
end) end)
end end
@impl Import.Runner @impl Import.Runner
def timeout, do: @timeout def timeout, do: @timeout
@spec insert([map()], %{ @spec insert(Repo.t(), [map()], %{
optional(:on_conflict) => Import.Runner.on_conflict(), optional(:on_conflict) => Import.Runner.on_conflict(),
required(:timeout) => timeout(), required(:timeout) => timeout(),
required(:timestamps) => Import.timestamps() required(:timestamps) => Import.timestamps()
}) :: }) ::
{:ok, [CurrentTokenBalance.t()]} {:ok, [CurrentTokenBalance.t()]}
| {:error, [Changeset.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) on_conflict = Map.get_lazy(options, :on_conflict, &default_on_conflict/0)
{:ok, _} = {:ok, _} =
Import.insert_changes_list( Import.insert_changes_list(
repo,
unique_token_balances(changes_list), unique_token_balances(changes_list),
conflict_target: ~w(address_hash token_contract_address_hash)a, conflict_target: ~w(address_hash token_contract_address_hash)a,
on_conflict: on_conflict, on_conflict: on_conflict,

@ -7,7 +7,7 @@ defmodule Explorer.Chain.Import.Address.TokenBalances do
import Ecto.Query, only: [from: 2] import Ecto.Query, only: [from: 2]
alias Ecto.{Changeset, Multi} alias Ecto.{Changeset, Multi, Repo}
alias Explorer.Chain.Address.TokenBalance alias Explorer.Chain.Address.TokenBalance
alias Explorer.Chain.Import alias Explorer.Chain.Import
@ -41,22 +41,22 @@ defmodule Explorer.Chain.Import.Address.TokenBalances do
|> Map.put_new(:timeout, @timeout) |> Map.put_new(:timeout, @timeout)
|> Map.put(:timestamps, timestamps) |> Map.put(:timestamps, timestamps)
Multi.run(multi, :address_token_balances, fn _ -> Multi.run(multi, :address_token_balances, fn repo, _ ->
insert(changes_list, insert_options) insert(repo, changes_list, insert_options)
end) end)
end end
@impl Import.Runner @impl Import.Runner
def timeout, do: @timeout def timeout, do: @timeout
@spec insert([map()], %{ @spec insert(Repo.t(), [map()], %{
optional(:on_conflict) => Import.Runner.on_conflict(), optional(:on_conflict) => Import.Runner.on_conflict(),
required(:timeout) => timeout(), required(:timeout) => timeout(),
required(:timestamps) => Import.timestamps() required(:timestamps) => Import.timestamps()
}) :: }) ::
{:ok, [TokenBalance.t()]} {:ok, [TokenBalance.t()]}
| {:error, [Changeset.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) on_conflict = Map.get_lazy(options, :on_conflict, &default_on_conflict/0)
# order so that row ShareLocks are grabbed in a consistent order # order so that row ShareLocks are grabbed in a consistent order
@ -64,6 +64,7 @@ defmodule Explorer.Chain.Import.Address.TokenBalances do
{:ok, _} = {:ok, _} =
Import.insert_changes_list( Import.insert_changes_list(
repo,
ordered_changes_list, ordered_changes_list,
conflict_target: ~w(address_hash token_contract_address_hash block_number)a, conflict_target: ~w(address_hash token_contract_address_hash block_number)a,
on_conflict: on_conflict, on_conflict: on_conflict,

@ -5,7 +5,7 @@ defmodule Explorer.Chain.Import.Addresses do
require Ecto.Query require Ecto.Query
alias Ecto.Multi alias Ecto.{Multi, Repo}
alias Explorer.Chain.{Address, Hash, Import} alias Explorer.Chain.{Address, Hash, Import}
import Ecto.Query, only: [from: 2] import Ecto.Query, only: [from: 2]
@ -40,8 +40,8 @@ defmodule Explorer.Chain.Import.Addresses do
|> Map.put_new(:timeout, @timeout) |> Map.put_new(:timeout, @timeout)
|> Map.put(:timestamps, timestamps) |> Map.put(:timestamps, timestamps)
Multi.run(multi, :addresses, fn _ -> Multi.run(multi, :addresses, fn repo, _ ->
insert(changes_list, insert_options) insert(repo, changes_list, insert_options)
end) end)
end end
@ -50,18 +50,19 @@ defmodule Explorer.Chain.Import.Addresses do
## Private Functions ## Private Functions
@spec insert([%{hash: Hash.Address.t()}], %{ @spec insert(Repo.t(), [%{hash: Hash.Address.t()}], %{
optional(:on_conflict) => Import.Runner.on_conflict(), optional(:on_conflict) => Import.Runner.on_conflict(),
required(:timeout) => timeout, required(:timeout) => timeout,
required(:timestamps) => Import.timestamps() required(:timestamps) => Import.timestamps()
}) :: {:ok, [Address.t()]} }) :: {: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) on_conflict = Map.get_lazy(options, :on_conflict, &default_on_conflict/0)
# order so that row ShareLocks are grabbed in a consistent order # order so that row ShareLocks are grabbed in a consistent order
ordered_changes_list = sort_changes_list(changes_list) ordered_changes_list = sort_changes_list(changes_list)
Import.insert_changes_list( Import.insert_changes_list(
repo,
ordered_changes_list, ordered_changes_list,
conflict_target: :hash, conflict_target: :hash,
on_conflict: on_conflict, on_conflict: on_conflict,

@ -7,7 +7,7 @@ defmodule Explorer.Chain.Import.Block.SecondDegreeRelations do
import Ecto.Query, only: [from: 2] import Ecto.Query, only: [from: 2]
alias Ecto.{Changeset, Multi} alias Ecto.{Changeset, Multi, Repo}
alias Explorer.Chain.{Block, Hash, Import} alias Explorer.Chain.{Block, Hash, Import}
@behaviour Import.Runner @behaviour Import.Runner
@ -40,23 +40,25 @@ defmodule Explorer.Chain.Import.Block.SecondDegreeRelations do
|> Map.take(~w(on_conflict timeout)a) |> Map.take(~w(on_conflict timeout)a)
|> Map.put_new(:timeout, @timeout) |> Map.put_new(:timeout, @timeout)
Multi.run(multi, :block_second_degree_relations, fn _ -> Multi.run(multi, :block_second_degree_relations, fn repo, _ ->
insert(changes_list, insert_options) insert(repo, changes_list, insert_options)
end) end)
end end
@impl Import.Runner @impl Import.Runner
def timeout, do: @timeout def timeout, do: @timeout
@spec insert([map()], %{optional(:on_conflict) => Import.Runner.on_conflict(), required(:timeout) => timeout}) :: @spec insert(Repo.t(), [map()], %{
{:ok, %{nephew_hash: Hash.Full.t(), uncle_hash: Hash.Full.t()}} | {:error, [Changeset.t()]} optional(:on_conflict) => Import.Runner.on_conflict(),
defp insert(changes_list, %{timeout: timeout} = options) when is_list(changes_list) do 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) on_conflict = Map.get_lazy(options, :on_conflict, &default_on_conflict/0)
# order so that row ShareLocks are grabbed in a consistent order # 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}) 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], conflict_target: [:nephew_hash, :uncle_hash],
on_conflict: on_conflict, on_conflict: on_conflict,
for: Block.SecondDegreeRelation, for: Block.SecondDegreeRelation,

@ -5,7 +5,7 @@ defmodule Explorer.Chain.Import.Block.Rewards do
import Ecto.Query, only: [from: 2] import Ecto.Query, only: [from: 2]
alias Ecto.{Changeset, Multi} alias Ecto.{Changeset, Multi, Repo}
alias Explorer.Chain.Block.Reward alias Explorer.Chain.Block.Reward
alias Explorer.Chain.Import alias Explorer.Chain.Import
@ -37,19 +37,20 @@ defmodule Explorer.Chain.Import.Block.Rewards do
|> Map.put_new(:timeout, @timeout) |> Map.put_new(:timeout, @timeout)
|> Map.put(:timestamps, timestamps) |> 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 end
@impl Import.Runner @impl Import.Runner
def timeout, do: @timeout def timeout, do: @timeout
@spec insert([map()], %{ @spec insert(Repo.t(), [map()], %{
required(:timeout) => timeout, required(:timeout) => timeout,
required(:timestamps) => Import.timestamps() required(:timestamps) => Import.timestamps()
}) :: {:ok, [Reward.t()]} | {:error, [Changeset.t()]} }) :: {: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 when is_list(changes_list) do
Import.insert_changes_list( Import.insert_changes_list(
repo,
changes_list, changes_list,
conflict_target: [:address_hash, :address_type, :block_hash], conflict_target: [:address_hash, :address_type, :block_hash],
on_conflict: on_conflict(), on_conflict: on_conflict(),

@ -5,12 +5,11 @@ defmodule Explorer.Chain.Import.Blocks do
require Ecto.Query 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.Adapters.SQL
alias Ecto.{Changeset, Multi} alias Ecto.{Changeset, Multi, Repo}
alias Explorer.Chain.{Block, Import, InternalTransaction, Transaction} alias Explorer.Chain.{Block, Import, InternalTransaction, Transaction}
alias Explorer.Repo
@behaviour Import.Runner @behaviour Import.Runner
@ -45,29 +44,32 @@ defmodule Explorer.Chain.Import.Blocks do
where_forked = where_forked(changes_list) where_forked = where_forked(changes_list)
multi multi
|> Multi.run(:derive_transaction_forks, fn _ -> |> Multi.run(:derive_transaction_forks, fn repo, _ ->
derive_transaction_forks(%{ derive_transaction_forks(%{
repo: repo,
timeout: options[Import.Transaction.Forks.option_key()][:timeout] || Import.Transaction.Forks.timeout(), timeout: options[Import.Transaction.Forks.option_key()][:timeout] || Import.Transaction.Forks.timeout(),
timestamps: timestamps, timestamps: timestamps,
where_forked: where_forked where_forked: where_forked
}) })
end) end)
# MUST be after `:derive_transaction_forks`, which depends on values in `transactions` table # 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(%{ fork_transactions(%{
repo: repo,
timeout: options[Import.Transactions.option_key()][:timeout] || Import.Transactions.timeout(), timeout: options[Import.Transactions.option_key()][:timeout] || Import.Transactions.timeout(),
timestamps: timestamps, timestamps: timestamps,
where_forked: where_forked where_forked: where_forked
}) })
end) end)
|> Multi.run(:lose_consenus, fn _ -> |> Multi.run(:lose_consenus, fn repo, _ ->
lose_consensus(changes_list, insert_options) lose_consensus(repo, changes_list, insert_options)
end) end)
|> Multi.run(:blocks, fn _ -> |> Multi.run(:blocks, fn repo, _ ->
insert(changes_list, insert_options) insert(repo, changes_list, insert_options)
end) 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( update_block_second_degree_relations(
repo,
blocks, blocks,
%{ %{
timeout: timeout:
@ -79,7 +81,7 @@ defmodule Explorer.Chain.Import.Blocks do
end) end)
|> Multi.run( |> Multi.run(
:internal_transaction_transaction_block_number, :internal_transaction_transaction_block_number,
fn %{blocks: blocks} -> fn repo, %{blocks: blocks} ->
blocks_hashes = Enum.map(blocks, & &1.hash) blocks_hashes = Enum.map(blocks, & &1.hash)
query = query =
@ -97,7 +99,7 @@ defmodule Explorer.Chain.Import.Blocks do
] ]
) )
{total, _} = Repo.update_all(query, []) {total, _} = repo.update_all(query, [])
{:ok, total} {:ok, total}
end end
@ -109,6 +111,7 @@ defmodule Explorer.Chain.Import.Blocks do
# sobelow_skip ["SQL.Query"] # sobelow_skip ["SQL.Query"]
defp derive_transaction_forks(%{ defp derive_transaction_forks(%{
repo: repo,
timeout: timeout, timeout: timeout,
timestamps: %{inserted_at: inserted_at, updated_at: updated_at}, timestamps: %{inserted_at: inserted_at, updated_at: updated_at},
where_forked: where_forked 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_sql = """
INSERT INTO transaction_forks (uncle_hash, index, hash, inserted_at, updated_at) 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}} <- with {:ok, %Postgrex.Result{columns: ["uncle_hash", "hash"], command: :insert, rows: rows}} <-
SQL.query( SQL.query(
Repo, repo,
insert_sql, insert_sql,
parameters, parameters,
timeout: timeout timeout: timeout
@ -145,7 +148,12 @@ defmodule Explorer.Chain.Import.Blocks do
end end
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 = query =
where_forked where_forked
|> update( |> update(
@ -161,9 +169,10 @@ defmodule Explorer.Chain.Import.Blocks do
updated_at: ^updated_at updated_at: ^updated_at
] ]
) )
|> select([:hash])
try do try do
{_, result} = Repo.update_all(query, [], timeout: timeout, returning: [:hash]) {_, result} = repo.update_all(query, [], timeout: timeout)
{:ok, result} {:ok, result}
rescue rescue
@ -172,18 +181,19 @@ defmodule Explorer.Chain.Import.Blocks do
end end
end end
@spec insert([map()], %{ @spec insert(Repo.t(), [map()], %{
optional(:on_conflict) => Import.Runner.on_conflict(), optional(:on_conflict) => Import.Runner.on_conflict(),
required(:timeout) => timeout, required(:timeout) => timeout,
required(:timestamps) => Import.timestamps() required(:timestamps) => Import.timestamps()
}) :: {:ok, [Block.t()]} | {:error, [Changeset.t()]} }) :: {: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) on_conflict = Map.get_lazy(options, :on_conflict, &default_on_conflict/0)
# order so that row ShareLocks are grabbed in a consistent order # order so that row ShareLocks are grabbed in a consistent order
ordered_changes_list = Enum.sort_by(changes_list, &{&1.number, &1.hash}) ordered_changes_list = Enum.sort_by(changes_list, &{&1.number, &1.hash})
Import.insert_changes_list( Import.insert_changes_list(
repo,
ordered_changes_list, ordered_changes_list,
conflict_target: :hash, conflict_target: :hash,
on_conflict: on_conflict, on_conflict: on_conflict,
@ -218,7 +228,7 @@ defmodule Explorer.Chain.Import.Blocks do
) )
end 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 when is_list(blocks_changes) do
ordered_consensus_block_number = ordered_consensus_block_number =
blocks_changes blocks_changes
@ -240,11 +250,12 @@ defmodule Explorer.Chain.Import.Blocks do
consensus: false, consensus: false,
updated_at: ^updated_at updated_at: ^updated_at
] ]
] ],
select: [:hash, :number]
) )
try do try do
{_, result} = Repo.update_all(query, [], timeout: timeout, returning: [:hash, :number]) {_, result} = repo.update_all(query, [], timeout: timeout)
{:ok, result} {:ok, result}
rescue rescue
@ -253,7 +264,7 @@ defmodule Explorer.Chain.Import.Blocks do
end end
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 when is_list(blocks) do
ordered_uncle_hashes = ordered_uncle_hashes =
blocks blocks
@ -272,7 +283,7 @@ defmodule Explorer.Chain.Import.Blocks do
) )
try do try do
{_, result} = Repo.update_all(query, [], timeout: timeout) {_, result} = repo.update_all(query, [], timeout: timeout)
{:ok, result} {:ok, result}
rescue rescue

@ -5,9 +5,8 @@ defmodule Explorer.Chain.Import.InternalTransactions do
require Ecto.Query require Ecto.Query
alias Ecto.{Changeset, Multi} alias Ecto.{Changeset, Multi, Repo}
alias Explorer.Chain.{Hash, Import, InternalTransaction, Transaction} alias Explorer.Chain.{Hash, Import, InternalTransaction, Transaction}
alias Explorer.Repo
import Ecto.Query, only: [from: 2] import Ecto.Query, only: [from: 2]
@ -48,26 +47,27 @@ defmodule Explorer.Chain.Import.InternalTransactions do
update_transactions_options = %{timeout: transactions_timeout, timestamps: timestamps} update_transactions_options = %{timeout: transactions_timeout, timestamps: timestamps}
multi multi
|> Multi.run(:internal_transactions, fn _ -> |> Multi.run(:internal_transactions, fn repo, _ ->
insert(changes_list, insert_options) insert(repo, changes_list, insert_options)
end) 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) -> when is_list(internal_transactions) ->
update_transactions(internal_transactions, update_transactions_options) update_transactions(repo, internal_transactions, update_transactions_options)
end) end)
end end
@impl Import.Runner @impl Import.Runner
def timeout, do: @timeout def timeout, do: @timeout
@spec insert([map], %{ @spec insert(Repo.t(), [map], %{
optional(:on_conflict) => Import.Runner.on_conflict(), optional(:on_conflict) => Import.Runner.on_conflict(),
required(:timeout) => timeout, required(:timeout) => timeout,
required(:timestamps) => Import.timestamps() required(:timestamps) => Import.timestamps()
}) :: }) ::
{:ok, [%{index: non_neg_integer, transaction_hash: Hash.t()}]} {:ok, [%{index: non_neg_integer, transaction_hash: Hash.t()}]}
| {:error, [Changeset.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 when is_list(changes_list) do
on_conflict = Map.get_lazy(options, :on_conflict, &default_on_conflict/0) 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} = {:ok, internal_transactions} =
Import.insert_changes_list( Import.insert_changes_list(
repo,
ordered_changes_list, ordered_changes_list,
conflict_target: [:transaction_hash, :index], conflict_target: [:transaction_hash, :index],
for: InternalTransaction, for: InternalTransaction,
@ -122,7 +123,7 @@ defmodule Explorer.Chain.Import.InternalTransactions do
) )
end end
defp update_transactions(internal_transactions, %{ defp update_transactions(repo, internal_transactions, %{
timeout: timeout, timeout: timeout,
timestamps: timestamps timestamps: timestamps
}) })
@ -164,7 +165,7 @@ defmodule Explorer.Chain.Import.InternalTransactions do
transaction_count = Enum.count(ordered_transaction_hashes) transaction_count = Enum.count(ordered_transaction_hashes)
try do try do
{^transaction_count, result} = Repo.update_all(query, [], timeout: timeout) {^transaction_count, result} = repo.update_all(query, [], timeout: timeout)
{:ok, result} {:ok, result}
rescue rescue

@ -5,7 +5,7 @@ defmodule Explorer.Chain.Import.Logs do
require Ecto.Query require Ecto.Query
alias Ecto.{Changeset, Multi} alias Ecto.{Changeset, Multi, Repo}
alias Explorer.Chain.{Import, Log} alias Explorer.Chain.{Import, Log}
import Ecto.Query, only: [from: 2] import Ecto.Query, only: [from: 2]
@ -40,22 +40,22 @@ defmodule Explorer.Chain.Import.Logs do
|> Map.put_new(:timeout, @timeout) |> Map.put_new(:timeout, @timeout)
|> Map.put(:timestamps, timestamps) |> Map.put(:timestamps, timestamps)
Multi.run(multi, :logs, fn _ -> Multi.run(multi, :logs, fn repo, _ ->
insert(changes_list, insert_options) insert(repo, changes_list, insert_options)
end) end)
end end
@impl Import.Runner @impl Import.Runner
def timeout, do: @timeout def timeout, do: @timeout
@spec insert([map()], %{ @spec insert(Repo.t(), [map()], %{
optional(:on_conflict) => Import.Runner.on_conflict(), optional(:on_conflict) => Import.Runner.on_conflict(),
required(:timeout) => timeout, required(:timeout) => timeout,
required(:timestamps) => Import.timestamps() required(:timestamps) => Import.timestamps()
}) :: }) ::
{:ok, [Log.t()]} {:ok, [Log.t()]}
| {:error, [Changeset.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) on_conflict = Map.get_lazy(options, :on_conflict, &default_on_conflict/0)
# order so that row ShareLocks are grabbed in a consistent order # order so that row ShareLocks are grabbed in a consistent order
@ -63,6 +63,7 @@ defmodule Explorer.Chain.Import.Logs do
{:ok, _} = {:ok, _} =
Import.insert_changes_list( Import.insert_changes_list(
repo,
ordered_changes_list, ordered_changes_list,
conflict_target: [:transaction_hash, :index], conflict_target: [:transaction_hash, :index],
on_conflict: on_conflict, on_conflict: on_conflict,

@ -7,7 +7,7 @@ defmodule Explorer.Chain.Import.TokenTransfers do
import Ecto.Query, only: [from: 2] import Ecto.Query, only: [from: 2]
alias Ecto.{Changeset, Multi} alias Ecto.{Changeset, Multi, Repo}
alias Explorer.Chain.{Import, TokenTransfer} alias Explorer.Chain.{Import, TokenTransfer}
@behaviour Import.Runner @behaviour Import.Runner
@ -40,18 +40,18 @@ defmodule Explorer.Chain.Import.TokenTransfers do
|> Map.put_new(:timeout, @timeout) |> Map.put_new(:timeout, @timeout)
|> Map.put(:timestamps, timestamps) |> Map.put(:timestamps, timestamps)
Multi.run(multi, :token_transfers, fn _ -> Multi.run(multi, :token_transfers, fn repo, _ ->
insert(changes_list, insert_options) insert(repo, changes_list, insert_options)
end) end)
end end
@impl Import.Runner @impl Import.Runner
def timeout, do: @timeout 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()]} {:ok, [TokenTransfer.t()]}
| {:error, [Changeset.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) on_conflict = Map.get_lazy(options, :on_conflict, &default_on_conflict/0)
# order so that row ShareLocks are grabbed in a consistent order # order so that row ShareLocks are grabbed in a consistent order
@ -59,6 +59,7 @@ defmodule Explorer.Chain.Import.TokenTransfers do
{:ok, _} = {:ok, _} =
Import.insert_changes_list( Import.insert_changes_list(
repo,
ordered_changes_list, ordered_changes_list,
conflict_target: [:transaction_hash, :log_index], conflict_target: [:transaction_hash, :log_index],
on_conflict: on_conflict, on_conflict: on_conflict,

@ -7,7 +7,7 @@ defmodule Explorer.Chain.Import.Tokens do
import Ecto.Query, only: [from: 2] import Ecto.Query, only: [from: 2]
alias Ecto.Multi alias Ecto.{Multi, Repo}
alias Explorer.Chain.{Import, Token} alias Explorer.Chain.{Import, Token}
@behaviour Import.Runner @behaviour Import.Runner
@ -40,26 +40,27 @@ defmodule Explorer.Chain.Import.Tokens do
|> Map.put_new(:timeout, @timeout) |> Map.put_new(:timeout, @timeout)
|> Map.put(:timestamps, timestamps) |> Map.put(:timestamps, timestamps)
Multi.run(multi, :tokens, fn _ -> Multi.run(multi, :tokens, fn repo, _ ->
insert(changes_list, insert_options) insert(repo, changes_list, insert_options)
end) end)
end end
@impl Import.Runner @impl Import.Runner
def timeout, do: @timeout def timeout, do: @timeout
@spec insert([map()], %{ @spec insert(Repo.t(), [map()], %{
required(:on_conflict) => Import.Runner.on_conflict(), required(:on_conflict) => Import.Runner.on_conflict(),
required(:timeout) => timeout(), required(:timeout) => timeout(),
required(:timestamps) => Import.timestamps() required(:timestamps) => Import.timestamps()
}) :: {:ok, [Token.t()]} }) :: {: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) on_conflict = Map.get_lazy(options, :on_conflict, &default_on_conflict/0)
# order so that row ShareLocks are grabbed in a consistent order # order so that row ShareLocks are grabbed in a consistent order
ordered_changes_list = Enum.sort_by(changes_list, & &1.contract_address_hash) ordered_changes_list = Enum.sort_by(changes_list, & &1.contract_address_hash)
{:ok, _} = {:ok, _} =
Import.insert_changes_list( Import.insert_changes_list(
repo,
ordered_changes_list, ordered_changes_list,
conflict_target: :contract_address_hash, conflict_target: :contract_address_hash,
on_conflict: on_conflict, on_conflict: on_conflict,

@ -7,7 +7,7 @@ defmodule Explorer.Chain.Import.Transaction.Forks do
import Ecto.Query, only: [from: 2] import Ecto.Query, only: [from: 2]
alias Ecto.Multi alias Ecto.{Multi, Repo}
alias Explorer.Chain.{Hash, Import, Transaction} alias Explorer.Chain.{Hash, Import, Transaction}
@behaviour Import.Runner @behaviour Import.Runner
@ -42,26 +42,27 @@ defmodule Explorer.Chain.Import.Transaction.Forks do
|> Map.put_new(:timeout, @timeout) |> Map.put_new(:timeout, @timeout)
|> Map.put(:timestamps, timestamps) |> Map.put(:timestamps, timestamps)
Multi.run(multi, :transaction_forks, fn _ -> Multi.run(multi, :transaction_forks, fn repo, _ ->
insert(changes_list, insert_options) insert(repo, changes_list, insert_options)
end) end)
end end
@impl Import.Runner @impl Import.Runner
def timeout, do: @timeout def timeout, do: @timeout
@spec insert([map()], %{ @spec insert(Repo.t(), [map()], %{
optional(:on_conflict) => Import.Runner.on_conflict(), optional(:on_conflict) => Import.Runner.on_conflict(),
required(:timeout) => timeout, required(:timeout) => timeout,
required(:timestamps) => Import.timestamps() required(:timestamps) => Import.timestamps()
}) :: {:ok, [%{uncle_hash: Hash.t(), hash: Hash.t()}]} }) :: {: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) on_conflict = Map.get_lazy(options, :on_conflict, &default_on_conflict/0)
# order so that row ShareLocks are grabbed in a consistent order # order so that row ShareLocks are grabbed in a consistent order
ordered_changes_list = Enum.sort_by(changes_list, &{&1.uncle_hash, &1.hash}) ordered_changes_list = Enum.sort_by(changes_list, &{&1.uncle_hash, &1.hash})
Import.insert_changes_list( Import.insert_changes_list(
repo,
ordered_changes_list, ordered_changes_list,
conflict_target: [:uncle_hash, :index], conflict_target: [:uncle_hash, :index],
on_conflict: on_conflict, on_conflict: on_conflict,

@ -7,7 +7,7 @@ defmodule Explorer.Chain.Import.Transactions do
import Ecto.Query, only: [from: 2] import Ecto.Query, only: [from: 2]
alias Ecto.Multi alias Ecto.{Multi, Repo}
alias Explorer.Chain.{Hash, Import, Transaction} alias Explorer.Chain.{Hash, Import, Transaction}
@behaviour Import.Runner @behaviour Import.Runner
@ -40,20 +40,20 @@ defmodule Explorer.Chain.Import.Transactions do
|> Map.put_new(:timeout, @timeout) |> Map.put_new(:timeout, @timeout)
|> Map.put(:timestamps, timestamps) |> Map.put(:timestamps, timestamps)
Multi.run(multi, :transactions, fn _ -> Multi.run(multi, :transactions, fn repo, _ ->
insert(changes_list, insert_options) insert(repo, changes_list, insert_options)
end) end)
end end
@impl Import.Runner @impl Import.Runner
def timeout, do: @timeout def timeout, do: @timeout
@spec insert([map()], %{ @spec insert(Repo.t(), [map()], %{
optional(:on_conflict) => Import.Runner.on_conflict(), optional(:on_conflict) => Import.Runner.on_conflict(),
required(:timeout) => timeout, required(:timeout) => timeout,
required(:timestamps) => Import.timestamps() required(:timestamps) => Import.timestamps()
}) :: {:ok, [Hash.t()]} }) :: {: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 when is_list(changes_list) do
on_conflict = Map.get_lazy(options, :on_conflict, &default_on_conflict/0) on_conflict = Map.get_lazy(options, :on_conflict, &default_on_conflict/0)
@ -62,6 +62,7 @@ defmodule Explorer.Chain.Import.Transactions do
{:ok, transactions} = {:ok, transactions} =
Import.insert_changes_list( Import.insert_changes_list(
repo,
ordered_changes_list, ordered_changes_list,
conflict_target: :hash, conflict_target: :hash,
on_conflict: on_conflict, 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) * [ERC-1155](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1155.md)
""" """
use Ecto.Schema use Explorer.Schema
import Ecto.{Changeset, Query} import Ecto.{Changeset, Query}

@ -22,7 +22,7 @@ defmodule Explorer.Chain.TokenTransfer do
| `:index` | `:log_index` | Index of log in transaction | | `:index` | `:log_index` | Index of log in transaction |
""" """
use Ecto.Schema use Explorer.Schema
import Ecto.Changeset import Ecto.Changeset
import Ecto.Query, only: [from: 2, limit: 2, where: 3] 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_price, Wei)
field(:gas_used, :decimal) field(:gas_used, :decimal)
field(:index, :integer) field(:index, :integer)
field(:internal_transactions_indexed_at, :utc_datetime) field(:internal_transactions_indexed_at, :utc_datetime_usec)
field(:input, Data) field(:input, Data)
field(:nonce, :integer) field(:nonce, :integer)
field(:r, :decimal) field(:r, :decimal)

@ -1,4 +1,4 @@
defmodule Explorer.Counters.AddessesWithBalanceCounter do defmodule Explorer.Counters.AddressesWithBalanceCounter do
@moduledoc """ @moduledoc """
Caches the number of addresses with fetched coin balance > 0. 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 # finish before a test ends, that test will fail. This way, hundreds of
# tests were failing before disabling the consolidation and the scheduler in # tests were failing before disabling the consolidation and the scheduler in
# the test env. # 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) @enable_consolidation Keyword.get(config, :enable_consolidation)
@doc """ @doc """

@ -11,6 +11,27 @@ defmodule Explorer.Counters.TokenTransferCounter do
@table :token_transfer_counter @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 def table_name do
@table @table
end end
@ -28,7 +49,9 @@ defmodule Explorer.Counters.TokenTransferCounter do
def init(args) do def init(args) do
create_table() create_table()
Task.start_link(&consolidate/0) if enable_consolidation?() do
Task.start_link(&consolidate/0)
end
Chain.subscribe_to_events(:token_transfers) Chain.subscribe_to_events(:token_transfers)

@ -43,7 +43,11 @@ defmodule Explorer.ExchangeRates.Source do
def to_decimal(nil), do: nil 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) Decimal.new(value)
end end

@ -50,9 +50,9 @@ defmodule Explorer.Market.History.Source.CryptoCompare do
for item <- json["Data"] do for item <- json["Data"] do
%{ %{
closing_price: Decimal.new(item["close"]), closing_price: Decimal.new(to_string(item["close"])),
date: date(item["time"]), date: date(item["time"]),
opening_price: Decimal.new(item["open"]) opening_price: Decimal.new(to_string(item["open"]))
} }
end end
end end

@ -2,7 +2,8 @@ defmodule Explorer.Market.MarketHistory do
@moduledoc """ @moduledoc """
Represents market history of configured coin to USD. Represents market history of configured coin to USD.
""" """
use Ecto.Schema
use Explorer.Schema
schema "market_history" do schema "market_history" do
field(:closing_price, :decimal) field(:closing_price, :decimal)

@ -1,5 +1,7 @@
defmodule Explorer.Repo do defmodule Explorer.Repo do
use Ecto.Repo, otp_app: :explorer use Ecto.Repo,
otp_app: :explorer,
adapter: Ecto.Adapters.Postgres
require Logger require Logger

@ -7,10 +7,7 @@ defmodule Explorer.Schema do
import Ecto.{Changeset, Query} import Ecto.{Changeset, Query}
@timestamps_opts [ @timestamps_opts [type: :utc_datetime_usec]
type: :utc_datetime,
usec: true
]
end end
end end
end end

@ -71,8 +71,10 @@ defmodule Explorer.Mixfile do
{:dataloader, "~> 1.0.0"}, {:dataloader, "~> 1.0.0"},
{:decimal, "~> 1.0"}, {:decimal, "~> 1.0"},
{:dialyxir, "~> 0.5", only: [:dev, :test], runtime: false}, {:dialyxir, "~> 0.5", only: [:dev, :test], runtime: false},
# Casting Ethereum-native types to Elixir-native types # `override: true` for `ex_machina` compatibility
{:ecto, "~> 2.2"}, {:ecto, "~> 3.0", override: true},
# Storing blockchain data and derived data in PostgreSQL.
{:ecto_sql, "~> 3.0"},
# JSONRPC access to query smart contracts # JSONRPC access to query smart contracts
{:ethereum_jsonrpc, in_umbrella: true}, {:ethereum_jsonrpc, in_umbrella: true},
# Data factory for testing # Data factory for testing
@ -92,7 +94,12 @@ defmodule Explorer.Mixfile do
# For compatibility with `prometheus_process_collector`, which hasn't been updated yet # For compatibility with `prometheus_process_collector`, which hasn't been updated yet
{:prometheus, "~> 4.0", override: true}, {:prometheus, "~> 4.0", override: true},
# Prometheus metrics for query duration # 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 # bypass optional dependency
{:plug_cowboy, "~> 1.0", only: :test}, {:plug_cowboy, "~> 1.0", only: :test},
{:sobelow, ">= 0.7.0", only: [:dev, :test], runtime: false}, {:sobelow, ">= 0.7.0", only: [:dev, :test], runtime: false},
@ -102,9 +109,10 @@ defmodule Explorer.Mixfile do
{:spandex_datadog, "~> 0.3.1"}, {:spandex_datadog, "~> 0.3.1"},
# `:spandex` tracing of `:ecto` # `:spandex` tracing of `:ecto`
{:spandex_ecto, "~> 0.4.0"}, {: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.Duration` for `Explorer.Chain.average_block_time/0`
{:timex_ecto, "~> 3.3"} {:timex, "~> 3.4"}
] ]
end end

@ -8,7 +8,7 @@ defmodule Explorer.Repo.Migrations.CreateAddress do
add(:hash, :bytea, null: false, primary_key: true) add(:hash, :bytea, null: false, primary_key: true)
add(:contract_code, :bytea, null: true) add(:contract_code, :bytea, null: true)
timestamps(null: false, type: :utc_datetime) timestamps(null: false, type: :utc_datetime_usec)
end end
end end
end end

@ -16,10 +16,10 @@ defmodule Explorer.Repo.Migrations.CreateBlocks do
add(:parent_hash, :bytea, null: false) add(:parent_hash, :bytea, null: false)
add(:size, :integer, 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) add(:total_difficulty, :numeric, precision: 50)
timestamps(null: false, type: :utc_datetime) timestamps(null: false, type: :utc_datetime_usec)
end end
create(index(:blocks, [:timestamp])) create(index(:blocks, [:timestamp]))

@ -23,7 +23,7 @@ defmodule Explorer.Repo.Migrations.CreateTransactions do
add(:input, :bytea, null: false) add(:input, :bytea, null: false)
# `null` when `internal_transactions` has never been fetched # `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(:nonce, :integer, null: false)
add(:r, :numeric, precision: 100, 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(:v, :integer, null: false)
add(:value, :numeric, precision: 100, 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 # `null` when a pending transaction
add(:block_hash, references(:blocks, column: :hash, on_delete: :delete_all, type: :bytea), null: true) 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(:third_topic, :string, null: true)
add(:fourth_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) 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(:type, :string, null: false)
add(:value, :numeric, precision: 100, 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 # Nullability controlled by create_has_created constraint below
add(:created_contract_address_hash, references(:addresses, column: :hash, type: :bytea), null: true) 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 # null until fetched
add(:value, :numeric, precision: 100, default: fragment("NULL"), null: true) 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 end
create(unique_index(:address_coin_balances, [:address_hash, :block_number])) 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, :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 end
create(unique_index(:address_token_balances, ~w(address_hash token_contract_address_hash block_number)a)) 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 create table(:block_second_degree_relations, primary_key: false) do
add(:nephew_hash, references(:blocks, column: :hash, type: :bytea), null: false) add(:nephew_hash, references(:blocks, column: :hash, type: :bytea), null: false)
add(:uncle_hash, :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 end
create(unique_index(:block_second_degree_relations, [:nephew_hash, :uncle_hash], name: :nephew_hash_to_uncle_hash)) 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, :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 end
create(unique_index(:address_current_token_balances, ~w(address_hash token_contract_address_hash)a)) 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 use Explorer.DataCase
alias Ecto.Changeset alias Ecto.Changeset
alias Explorer.Chain.{Block, Wei}
alias Explorer.Chain.Address.CoinBalance alias Explorer.Chain.Address.CoinBalance
alias Explorer.Chain.Wei
alias Explorer.PagingOptions alias Explorer.PagingOptions
describe "changeset/2" do describe "changeset/2" do
@ -183,7 +183,7 @@ defmodule Explorer.Chain.Address.CoinBalanceTest do
test "returns dates at midnight" do test "returns dates at midnight" do
address = insert(:address) address = insert(:address)
noon = Timex.now() |> Timex.beginning_of_day() |> Timex.set(hour: 12) 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)) 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: 1000, block_number: block.number)
insert(:fetched_balance, address_hash: address.hash, value: 2000, block_number: block_one_day_ago.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) 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) 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 end
test "gets the max value of the day (value is at the beginning)" do 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 test "with duplicate information" do
%Block{hash: hash, miner_hash: miner_hash} = insert(:block) %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{}
|> Block.changeset(params_for(:block, hash: hash, miner_hash: miner_hash)) |> Block.changeset(params_for(:block, hash: hash, miner_hash: miner_hash))
|> Repo.insert() |> Repo.insert()
assert errors == [hash: {"has already been taken", []}]
end end
test "rejects duplicate blocks with mixed case" do test "rejects duplicate blocks with mixed case" do
%Block{miner_hash: miner_hash} = %Block{miner_hash: miner_hash} =
insert(:block, hash: "0xef95f2f1ed3ca60b048b4bf67cde2195961e0bba6f70bcbea9a2c4e133e34b46") insert(:block, hash: "0xef95f2f1ed3ca60b048b4bf67cde2195961e0bba6f70bcbea9a2c4e133e34b46")
{:error, changeset} = assert {:error, %Changeset{valid?: false, errors: [hash: {"has already been taken", _}]}} =
%Block{} %Block{}
|> Block.changeset( |> Block.changeset(
params_for( params_for(
:block, :block,
hash: "0xeF95f2f1ed3ca60b048b4bf67cde2195961e0bba6f70bcbea9a2c4e133e34b46", hash: "0xeF95f2f1ed3ca60b048b4bf67cde2195961e0bba6f70bcbea9a2c4e133e34b46",
miner_hash: miner_hash miner_hash: miner_hash
) )
) )
|> Repo.insert() |> Repo.insert()
refute changeset.valid?
assert changeset.errors == [hash: {"has already been taken", []}]
end end
end end
end end

@ -1,9 +1,9 @@
defmodule Explorer.Chain.Import.Address.CurrentTokenBalancesTest do defmodule Explorer.Chain.Import.Address.CurrentTokenBalancesTest do
use Explorer.DataCase use Explorer.DataCase
alias Explorer.Chain.Address.CurrentTokenBalance
alias Explorer.Chain.Import.Address.CurrentTokenBalances alias Explorer.Chain.Import.Address.CurrentTokenBalances
alias Explorer.Repo
alias Explorer.Chain.{Address.CurrentTokenBalance}
describe "insert/2" do describe "insert/2" do
setup 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 = current_token_balances =
CurrentTokenBalance CurrentTokenBalance
|> Explorer.Repo.all() |> Repo.all()
|> Enum.count() |> Enum.count()
assert current_token_balances == 1 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.block_number == 2
assert current_token_balance.value == Decimal.new(200) 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.block_number == 4
assert current_token_balance.value == Decimal.new(200) 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 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 %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 end
test "a transaction fork cannot be inserted if the corresponding uncle does not exist" do 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} = assert %Changeset{valid?: true} =
changeset = Fork.changeset(%Fork{}, %{hash: transaction.hash, index: 0, uncle_hash: block_hash()}) 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
end end

@ -24,7 +24,7 @@ defmodule Explorer.ChainTest do
alias Explorer.Chain.Supply.ProofOfAuthority alias Explorer.Chain.Supply.ProofOfAuthority
alias Explorer.Counters.{AddessesWithBalanceCounter, TokenHoldersCounter} alias Explorer.Counters.{AddressesWithBalanceCounter, TokenHoldersCounter}
doctest Explorer.Chain doctest Explorer.Chain
@ -34,7 +34,8 @@ defmodule Explorer.ChainTest do
insert(:address, fetched_coin_balance: 1) insert(:address, fetched_coin_balance: 1)
insert(:address, fetched_coin_balance: 2) insert(:address, fetched_coin_balance: 2)
AddessesWithBalanceCounter.consolidate() start_supervised!(AddressesWithBalanceCounter)
AddressesWithBalanceCounter.consolidate()
addresses_with_balance = Chain.count_addresses_with_balance_from_cache() addresses_with_balance = Chain.count_addresses_with_balance_from_cache()
@ -3002,6 +3003,7 @@ defmodule Explorer.ChainTest do
value: 1000 value: 1000
) )
start_supervised!(TokenHoldersCounter)
TokenHoldersCounter.consolidate() TokenHoldersCounter.consolidate()
assert Chain.count_token_holders_from_token_hash(contract_address_hash) == 2 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 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 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: 0)
insert(:address, fetched_coin_balance: 1) insert(:address, fetched_coin_balance: 1)
insert(:address, fetched_coin_balance: 2) insert(:address, fetched_coin_balance: 2)
AddessesWithBalanceCounter.consolidate() start_supervised!(AddressesWithBalanceCounter)
AddressesWithBalanceCounter.consolidate()
assert AddessesWithBalanceCounter.fetch() == 2 assert AddressesWithBalanceCounter.fetch() == 2
end end
end end

@ -3,6 +3,12 @@ defmodule Explorer.Counters.BlockValidationCounterTest do
alias Explorer.Counters.BlockValidationCounter alias Explorer.Counters.BlockValidationCounter
setup do
start_supervised!(BlockValidationCounter)
:ok
end
describe "consolidate/0" do describe "consolidate/0" do
test "loads the address' validations consolidated info" do test "loads the address' validations consolidated info" do
address = insert(:address) address = insert(:address)

@ -4,6 +4,12 @@ defmodule Explorer.Counters.TokenHoldersCounterTest do
alias Explorer.Chain.Token alias Explorer.Chain.Token
alias Explorer.Counters.TokenHoldersCounter alias Explorer.Counters.TokenHoldersCounter
setup do
start_supervised!(TokenHoldersCounter)
:ok
end
describe "consolidate/0" do describe "consolidate/0" do
test "consolidates the token holders info with the most current database info" do test "consolidates the token holders info with the most current database info" do
address_a = insert(:address, hash: "0xe49fedd93960a0267b3c3b2c1e2d66028e013fee") address_a = insert(:address, hash: "0xe49fedd93960a0267b3c3b2c1e2d66028e013fee")

@ -3,6 +3,12 @@ defmodule Explorer.Counters.TokenTransferCounterTest do
alias Explorer.Counters.TokenTransferCounter alias Explorer.Counters.TokenTransferCounter
setup do
start_supervised!(TokenTransferCounter)
:ok
end
describe "consolidate/0" do describe "consolidate/0" do
test "loads the token's transfers consolidate info" do test "loads the token's transfers consolidate info" do
token_contract_address = insert(:contract_address) token_contract_address = insert(:contract_address)
@ -36,7 +42,7 @@ defmodule Explorer.Counters.TokenTransferCounterTest do
end end
describe "fetch/1" do 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_contract_address = insert(:contract_address)
token = insert(:token, contract_address: token_contract_address) token = insert(:token, contract_address: token_contract_address)

@ -61,19 +61,19 @@ defmodule Explorer.Market.History.Source.CryptoCompareTest do
expected = [ expected = [
%{ %{
closing_price: Decimal.new(9655.77), closing_price: Decimal.from_float(9655.77),
date: ~D[2018-04-24], 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], 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], 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 =~ "Options:\n\n[conflict_target: [:transaction_hash, :index], on_conflict: :replace_all]\n\n"
assert log =~ 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 end
end end

@ -45,18 +45,7 @@ defmodule Explorer.DataCase do
def wait_for_results(producer) do def wait_for_results(producer) do
producer.() producer.()
rescue rescue
Ecto.NoResultsError -> [DBConnection.ConnectionError, Ecto.NoResultsError] ->
Process.sleep(100)
wait_for_results(producer)
catch
:exit,
{:timeout,
{GenServer, :call,
[
_,
{:checkout, _, _, _},
_
]}} ->
Process.sleep(100) Process.sleep(100)
wait_for_results(producer) wait_for_results(producer)
end end

@ -512,18 +512,6 @@ defmodule Explorer.Factory do
} }
end 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 defp block_hash_to_next_transaction_index(block_hash) do
import Kernel, except: [+: 2] 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"}, "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]}]}, "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"}, "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]}]}, "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.5.0", "b0433a36d0e2430e3d50291b1c65f53c37d56f83665b43d79963684865beab68", [:mix], []}, "decimal": {:hex, :decimal, "1.6.0", "bfd84d90ff966e1f5d4370bdd3943432d8f65f07d3bab48001aebd7030590dcc", [:mix], [], "hexpm"},
"decorator": {:hex, :decorator, "1.2.4", "31dfff6143d37f0b68d0bffb3b9f18ace14fea54d4f1b5e4f86ead6f00d9ff6e", [:mix], [], "hexpm"}, "decorator": {:hex, :decorator, "1.2.4", "31dfff6143d37f0b68d0bffb3b9f18ace14fea54d4f1b5e4f86ead6f00d9ff6e", [:mix], [], "hexpm"},
"deep_merge": {:hex, :deep_merge, "0.2.0", "c1050fa2edf4848b9f556fba1b75afc66608a4219659e3311d9c9427b5b680b3", [:mix], [], "hexpm"}, "deep_merge": {:hex, :deep_merge, "0.2.0", "c1050fa2edf4848b9f556fba1b75afc66608a4219659e3311d9c9427b5b680b3", [:mix], [], "hexpm"},
"dialyxir": {:hex, :dialyxir, "0.5.1", "b331b091720fd93e878137add264bac4f644e1ddae07a70bf7062c7862c4b952", [:mix], []}, "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"}, "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"}, "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"}, "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_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": {: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_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_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_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"}, "ex_rlp": {:hex, :ex_rlp, "0.3.1", "190554f7b26f79734fc5a772241eec14a71b2e83576e43f451479feb017013e9", [:mix], [], "hexpm"},
"exactor": {:hex, :exactor, "2.2.4", "5efb4ddeb2c48d9a1d7c9b465a6fffdd82300eb9618ece5d34c3334d5d7245b1", [:mix], []}, "exactor": {:hex, :exactor, "2.2.4", "5efb4ddeb2c48d9a1d7c9b465a6fffdd82300eb9618ece5d34c3334d5d7245b1", [:mix], []},
"excoveralls": {:git, "https://github.com/KronicDeth/excoveralls.git", "0a859b68851eeba9b43eba59fbc8f9098299cfe1", [branch: "circle-workflows"]}, "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"}, "plug_crypto": {:hex, :plug_crypto, "1.0.0", "18e49317d3fa343f24620ed22795ec29d4a5e602d52d1513ccea0b07d8ea7d4d", [:mix], [], "hexpm"},
"poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], []}, "poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], []},
"poolboy": {:hex, :poolboy, "1.5.1", "6b46163901cfd0a1b43d692657ed9d7e599853b3b21b95ae5ae0a777cf9b6ca8", [:rebar], []}, "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": {: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_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_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"}, "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_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"}, "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"}, "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": {: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"}, "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"}, "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]}]}, "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