Merge branch 'master' into ab-read-contract-not-found

pull/2800/head
Ayrat Badykov 5 years ago committed by GitHub
commit bbc2e57963
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      .dialyzer-ignore
  2. 9
      CHANGELOG.md
  3. 51
      apps/block_scout_web/assets/css/components/_custom_tooltips_block_details.scss
  4. 4
      apps/block_scout_web/assets/js/pages/chain.js
  5. 27
      apps/block_scout_web/assets/static/images/errors-img/pic-404.svg
  6. 5
      apps/block_scout_web/lib/block_scout_web/controller.ex
  7. 2
      apps/block_scout_web/lib/block_scout_web/templates/address/_link.html.eex
  8. 6
      apps/block_scout_web/lib/block_scout_web/templates/address/_responsive_hash.html.eex
  9. 3
      apps/block_scout_web/lib/block_scout_web/templates/block/_tile.html.eex
  10. 5
      apps/block_scout_web/lib/block_scout_web/templates/block/overview.html.eex
  11. 3
      apps/block_scout_web/lib/block_scout_web/templates/chain/_block.html.eex
  12. 64
      apps/block_scout_web/lib/block_scout_web/templates/chain/show.html.eex
  13. 12
      apps/block_scout_web/lib/block_scout_web/templates/error422/index.html.eex
  14. 2
      apps/block_scout_web/lib/block_scout_web/templates/tokens/holder/_token_balances.html.eex
  15. 3
      apps/block_scout_web/lib/block_scout_web/templates/tokens/inventory/_token.html.eex
  16. 6
      apps/block_scout_web/lib/block_scout_web/templates/tokens/transfer/_token_transfer.html.eex
  17. 4
      apps/block_scout_web/lib/block_scout_web/templates/transaction/_pending_tile.html.eex
  18. 1
      apps/block_scout_web/lib/block_scout_web/templates/transaction/overview.html.eex
  19. 4
      apps/block_scout_web/lib/block_scout_web/templates/transaction_token_transfer/_token_transfer.html.eex
  20. 6
      apps/block_scout_web/lib/block_scout_web/views/address_view.ex
  21. 5
      apps/block_scout_web/lib/block_scout_web/views/error_422.ex
  22. 29
      apps/block_scout_web/lib/block_scout_web/views/layout_view.ex
  23. 55
      apps/block_scout_web/priv/gettext/default.pot
  24. 55
      apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po
  25. 24
      apps/block_scout_web/test/block_scout_web/views/address_view_test.exs
  26. 4
      apps/ethereum_jsonrpc/config/config.exs
  27. 25
      apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/application.ex
  28. 6
      apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/http.ex
  29. 94
      apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/ipc.ex
  30. 3
      apps/ethereum_jsonrpc/mix.exs
  31. 12
      apps/explorer/config/config.exs
  32. 3
      apps/explorer/config/test.exs
  33. 1
      apps/explorer/lib/explorer/application.ex
  34. 26
      apps/explorer/lib/explorer/chain/events/db_sender.ex
  35. 55
      apps/explorer/lib/explorer/chain/events/listener.ex
  36. 17
      apps/explorer/lib/explorer/chain/events/publisher.ex
  37. 21
      apps/explorer/lib/explorer/chain/events/simple_sender.ex
  38. 2
      apps/explorer/lib/explorer/chain/token_transfer.ex
  39. 4
      apps/explorer/test/explorer/chain/events/publisher_test.exs
  40. 4
      apps/explorer/test/explorer/chain/events/subscriber_test.exs
  41. 12
      apps/explorer/test/explorer/chain/import_test.exs
  42. 6
      apps/indexer/config/dev/ganache.exs
  43. 6
      apps/indexer/config/dev/geth.exs
  44. 7
      apps/indexer/config/dev/parity.exs
  45. 6
      apps/indexer/config/dev/rsk.exs
  46. 6
      apps/indexer/config/prod/ganache.exs
  47. 6
      apps/indexer/config/prod/geth.exs
  48. 6
      apps/indexer/config/prod/parity.exs
  49. 6
      apps/indexer/config/prod/rsk.exs
  50. 78
      docker/README.md

@ -13,3 +13,4 @@ apps/explorer/lib/explorer/smart_contract/publisher_worker.ex:6: The pattern 'fa
apps/explorer/lib/explorer/smart_contract/publisher_worker.ex:6: The test 5 == 'infinity' can never evaluate to 'true'
lib/block_scout_web/router.ex:1
lib/phoenix/router.ex:324
lib/block_scout_web/views/layout_view.ex:146

@ -1,11 +1,20 @@
## Current
### Features
- [#2791](https://github.com/poanetwork/blockscout/pull/2791) - add ipc client
- [#2449](https://github.com/poanetwork/blockscout/pull/2449) - add ability to send notification events through postgres notify
### Fixes
- [#2800](https://github.com/poanetwork/blockscout/pull/2800) - return not found for not verified contract for token read_contract
- [#2806](https://github.com/poanetwork/blockscout/pull/2806) - Fix blocks fetching on the main page
- [#2803](https://github.com/poanetwork/blockscout/pull/2803) - Fix block validator custom tooltip
### Chore
- [#2817](https://github.com/poanetwork/blockscout/pull/2817) - move docker integration documentation to blockscout docs
- [#2808](https://github.com/poanetwork/blockscout/pull/2808) - Add tooltip for tx input
- [#2807](https://github.com/poanetwork/blockscout/pull/2807) - 422 page
- [#2805](https://github.com/poanetwork/blockscout/pull/2805) - Update supported chains default option
- [#2801](https://github.com/poanetwork/blockscout/pull/2801) - remove unused clause in address_to_unique_tokens query
## 2.1.0-beta

@ -1,4 +1,5 @@
/* Custom Tooltips for Block Details Page */
$tooltip-background-color: $btn-line-color !default;
.tooltipCustom {
position: relative;
@ -8,23 +9,20 @@
.tooltipCustom .tooltiptextTopMiner {
visibility: hidden;
position: absolute;
width: 50%;
width: 100%;
background-color: white;
color: black;
color: $tooltip-background-color;
text-align: center;
border-radius: 6px;
left: 25%;
left: 0%;
bottom: 100%;
padding: 15px 0px;
padding: 15px;
display: inline-block;
z-index: 1;
font-family: Nunito;
margin-bottom: 15px;
opacity: 0;
transition: opacity 0.5s;
@include media-breakpoint-down(lg) {
left: 60%;
}
}
.tooltipCustom .tooltiptextTopMiner::after {
@ -43,44 +41,5 @@
opacity: 1;
}
.tooltipCustom .tooltiptextTopR {
visibility: hidden;
position: absolute;
width: 50%;
background-color: $primary;
color: white;
text-align: center;
border-radius: 6px;
left: 52%;
bottom: 120%;
padding: 15px 10px;
font-family: Nunito;
display: inline-block;
z-index: 1;
margin-bottom: 15px;
opacity: 0;
transition: opacity 0.5s;
@include media-breakpoint-down(lg) {
bottom: 100%;
padding: 9px 10px;
}
}
.tooltipCustom .tooltiptextTopR::after {
content: '';
position: absolute;
top: 100%;
left: 50%;
margin-left: -5px;
border-width: 5px;
border-style: solid;
border-color: $primary transparent transparent transparent;
}
.tooltipCustom:hover .tooltiptextTopR {
visibility: visible;
opacity: 1;
}
/* Custom Tooltips for Block Details Page end*/

@ -68,10 +68,10 @@ function baseReducer (state = initialState, action) {
return Object.assign({}, state, { blocksLoading: false })
}
case 'BLOCKS_FETCHED': {
return Object.assign({}, state, { blocks: [...action.msg.blocks] })
return Object.assign({}, state, { blocks: [...action.msg.blocks], blocksLoading: false })
}
case 'BLOCKS_REQUEST_ERROR': {
return Object.assign({}, state, { blocksError: true })
return Object.assign({}, state, { blocksError: true, blocksLoading: false })
}
case 'RECEIVED_NEW_EXCHANGE_RATE': {
return Object.assign({}, state, {

@ -0,0 +1,27 @@
<svg xmlns="http://www.w3.org/2000/svg" width="357" height="319">
<path fill="#FFF" fill-rule="evenodd" d="M178.5 148.625c98.583 0 178.5 38.14 178.5 85.187C357 280.86 277.083 319 178.5 319S0 280.86 0 233.812c0-47.047 79.917-85.187 178.5-85.187z"/>
<path fill="#9F68FF" fill-rule="evenodd" d="M198.726 152.391l11.347-2.833 16.186 16.115-11.503 3.122-16.03-16.404zm29.411 43.278l-10.899 2.702-8.093-8.057 10.606-2.859 8.386 8.214z"/>
<path fill="#7441CC" fill-rule="evenodd" d="M228.908 155.202l-8.522-8.66 3.39-10.445 10.899-2.702-5.767 21.807zm-29.889-2.654l8.416-32.279 11.054-2.99-8.572 32.567-10.898 2.702zm27.103 12.681l-6.234 22.671-10.743 2.414 6.06-21.651 10.917-3.434z"/>
<path fill="#CAADFF" fill-rule="evenodd" d="M220.044 187.612l5.922-22.095-16.049-15.671 8.728-32.855 7.8 7.901-5.474 21.964 7.957 7.613 5.747-21.074 8.249 7.769-14.787 54.505-8.093-8.057z"/>
<path fill="#9F68FF" fill-rule="evenodd" d="M73.617 158.33l9.164-5.341-27.731-20.715-9.358 6.068 27.925 19.988z"/>
<path fill="#7441CC" fill-rule="evenodd" d="M58.09 74.571l-10.08 5.874-2.318 57.897 9.885-5.146 2.513-58.625z"/>
<path fill="#9F68FF" fill-rule="evenodd" d="M62.667 92.186l15.879 4.267-4.668 17.472-15.88-4.267 4.669-17.472z"/>
<path fill="#7441CC" fill-rule="evenodd" d="M74.492 100.045l-10.08 5.875-1.34 33.971 9.885-5.146 1.535-34.7z"/>
<path fill="#CAADFF" fill-rule="evenodd" d="M82.585 152.703l-10.417-7.341-6.51-4.588-10.417-7.341 1.641-45.557.486-13.499 16.927 11.929 10.417 7.34-2.127 59.057zM67.298 95.216l-1.154 32.06 6.51 4.587 1.155-32.059-6.511-4.588z"/>
<path fill="#7441CC" fill-rule="evenodd" d="M246.418 40.027l-1.29-22.053 9.75-6.77 1.153 22.802-9.613 6.021zm-18.185-10.632l9.557-6.695 1.38 36.025-9.425 5.952-1.512-35.282zm-1.23-22.611l9.749-6.77.404 13.789-9.613 6.021-.54-13.04z"/>
<path fill="#9F68FF" fill-rule="evenodd" d="M238.161 46.997l.028-11.719 27.257 15.921-8.658 6.118-18.627-10.32zM227.525 19.61l8.791-6.864 27.256 15.921-8.658 6.118-27.389-15.175zm40.394 56.573l-8.689 6.086-29.485-17.592 8.823-6.827 29.351 18.333z"/>
<path fill="#7441CC" fill-rule="evenodd" d="M245.467 28.613l8.588-5.56 1.174 14.126-8.588 5.56-1.174-14.126z"/>
<path fill="#CAADFF" fill-rule="evenodd" d="M267.066 62.421l.635 13.493-28.846-16.924-.135-2.873-.017-.012-.126-3.026-.357-7.582.042.025-.802-19.273.011.006-.17-3.623 17.082 9.963-.408-8.935-17.008-10.225-.641-13.41 28.064 16.873.035.731.04.019.255 6.139.311 6.521-.042-.026.376 9.072-.026.011.592 12.648-17.001-9.916.435 9.939 17.701 10.385z"/>
<path fill="#7441CC" fill-rule="evenodd" d="M97.535 45.483l-.716 7.065L112.06 69.08l.716-7.065-15.241-16.532zM120.006 70.246l-.716 7.065 15.848 17.058 1.006-6.784-16.138-17.339zM121.259 41.213l-.716 7.065 14.459 16.461 1.498-6.994-15.241-16.532zM143.73 65.975l-1.108 7.03 16.275 16.704.971-6.394-16.138-17.34z"/>
<path fill="#9F68FF" fill-rule="evenodd" d="M112.434 62.656l-.558 6.288 8.201 2.634 3.577-6.328-11.22-2.594zM170.179 87.515l-11.647 1.874 1.084-6.712 11.937-1.586-1.374 6.424zm-35.163 6.622l1.119-7.102 11.153-1.656-.981 6.459-11.291 2.299zm-2.255-19.512l-4.539-7.408 15.81-1.337-1.053 7.239-10.218 1.506z"/>
<path fill="#CAADFF" fill-rule="evenodd" d="M171.662 81.195l-11.978 2.184-15.649-17.091-11.977 2.184 15.649 17.091-11.977 2.184-15.649-17.091 2.411-4.998-9.565-2.815-15.65-17.091 11.977-2.184 15.65 17.091 11.977-2.184-15.65-17.091 11.977-2.184 15.65 17.091-2.412 4.998 9.566 2.815 15.65 17.091z"/>
<path fill="#9F68FF" fill-rule="evenodd" d="M120.264 210.586l11.091-10.907 3.852 14.415L124.116 225l-3.852-14.414z"/>
<path fill="#7441CC" fill-rule="evenodd" d="M120.269 210.605l-15.04-3.873 3.846 14.395L124.116 225l-3.847-14.395z"/>
<path fill="#CAADFF" fill-rule="evenodd" d="M116.414 196.175l14.985 3.694-11.136 10.713-14.985-3.694 11.136-10.713z"/>
<path fill="#9F68FF" fill-rule="evenodd" d="M30.636 25.199l8.023-8.735 3.53 11.003-8.024 8.735-3.529-11.003z"/>
<path fill="#7441CC" fill-rule="evenodd" d="M30.64 25.214l-11.643-2.548 3.525 10.989 11.643 2.547-3.525-10.988z"/>
<path fill="#CAADFF" fill-rule="evenodd" d="M27.107 14.199l11.593 2.41-8.065 8.587-11.594-2.41 8.066-8.587z"/>
<path fill="#9F68FF" fill-rule="evenodd" d="M322.446 95.746l20.542-5.304-5.259 19.683-20.542 5.304 5.259-19.683z"/>
<path fill="#7441CC" fill-rule="evenodd" d="M322.439 95.772L307.29 80.894l-5.252 19.657 15.149 14.878 5.252-19.657z"/>
<path fill="#CAADFF" fill-rule="evenodd" d="M327.704 76.069l15.206 14.628-20.462 5.044-15.206-14.628 20.462-5.044z"/>
</svg>

After

Width:  |  Height:  |  Size: 4.5 KiB

@ -20,8 +20,9 @@ defmodule BlockScoutWeb.Controller do
def unprocessable_entity(conn) do
conn
|> put_status(:unprocessable_entity)
|> put_view(BlockScoutWeb.ErrorView)
|> render("422.html")
|> put_view(BlockScoutWeb.Error422View)
|> render(:index)
|> halt()
end
@doc """

@ -1,5 +1,5 @@
<%= if @address do %>
<%= link to: address_path(BlockScoutWeb.Endpoint, :show, @address), "data-test": "address_hash_link", class: assigns[:class] do %>
<%= render BlockScoutWeb.AddressView, "_responsive_hash.html", address: @address, contract: @contract, truncate: assigns[:truncate] %>
<%= render BlockScoutWeb.AddressView, "_responsive_hash.html", address: @address, contract: @contract, truncate: assigns[:truncate], use_custom_tooltip: @use_custom_tooltip %>
<% end %>
<% end %>

@ -1,6 +1,10 @@
<span class="<%= if @contract do %>contract-address<% end %>" data-address-hash="<%= @address %>">
<%= if name = primary_name(@address) do %>
<span data-toggle="tooltip" data-placement="top" title="<%= @address %>"><%= name %> (<%= short_hash(@address) %>...)</span>
<%= if @use_custom_tooltip == true do %>
<span><%= name %> (<%= short_hash(@address) %>...)</span>
<% else %>
<span data-toggle="tooltip" data-placement="top" title="<%= @address %>"><%= name %> (<%= short_hash(@address) %>...)</span>
<% end %>
<% else %>
<%= if assigns[:truncate] do %>
<%= BlockScoutWeb.AddressView.trimmed_hash(@address.hash) %>

@ -39,7 +39,8 @@
<%= render BlockScoutWeb.AddressView,
"_link.html",
address: @block.miner,
contract: false %>
contract: false,
use_custom_tooltip: false %>
</div>
<%= if show_reward?(@block.rewards) do %>
<div class="text-nowrap text-truncate mt-3 mt-md-0">

@ -124,7 +124,7 @@
<h2 class="card-title balance-card-title"><%= gettext "Miner" %></h2>
<div class="text-right tooltipCustom">
<!-- Validator's Name -->
<span class="tooltiptextTopMiner"> Validator's Name</span>
<span class="tooltiptextTopMiner"> <%= @block.miner %></span>
<h3 class="address-balance-text text-truncate" >
@ -132,7 +132,8 @@
"_link.html",
address: @block.miner,
contract: false,
class: "" %>
class: "",
use_custom_tooltip: true %>
</h3>
</div>
</div>

@ -16,7 +16,8 @@
<%= render BlockScoutWeb.AddressView,
"_link.html",
address: @block.miner,
contract: false %>
contract: false,
use_custom_tooltip: false %>
</div>
<%= if BlockScoutWeb.BlockView.show_reward?(@block.rewards) do %>
<div class="text-truncate">

@ -91,50 +91,50 @@
<%= gettext "Something went wrong, click to reload." %>
</span>
</button>
<div hidden data-selector="loading-message" class="col-lg-3" >
<div hidden data-selector="loading-message" class="col-lg-3" >
<div data-selector="chain-block">
<div class="tile tile-type-block n-p d-flex flex-column">
<a class="tile-title"><span class="tile-loader tile-label-loader"></span> </a>
<div class="tile-bottom-contents">
<div class="dark-block-loader"></div>
<div class="dark-block-loader"></div>
<div class="tile tile-type-block n-p d-flex flex-column">
<a class="tile-title"><span class="tile-loader tile-label-loader"></span> </a>
<div class="tile-bottom-contents">
<div class="dark-block-loader"></div>
<div class="dark-block-loader"></div>
</div>
</div>
</div>
</div>
</div>
</div>
<div hidden data-selector="loading-message" class="col-lg-3" >
<div hidden data-selector="loading-message" class="col-lg-3" >
<div data-selector="chain-block">
<div class="tile tile-type-block n-p d-flex flex-column">
<a class="tile-title"><span class="tile-loader tile-label-loader"></span> </a>
<div class="tile-bottom-contents">
<div class="dark-block-loader"></div>
<div class="dark-block-loader"></div>
<div class="tile tile-type-block n-p d-flex flex-column">
<a class="tile-title"><span class="tile-loader tile-label-loader"></span> </a>
<div class="tile-bottom-contents">
<div class="dark-block-loader"></div>
<div class="dark-block-loader"></div>
</div>
</div>
</div>
</div>
</div>
</div>
<div hidden data-selector="loading-message" class="col-lg-3" >
<div hidden data-selector="loading-message" class="col-lg-3" >
<div data-selector="chain-block">
<div class="tile tile-type-block n-p d-flex flex-column">
<a class="tile-title"><span class="tile-loader tile-label-loader"></span> </a>
<div class="tile-bottom-contents">
<div class="dark-block-loader"></div>
<div class="dark-block-loader"></div>
<div class="tile tile-type-block n-p d-flex flex-column">
<a class="tile-title"><span class="tile-loader tile-label-loader"></span> </a>
<div class="tile-bottom-contents">
<div class="dark-block-loader"></div>
<div class="dark-block-loader"></div>
</div>
</div>
</div>
</div>
</div>
</div>
<div hidden data-selector="loading-message" class="col-lg-3" >
<div hidden data-selector="loading-message" class="col-lg-3" >
<div data-selector="chain-block">
<div class="tile tile-type-block n-p d-flex flex-column">
<a class="tile-title"><span class="tile-loader tile-label-loader"></span> </a>
<div class="tile-bottom-contents">
<div class="dark-block-loader"></div>
<div class="dark-block-loader"></div>
<div class="tile tile-type-block n-p d-flex flex-column">
<a class="tile-title"><span class="tile-loader tile-label-loader"></span> </a>
<div class="tile-bottom-contents">
<div class="dark-block-loader"></div>
<div class="dark-block-loader"></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>

@ -0,0 +1,12 @@
<section class="container">
<div class="block-not-found">
<div class="block-not-found-img">
<img alt="Page Not Found" src="/images/errors-img/pic-404.svg">
</div>
<div class="block-not-found-content">
<h1 class="card-title error-title">Unprocessable Entity</h1>
<p class="error-descr">The request was well-formed but was unable to be followed due to semantic errors. Maybe, you mistype a hash of tx/block/address?</p>
<a class="error-btn btn-line" href="/">Back Home</a>
</div>
</div>
</section>

@ -2,7 +2,7 @@
<div class="row">
<div class="col-md-7 col-lg-8 d-flex flex-column">
<span>
<%= render BlockScoutWeb.AddressView, "_link.html", address: @token_balance.address, contract: BlockScoutWeb.AddressView.contract?(@token_balance.address) %>
<%= render BlockScoutWeb.AddressView, "_link.html", address: @token_balance.address, contract: BlockScoutWeb.AddressView.contract?(@token_balance.address), use_custom_tooltip: false %>
</span>
<span>

@ -20,7 +20,8 @@
<%= render BlockScoutWeb.AddressView,
"_link.html",
address: @token_transfer.to_address,
contract: false %>
contract: false,
use_custom_tooltip: false %>
</span>
</span>
</div>

@ -13,7 +13,8 @@
BlockScoutWeb.AddressView,
"_responsive_hash.html",
address: @token_transfer.from_address,
contract: BlockScoutWeb.AddressView.contract?(@token_transfer.from_address)
contract: BlockScoutWeb.AddressView.contract?(@token_transfer.from_address),
use_custom_tooltip: false
) %>
<% end %>
&rarr;
@ -22,7 +23,8 @@
BlockScoutWeb.AddressView,
"_responsive_hash.html",
address: @token_transfer.to_address,
contract: BlockScoutWeb.AddressView.contract?(@token_transfer.to_address)
contract: BlockScoutWeb.AddressView.contract?(@token_transfer.to_address),
use_custom_tooltip: false
) %>
<% end %>
</span>

@ -8,10 +8,10 @@
<div class="col-md-7 col-lg-8 d-flex flex-column pr-2 pr-sm-2 pr-md-0">
<%= render BlockScoutWeb.TransactionView, "_link.html", transaction_hash: @transaction.hash %>
<span class="text-nowrap">
<%= render BlockScoutWeb.AddressView, "_link.html", address: @transaction.from_address, contract: BlockScoutWeb.AddressView.contract?(@transaction.from_address) %>
<%= render BlockScoutWeb.AddressView, "_link.html", address: @transaction.from_address, contract: BlockScoutWeb.AddressView.contract?(@transaction.from_address), use_custom_tooltip: false %>
&rarr;
<%= if @transaction.to_address_hash do %>
<%= render BlockScoutWeb.AddressView, "_link.html", address: @transaction.to_address, contract: BlockScoutWeb.AddressView.contract?(@transaction.to_address) %>
<%= render BlockScoutWeb.AddressView, "_link.html", address: @transaction.to_address, contract: BlockScoutWeb.AddressView.contract?(@transaction.to_address), use_custom_tooltip: false %>
<% else %>
<%= gettext("Contract Address Pending") %>
<% end %>

@ -131,6 +131,7 @@
data-clipboard-text="<%= @transaction.input %>"
data-placement="top"
data-toggle="tooltip"
title='<%= gettext("Copy Txn Input") %>'
>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32.5 32.5" width="32" height="32">
<path fill-rule="evenodd" d="M23.5 20.5a1 1 0 0 1-1-1v-9h-9a1 1 0 0 1 0-2h10a1 1 0 0 1 1 1v10a1 1 0 0 1-1 1zm-3-7v10a1 1 0 0 1-1 1h-10a1 1 0 0 1-1-1v-10a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1zm-2 1h-8v8h8v-8z"/>

@ -7,9 +7,9 @@
<div class="col-12 col-md-8 col-lg-10 d-flex flex-column text-nowrap">
<%= render BlockScoutWeb.TransactionView, "_link.html", transaction_hash: @token_transfer.transaction_hash %>
<span class="text-nowrap">
<%= render BlockScoutWeb.AddressView, "_link.html", address: @token_transfer.from_address, contract: BlockScoutWeb.AddressView.contract?(@token_transfer.from_address) %>
<%= render BlockScoutWeb.AddressView, "_link.html", address: @token_transfer.from_address, contract: BlockScoutWeb.AddressView.contract?(@token_transfer.from_address), use_custom_tooltip: false %>
&rarr;
<%= render BlockScoutWeb.AddressView, "_link.html", address: @token_transfer.to_address, contract: BlockScoutWeb.AddressView.contract?(@token_transfer.to_address) %>
<%= render BlockScoutWeb.AddressView, "_link.html", address: @token_transfer.to_address, contract: BlockScoutWeb.AddressView.contract?(@token_transfer.to_address), use_custom_tooltip: false %>
</span>
<span class="tile-title text-truncate">

@ -271,7 +271,8 @@ defmodule BlockScoutWeb.AddressView do
partial: "_responsive_hash.html",
address: current_address,
contract: contract?,
truncate: truncate
truncate: truncate,
use_custom_tooltip: false
]
end
@ -281,7 +282,8 @@ defmodule BlockScoutWeb.AddressView do
partial: "_link.html",
address: address,
contract: contract?,
truncate: truncate
truncate: truncate,
use_custom_tooltip: false
]
end

@ -0,0 +1,5 @@
defmodule BlockScoutWeb.Error422View do
use BlockScoutWeb, :view
@dialyzer :no_match
end

@ -19,45 +19,16 @@ defmodule BlockScoutWeb.LayoutView do
title: "xDai Chain",
url: "https://blockscout.com/poa/dai"
},
%{
title: "Ethereum Mainnet",
url: "https://blockscout.com/eth/mainnet"
},
%{
title: "Kovan Testnet",
url: "https://blockscout.com/eth/kovan",
test_net?: true
},
%{
title: "Ropsten Testnet",
url: "https://blockscout.com/eth/ropsten",
test_net?: true
},
%{
title: "Goerli Testnet",
url: "https://blockscout.com/eth/goerli",
test_net?: true
},
%{
title: "Rinkeby Testnet",
url: "https://blockscout.com/eth/rinkeby",
test_net?: true
},
%{
title: "Ethereum Classic",
url: "https://blockscout.com/etc/mainnet",
other?: true
},
%{
title: "Aerum Mainnet",
url: "https://blockscout.com/aerum/mainnet",
other?: true
},
%{
title: "Callisto Mainnet",
url: "https://blockscout.com/callisto/mainnet",
other?: true
},
%{
title: "RSK Mainnet",
url: "https://blockscout.com/rsk/mainnet",

@ -13,7 +13,7 @@ msgstr[0] ""
msgstr[1] ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/overview.html.eex:192
#: lib/block_scout_web/templates/transaction/overview.html.eex:193
msgid " Token Transfer"
msgstr ""
@ -186,7 +186,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/block/_link.html.eex:2
#: lib/block_scout_web/templates/internal_transaction/_tile.html.eex:28
#: lib/block_scout_web/templates/tokens/transfer/_token_transfer.html.eex:46
#: lib/block_scout_web/templates/tokens/transfer/_token_transfer.html.eex:48
msgid "Block #%{number}"
msgstr ""
@ -251,7 +251,7 @@ msgstr ""
#: lib/block_scout_web/templates/address/_tabs.html.eex:32
#: lib/block_scout_web/templates/address/overview.html.eex:97
#: lib/block_scout_web/templates/address_validation/index.html.eex:13
#: lib/block_scout_web/views/address_view.ex:311
#: lib/block_scout_web/views/address_view.ex:313
msgid "Blocks Validated"
msgstr ""
@ -305,13 +305,13 @@ msgstr ""
#: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:187
#: lib/block_scout_web/templates/api_docs/_eth_rpc_item.html.eex:126
#: lib/block_scout_web/templates/api_docs/_eth_rpc_item.html.eex:149
#: lib/block_scout_web/views/address_view.ex:307
#: lib/block_scout_web/views/address_view.ex:309
msgid "Code"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/_tabs.html.eex:20
#: lib/block_scout_web/views/address_view.ex:310
#: lib/block_scout_web/views/address_view.ex:312
msgid "Coin Balance History"
msgstr ""
@ -526,7 +526,7 @@ msgid "Decoded"
msgstr ""
#, elixir-format
#: lib/block_scout_web/views/address_view.ex:308
#: lib/block_scout_web/views/address_view.ex:310
msgid "Decompiled Code"
msgstr ""
@ -546,16 +546,16 @@ msgid "Decompiler version"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/block/_tile.html.eex:56
#: lib/block_scout_web/templates/block/_tile.html.eex:57
#: lib/block_scout_web/templates/block/overview.html.eex:108
#: lib/block_scout_web/templates/block/overview.html.eex:158
#: lib/block_scout_web/templates/block/overview.html.eex:159
msgid "Gas Limit"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/block/_tile.html.eex:61
#: lib/block_scout_web/templates/block/_tile.html.eex:62
#: lib/block_scout_web/templates/block/overview.html.eex:101
#: lib/block_scout_web/templates/block/overview.html.eex:152
#: lib/block_scout_web/templates/block/overview.html.eex:153
msgid "Gas Used"
msgstr ""
@ -678,8 +678,8 @@ msgstr ""
#: lib/block_scout_web/templates/layout/app.html.eex:62
#: lib/block_scout_web/templates/transaction/_pending_tile.html.eex:20
#: lib/block_scout_web/templates/transaction/_tile.html.eex:29
#: lib/block_scout_web/templates/transaction/overview.html.eex:179
#: lib/block_scout_web/templates/transaction/overview.html.eex:214
#: lib/block_scout_web/templates/transaction/overview.html.eex:180
#: lib/block_scout_web/templates/transaction/overview.html.eex:215
#: lib/block_scout_web/views/wei_helpers.ex:78
msgid "Ether"
msgstr ""
@ -934,7 +934,7 @@ msgstr ""
#: lib/block_scout_web/templates/address/_tabs.html.eex:8
#: lib/block_scout_web/templates/address_token/index.html.eex:8
#: lib/block_scout_web/templates/address_token_transfer/index.html.eex:9
#: lib/block_scout_web/views/address_view.ex:304
#: lib/block_scout_web/views/address_view.ex:306
msgid "Tokens"
msgstr ""
@ -987,7 +987,7 @@ msgstr ""
#: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:19
#: lib/block_scout_web/templates/transaction/_tabs.html.eex:11
#: lib/block_scout_web/templates/transaction_internal_transaction/index.html.eex:6
#: lib/block_scout_web/views/address_view.ex:306
#: lib/block_scout_web/views/address_view.ex:308
#: lib/block_scout_web/views/transaction_view.ex:314
msgid "Internal Transactions"
msgstr ""
@ -1048,7 +1048,7 @@ msgid "License ID"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/overview.html.eex:242
#: lib/block_scout_web/templates/transaction/overview.html.eex:243
msgid "Limit"
msgstr ""
@ -1076,7 +1076,7 @@ msgstr ""
#: lib/block_scout_web/templates/address_logs/index.html.eex:8
#: lib/block_scout_web/templates/transaction/_tabs.html.eex:17
#: lib/block_scout_web/templates/transaction_log/index.html.eex:8
#: lib/block_scout_web/views/address_view.ex:312
#: lib/block_scout_web/views/address_view.ex:314
#: lib/block_scout_web/views/transaction_view.ex:315
msgid "Logs"
msgstr ""
@ -1267,7 +1267,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/_tabs.html.eex:58
#: lib/block_scout_web/templates/tokens/overview/_tabs.html.eex:25
#: lib/block_scout_web/views/address_view.ex:309
#: lib/block_scout_web/views/address_view.ex:311
#: lib/block_scout_web/views/tokens/overview_view.ex:37
msgid "Read Contract"
msgstr ""
@ -1301,8 +1301,8 @@ msgid "Responses"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/block/_tile.html.eex:47
#: lib/block_scout_web/templates/chain/_block.html.eex:23
#: lib/block_scout_web/templates/block/_tile.html.eex:48
#: lib/block_scout_web/templates/chain/_block.html.eex:24
#: lib/block_scout_web/views/internal_transaction_view.ex:28
msgid "Reward"
msgstr ""
@ -1366,7 +1366,7 @@ msgid "Show Validator Info"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/block/overview.html.eex:145
#: lib/block_scout_web/templates/block/overview.html.eex:146
msgid "Block Rewards"
msgstr ""
@ -1559,7 +1559,7 @@ msgstr ""
#: lib/block_scout_web/templates/block_transaction/index.html.eex:18
#: lib/block_scout_web/templates/chain/show.html.eex:145
#: lib/block_scout_web/templates/layout/_topnav.html.eex:64
#: lib/block_scout_web/views/address_view.ex:305
#: lib/block_scout_web/views/address_view.ex:307
msgid "Transactions"
msgstr ""
@ -1620,7 +1620,7 @@ msgid "Use the search box to find a hosted network, or select from the list of a
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/overview.html.eex:236
#: lib/block_scout_web/templates/transaction/overview.html.eex:237
msgid "Used"
msgstr ""
@ -1650,8 +1650,8 @@ msgid "Validator Info"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/overview.html.eex:179
#: lib/block_scout_web/templates/transaction/overview.html.eex:214
#: lib/block_scout_web/templates/transaction/overview.html.eex:180
#: lib/block_scout_web/templates/transaction/overview.html.eex:215
msgid "Value"
msgstr ""
@ -1826,7 +1826,7 @@ msgid "Decimals"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/overview.html.eex:232
#: lib/block_scout_web/templates/transaction/overview.html.eex:233
msgid "Gas"
msgstr ""
@ -1872,3 +1872,8 @@ msgstr ""
#: lib/block_scout_web/templates/tokens/instance/overview/_details.html.eex:67
msgid "Transfers"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/overview.html.eex:134
msgid "Copy Txn Input"
msgstr ""

@ -13,7 +13,7 @@ msgstr[0] ""
msgstr[1] ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/overview.html.eex:192
#: lib/block_scout_web/templates/transaction/overview.html.eex:193
msgid " Token Transfer"
msgstr ""
@ -186,7 +186,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/block/_link.html.eex:2
#: lib/block_scout_web/templates/internal_transaction/_tile.html.eex:28
#: lib/block_scout_web/templates/tokens/transfer/_token_transfer.html.eex:46
#: lib/block_scout_web/templates/tokens/transfer/_token_transfer.html.eex:48
msgid "Block #%{number}"
msgstr ""
@ -251,7 +251,7 @@ msgstr ""
#: lib/block_scout_web/templates/address/_tabs.html.eex:32
#: lib/block_scout_web/templates/address/overview.html.eex:97
#: lib/block_scout_web/templates/address_validation/index.html.eex:13
#: lib/block_scout_web/views/address_view.ex:311
#: lib/block_scout_web/views/address_view.ex:313
msgid "Blocks Validated"
msgstr ""
@ -305,13 +305,13 @@ msgstr ""
#: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:187
#: lib/block_scout_web/templates/api_docs/_eth_rpc_item.html.eex:126
#: lib/block_scout_web/templates/api_docs/_eth_rpc_item.html.eex:149
#: lib/block_scout_web/views/address_view.ex:307
#: lib/block_scout_web/views/address_view.ex:309
msgid "Code"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/_tabs.html.eex:20
#: lib/block_scout_web/views/address_view.ex:310
#: lib/block_scout_web/views/address_view.ex:312
msgid "Coin Balance History"
msgstr ""
@ -526,7 +526,7 @@ msgid "Decoded"
msgstr ""
#, elixir-format
#: lib/block_scout_web/views/address_view.ex:308
#: lib/block_scout_web/views/address_view.ex:310
msgid "Decompiled Code"
msgstr ""
@ -546,16 +546,16 @@ msgid "Decompiler version"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/block/_tile.html.eex:56
#: lib/block_scout_web/templates/block/_tile.html.eex:57
#: lib/block_scout_web/templates/block/overview.html.eex:108
#: lib/block_scout_web/templates/block/overview.html.eex:158
#: lib/block_scout_web/templates/block/overview.html.eex:159
msgid "Gas Limit"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/block/_tile.html.eex:61
#: lib/block_scout_web/templates/block/_tile.html.eex:62
#: lib/block_scout_web/templates/block/overview.html.eex:101
#: lib/block_scout_web/templates/block/overview.html.eex:152
#: lib/block_scout_web/templates/block/overview.html.eex:153
msgid "Gas Used"
msgstr ""
@ -678,8 +678,8 @@ msgstr ""
#: lib/block_scout_web/templates/layout/app.html.eex:62
#: lib/block_scout_web/templates/transaction/_pending_tile.html.eex:20
#: lib/block_scout_web/templates/transaction/_tile.html.eex:29
#: lib/block_scout_web/templates/transaction/overview.html.eex:179
#: lib/block_scout_web/templates/transaction/overview.html.eex:214
#: lib/block_scout_web/templates/transaction/overview.html.eex:180
#: lib/block_scout_web/templates/transaction/overview.html.eex:215
#: lib/block_scout_web/views/wei_helpers.ex:78
msgid "Ether"
msgstr ""
@ -934,7 +934,7 @@ msgstr ""
#: lib/block_scout_web/templates/address/_tabs.html.eex:8
#: lib/block_scout_web/templates/address_token/index.html.eex:8
#: lib/block_scout_web/templates/address_token_transfer/index.html.eex:9
#: lib/block_scout_web/views/address_view.ex:304
#: lib/block_scout_web/views/address_view.ex:306
msgid "Tokens"
msgstr ""
@ -987,7 +987,7 @@ msgstr ""
#: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:19
#: lib/block_scout_web/templates/transaction/_tabs.html.eex:11
#: lib/block_scout_web/templates/transaction_internal_transaction/index.html.eex:6
#: lib/block_scout_web/views/address_view.ex:306
#: lib/block_scout_web/views/address_view.ex:308
#: lib/block_scout_web/views/transaction_view.ex:314
msgid "Internal Transactions"
msgstr ""
@ -1048,7 +1048,7 @@ msgid "License ID"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/overview.html.eex:242
#: lib/block_scout_web/templates/transaction/overview.html.eex:243
msgid "Limit"
msgstr ""
@ -1076,7 +1076,7 @@ msgstr ""
#: lib/block_scout_web/templates/address_logs/index.html.eex:8
#: lib/block_scout_web/templates/transaction/_tabs.html.eex:17
#: lib/block_scout_web/templates/transaction_log/index.html.eex:8
#: lib/block_scout_web/views/address_view.ex:312
#: lib/block_scout_web/views/address_view.ex:314
#: lib/block_scout_web/views/transaction_view.ex:315
msgid "Logs"
msgstr ""
@ -1267,7 +1267,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/_tabs.html.eex:58
#: lib/block_scout_web/templates/tokens/overview/_tabs.html.eex:25
#: lib/block_scout_web/views/address_view.ex:309
#: lib/block_scout_web/views/address_view.ex:311
#: lib/block_scout_web/views/tokens/overview_view.ex:37
msgid "Read Contract"
msgstr ""
@ -1301,8 +1301,8 @@ msgid "Responses"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/block/_tile.html.eex:47
#: lib/block_scout_web/templates/chain/_block.html.eex:23
#: lib/block_scout_web/templates/block/_tile.html.eex:48
#: lib/block_scout_web/templates/chain/_block.html.eex:24
#: lib/block_scout_web/views/internal_transaction_view.ex:28
msgid "Reward"
msgstr ""
@ -1366,7 +1366,7 @@ msgid "Show Validator Info"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/block/overview.html.eex:145
#: lib/block_scout_web/templates/block/overview.html.eex:146
msgid "Block Rewards"
msgstr ""
@ -1559,7 +1559,7 @@ msgstr ""
#: lib/block_scout_web/templates/block_transaction/index.html.eex:18
#: lib/block_scout_web/templates/chain/show.html.eex:145
#: lib/block_scout_web/templates/layout/_topnav.html.eex:64
#: lib/block_scout_web/views/address_view.ex:305
#: lib/block_scout_web/views/address_view.ex:307
msgid "Transactions"
msgstr ""
@ -1620,7 +1620,7 @@ msgid "Use the search box to find a hosted network, or select from the list of a
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/overview.html.eex:236
#: lib/block_scout_web/templates/transaction/overview.html.eex:237
msgid "Used"
msgstr ""
@ -1650,8 +1650,8 @@ msgid "Validator Info"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/overview.html.eex:179
#: lib/block_scout_web/templates/transaction/overview.html.eex:214
#: lib/block_scout_web/templates/transaction/overview.html.eex:180
#: lib/block_scout_web/templates/transaction/overview.html.eex:215
msgid "Value"
msgstr ""
@ -1826,7 +1826,7 @@ msgid "Decimals"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/overview.html.eex:232
#: lib/block_scout_web/templates/transaction/overview.html.eex:233
msgid "Gas"
msgstr ""
@ -1872,3 +1872,8 @@ msgstr ""
#: lib/block_scout_web/templates/tokens/instance/overview/_details.html.eex:67
msgid "Transfers"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/overview.html.eex:134
msgid "Copy Txn Input"
msgstr ""

@ -32,7 +32,8 @@ defmodule BlockScoutWeb.AddressViewTest do
partial: "_link.html",
address: ^to_address,
contract: false,
truncate: true
truncate: true,
use_custom_tooltip: false
] = AddressView.address_partial_selector(transaction, :to, nil, true)
end
@ -44,7 +45,8 @@ defmodule BlockScoutWeb.AddressViewTest do
partial: "_link.html",
address: ^to_address,
contract: false,
truncate: false
truncate: false,
use_custom_tooltip: false
] = AddressView.address_partial_selector(transaction, :to, nil)
end
@ -56,7 +58,8 @@ defmodule BlockScoutWeb.AddressViewTest do
partial: "_link.html",
address: ^to_address,
contract: false,
truncate: false
truncate: false,
use_custom_tooltip: false
] = AddressView.address_partial_selector(transaction, :to, nil)
end
@ -68,7 +71,8 @@ defmodule BlockScoutWeb.AddressViewTest do
partial: "_responsive_hash.html",
address: ^to_address,
contract: false,
truncate: false
truncate: false,
use_custom_tooltip: false
] = AddressView.address_partial_selector(transaction, :to, transaction.to_address)
end
@ -81,7 +85,8 @@ defmodule BlockScoutWeb.AddressViewTest do
partial: "_link.html",
address: ^contract_address,
contract: true,
truncate: false
truncate: false,
use_custom_tooltip: false
] = AddressView.address_partial_selector(transaction, :to, transaction.to_address)
end
@ -94,7 +99,8 @@ defmodule BlockScoutWeb.AddressViewTest do
partial: "_responsive_hash.html",
address: ^contract_address,
contract: true,
truncate: false
truncate: false,
use_custom_tooltip: false
] = AddressView.address_partial_selector(transaction, :to, contract_address)
end
@ -106,7 +112,8 @@ defmodule BlockScoutWeb.AddressViewTest do
partial: "_link.html",
address: ^to_address,
contract: false,
truncate: false
truncate: false,
use_custom_tooltip: false
] = AddressView.address_partial_selector(transaction, :to, nil)
end
@ -118,7 +125,8 @@ defmodule BlockScoutWeb.AddressViewTest do
partial: "_responsive_hash.html",
address: ^from_address,
contract: false,
truncate: false
truncate: false,
use_custom_tooltip: false
] = AddressView.address_partial_selector(transaction, :from, transaction.from_address)
end
end

@ -9,6 +9,10 @@ config :ethereum_jsonrpc, EthereumJSONRPC.RequestCoordinator,
wait_per_timeout: :timer.seconds(20),
max_jitter: :timer.seconds(2)
config :ethereum_jsonrpc,
rpc_transport: if(System.get_env("ETHEREUM_JSONRPC_JSON_RPC_TRANSPORT", "http") == "http", do: :http, else: :ipc),
ipc_path: System.get_env("IPC_PATH")
# Add this configuration to add global RPC request throttling.
# throttle_rate_limit: 250,
# throttle_rolling_window_opts: [

@ -5,7 +5,7 @@ defmodule EthereumJSONRPC.Application do
use Application
alias EthereumJSONRPC.{RequestCoordinator, RollingWindow}
alias EthereumJSONRPC.{IPC, RequestCoordinator, RollingWindow}
@impl Application
def start(_type, _args) do
@ -18,6 +18,7 @@ defmodule EthereumJSONRPC.Application do
Supervisor.child_spec({RollingWindow, [rolling_window_opts]}, id: RollingWindow.ErrorThrottle)
]
|> add_throttle_rolling_window(config)
|> add_ipc_client()
|> Supervisor.start_link(strategy: :one_for_one, name: EthereumJSONRPC.Supervisor)
end
@ -37,4 +38,26 @@ defmodule EthereumJSONRPC.Application do
children
end
end
defp add_ipc_client(children) do
case Application.get_env(:ethereum_jsonrpc, :rpc_transport) do
:ipc ->
[
:poolboy.child_spec(:worker, poolboy_config(), path: Application.get_env(:ethereum_jsonrpc, :ipc_path))
| children
]
_ ->
children
end
end
defp poolboy_config do
[
{:name, {:local, :ipc_worker}},
{:worker_module, IPC},
{:size, 10},
{:max_overflow, 5}
]
end
end

@ -132,7 +132,7 @@ defmodule EthereumJSONRPC.HTTP do
# restrict response to only those fields supported by the JSON-RPC 2.0 standard, which means that level of keys is
# validated, so we can indicate that with switch to atom keys.
defp standardize_response(%{"jsonrpc" => "2.0" = jsonrpc, "id" => id} = unstandardized) do
def standardize_response(%{"jsonrpc" => "2.0" = jsonrpc, "id" => id} = unstandardized) do
# Nethermind return string ids
id = quantity_to_integer(id)
@ -155,8 +155,8 @@ defmodule EthereumJSONRPC.HTTP do
# restrict error to only those fields supported by the JSON-RPC 2.0 standard, which means that level of keys is
# validated, so we can indicate that with switch to atom keys.
defp standardize_error(%{"code" => code, "message" => message} = unstandardized)
when is_integer(code) and is_binary(message) do
def standardize_error(%{"code" => code, "message" => message} = unstandardized)
when is_integer(code) and is_binary(message) do
standardized = %{code: code, message: message}
case Map.fetch(unstandardized, "data") do

@ -0,0 +1,94 @@
defmodule EthereumJSONRPC.IPC do
use GenServer
@moduledoc false
import EthereumJSONRPC.HTTP, only: [standardize_response: 1]
# Server
def start_link(opts) do
GenServer.start_link(__MODULE__, Keyword.merge(opts, socket: nil))
end
def init(state) do
opts = [:binary, active: false, reuseaddr: true]
response = :gen_tcp.connect({:local, state[:path]}, 0, opts)
case response do
{:ok, socket} -> {:ok, Keyword.put(state, :socket, socket)}
{:error, reason} -> {:error, reason}
end
end
def post(pid, request) do
GenServer.call(pid, {:request, request})
end
def receive_response(data, socket, timeout, result \\ <<>>)
def receive_response({:error, reason}, _socket, _timeout, _result) do
{:error, reason}
end
def receive_response(:ok, socket, timeout, result) do
with {:ok, response} <- :gen_tcp.recv(socket, 0, timeout) do
new_result = result <> response
if String.ends_with?(response, "\n") do
{:ok, new_result}
else
receive_response(:ok, socket, timeout, new_result)
end
end
end
def receive_response(data, _socket, _timeout, _result) do
{:error, data}
end
def handle_call(
{:request, request},
_from,
[socket: socket, path: _] = state
) do
response =
socket
|> :gen_tcp.send(request)
|> receive_response(socket, 500_000)
{:reply, response, state}
end
# Client
def request(pid, payload) do
with {:ok, response} <- post(pid, Jason.encode!(payload)),
{:ok, decoded_body} <- Jason.decode(response) do
case decoded_body do
%{"error" => error} ->
{:error, error}
result = [%{} | _] ->
list =
result
|> Enum.reverse()
|> List.flatten()
|> Enum.map(&standardize_response/1)
{:ok, list}
result ->
{:ok, Map.get(result, "result")}
end
else
{:error, %Jason.DecodeError{data: ""}} -> {:error, :empty_response}
{:error, error} -> {:error, {:invalid_json, error}}
{:error, error} -> {:error, error}
end
end
def json_rpc(payload, _opts) do
:poolboy.transaction(:ipc_worker, fn pid -> request(pid, payload) end, 600_000)
end
end

@ -91,7 +91,8 @@ defmodule EthereumJsonrpc.MixProject do
{:websocket_client, "~> 1.3"},
{:decimal, "~> 1.0"},
{:decorator, "~> 1.2"},
{:hackney, "~> 1.15.2"}
{:hackney, "~> 1.15.2"},
{:poolboy, "~> 1.5.2"}
]
end
end

@ -16,6 +16,11 @@ config :explorer,
include_uncles_in_average_block_time:
if(System.get_env("UNCLES_IN_AVERAGE_BLOCK_TIME") == "true", do: true, else: false),
healthy_blocks_period: System.get_env("HEALTHY_BLOCKS_PERIOD") || :timer.minutes(5),
realtime_events_sender:
if(System.get_env("DISABLE_WEBAPP") != "true",
do: Explorer.Chain.Events.SimpleSender,
else: Explorer.Chain.Events.DBSender
),
index_internal_transactions_for_token_transfers:
if(System.get_env("INTERNAL_TRANSACTIONOS_FOR_TOKEN_TRANSFERS") == "true", do: true, else: false)
@ -29,6 +34,13 @@ config :explorer, Explorer.Counters.AverageBlockTime,
enabled: true,
period: average_block_period
config :explorer, Explorer.Chain.Events.Listener,
enabled:
if(System.get_env("DISABLE_WEBAPP") == nil && System.get_env("DISABLE_INDEXER") == nil,
do: false,
else: true
)
config :explorer, Explorer.ChainSpec.GenesisData,
enabled: true,
chain_spec_path: System.get_env("CHAIN_SPEC_PATH"),

@ -43,6 +43,9 @@ end
config :explorer, Explorer.ExchangeRates.Source.TransactionAndLog,
secondary_source: Explorer.ExchangeRates.Source.OneCoinSource
config :explorer,
realtime_events_sender: Explorer.Chain.Events.SimpleSender
variant =
if is_nil(System.get_env("ETHEREUM_JSONRPC_VARIANT")) do
"parity"

@ -71,6 +71,7 @@ defmodule Explorer.Application do
configure(Explorer.ChainSpec.GenesisData),
configure(Explorer.KnownTokens),
configure(Explorer.Market.History.Cataloger),
configure(Explorer.Chain.Events.Listener),
configure(Explorer.Counters.AddressesWithBalanceCounter),
configure(Explorer.Counters.AddressesCounter),
configure(Explorer.Counters.AverageBlockTime),

@ -0,0 +1,26 @@
defmodule Explorer.Chain.Events.DBSender do
@moduledoc """
Sends events to Postgres.
"""
alias Explorer.Repo
def send_data(event_type) do
payload = encode_payload({:chain_event, event_type})
send_notify(payload)
end
def send_data(event_type, broadcast_type, event_data) do
payload = encode_payload({:chain_event, event_type, broadcast_type, event_data})
send_notify(payload)
end
defp encode_payload(payload) do
payload
|> :erlang.term_to_binary([:compressed])
|> Base.encode64()
end
defp send_notify(payload) do
Repo.query!("select pg_notify('chain_event', $1::text);", [payload])
end
end

@ -0,0 +1,55 @@
defmodule Explorer.Chain.Events.Listener do
@moduledoc """
Listens and publishes events from PG
"""
use GenServer
alias Postgrex.Notifications
def start_link(_) do
GenServer.start_link(__MODULE__, "chain_event", name: __MODULE__)
end
def init(channel) do
{:ok, pid} =
:explorer
|> Application.get_env(Explorer.Repo)
|> Notifications.start_link()
ref = Notifications.listen!(pid, channel)
{:ok, {pid, ref, channel}}
end
def handle_info({:notification, _pid, _ref, _topic, payload}, state) do
payload
|> decode_payload!()
|> broadcast()
{:noreply, state}
end
# sobelow_skip ["Misc.BinToTerm"]
defp decode_payload!(payload) do
payload
|> Base.decode64!()
|> :erlang.binary_to_term()
end
defp broadcast({:chain_event, event_type} = event) do
Registry.dispatch(Registry.ChainEvents, event_type, fn entries ->
for {pid, _registered_val} <- entries do
send(pid, event)
end
end)
end
defp broadcast({:chain_event, event_type, broadcast_type, _data} = event) do
Registry.dispatch(Registry.ChainEvents, {event_type, broadcast_type}, fn entries ->
for {pid, _registered_val} <- entries do
send(pid, event)
end
end)
end
end

@ -16,14 +16,15 @@ defmodule Explorer.Chain.Events.Publisher do
@spec broadcast(atom()) :: :ok
def broadcast(event_type) do
send_data(event_type)
:ok
end
defp send_data(event_type) do
Registry.dispatch(Registry.ChainEvents, event_type, fn entries ->
for {pid, _registered_val} <- entries do
send(pid, {:chain_event, event_type})
end
end)
sender().send_data(event_type)
end
defp sender do
Application.get_env(:explorer, :realtime_events_sender)
end
# The :catchup type of event is not being consumed right now.
@ -32,10 +33,6 @@ defmodule Explorer.Chain.Events.Publisher do
defp send_data(_event_type, :catchup, _event_data), do: :ok
defp send_data(event_type, broadcast_type, event_data) do
Registry.dispatch(Registry.ChainEvents, {event_type, broadcast_type}, fn entries ->
for {pid, _registered_val} <- entries do
send(pid, {:chain_event, event_type, broadcast_type, event_data})
end
end)
sender().send_data(event_type, broadcast_type, event_data)
end
end

@ -0,0 +1,21 @@
defmodule Explorer.Chain.Events.SimpleSender do
@moduledoc """
Publishes events through Registry without intermediate levels.
"""
def send_data(event_type, broadcast_type, event_data) do
Registry.dispatch(Registry.ChainEvents, {event_type, broadcast_type}, fn entries ->
for {pid, _registered_val} <- entries do
send(pid, {:chain_event, event_type, broadcast_type, event_data})
end
end)
end
def send_data(event_type) do
Registry.dispatch(Registry.ChainEvents, event_type, fn entries ->
for {pid, _registered_val} <- entries do
send(pid, {:chain_event, event_type})
end
end)
end
end

@ -280,7 +280,7 @@ defmodule Explorer.Chain.TokenTransfer do
tt in TokenTransfer,
left_join: instance in Instance,
on: tt.token_contract_address_hash == instance.token_contract_address_hash and tt.token_id == instance.token_id,
where: tt.token_contract_address_hash == ^contract_address_hash and tt.token_id == tt.token_id,
where: tt.token_contract_address_hash == ^contract_address_hash,
order_by: [desc: tt.block_number],
distinct: tt.token_id,
preload: [:to_address],

@ -15,7 +15,7 @@ defmodule Explorer.Chain.Events.PublisherTest do
Publisher.broadcast([{event_type, event_data}], broadcast_type)
assert_received {:chain_event, ^event_type, ^broadcast_type, []}
assert_receive {:chain_event, ^event_type, ^broadcast_type, []}
end
test "won't send chain_event of catchup type" do
@ -59,7 +59,7 @@ defmodule Explorer.Chain.Events.PublisherTest do
Publisher.broadcast(event_type)
assert_received {:chain_event, ^event_type}
assert_receive {:chain_event, ^event_type}
end
end
end

@ -15,7 +15,7 @@ defmodule Explorer.Chain.Events.SubscriberTest do
Publisher.broadcast([{event_type, event_data}], broadcast_type)
assert_received {:chain_event, :blocks, :realtime, []}
assert_receive {:chain_event, :blocks, :realtime, []}
end
end
@ -27,7 +27,7 @@ defmodule Explorer.Chain.Events.SubscriberTest do
Publisher.broadcast(event_type)
assert_received {:chain_event, :exchange_rate}
assert_receive {:chain_event, :exchange_rate}
end
end
end

@ -470,27 +470,27 @@ defmodule Explorer.Chain.ImportTest do
test "publishes addresses with updated fetched_coin_balance data to subscribers on insert" do
Subscriber.to(:addresses, :realtime)
Import.all(@import_data)
assert_received {:chain_event, :addresses, :realtime, [%Address{}, %Address{}, %Address{}]}
assert_receive {:chain_event, :addresses, :realtime, [%Address{}, %Address{}, %Address{}]}
end
test "publishes block data to subscribers on insert" do
Subscriber.to(:blocks, :realtime)
Import.all(@import_data)
assert_received {:chain_event, :blocks, :realtime, [%Block{}]}
assert_receive {:chain_event, :blocks, :realtime, [%Block{}]}
end
test "publishes internal_transaction data to subscribers on insert" do
Subscriber.to(:internal_transactions, :realtime)
Import.all(@import_data)
assert_received {:chain_event, :internal_transactions, :realtime,
[%{transaction_hash: _, index: _}, %{transaction_hash: _, index: _}]}
assert_receive {:chain_event, :internal_transactions, :realtime,
[%{transaction_hash: _, index: _}, %{transaction_hash: _, index: _}]}
end
test "publishes transactions data to subscribers on insert" do
Subscriber.to(:transactions, :realtime)
Import.all(@import_data)
assert_received {:chain_event, :transactions, :realtime, [%Transaction{}]}
assert_receive {:chain_event, :transactions, :realtime, [%Transaction{}]}
end
test "publishes token_transfers data to subscribers on insert" do
@ -498,7 +498,7 @@ defmodule Explorer.Chain.ImportTest do
Import.all(@import_data)
assert_received {:chain_event, :token_transfers, :realtime, [%TokenTransfer{}]}
assert_receive {:chain_event, :token_transfers, :realtime, [%TokenTransfer{}]}
end
test "does not broadcast if broadcast option is false" do

@ -3,7 +3,11 @@ use Mix.Config
config :indexer,
block_interval: :timer.seconds(5),
json_rpc_named_arguments: [
transport: EthereumJSONRPC.HTTP,
transport:
if(System.get_env("ETHEREUM_JSONRPC_JSON_RPC_TRANSPORT", "http") == "http",
do: EthereumJSONRPC.HTTP,
else: EthereumJSONRPC.IPC
),
transport_options: [
http: EthereumJSONRPC.HTTP.HTTPoison,
url: System.get_env("ETHEREUM_JSONRPC_HTTP_URL") || "http://localhost:7545",

@ -3,7 +3,11 @@ use Mix.Config
config :indexer,
block_interval: :timer.seconds(5),
json_rpc_named_arguments: [
transport: EthereumJSONRPC.HTTP,
transport:
if(System.get_env("ETHEREUM_JSONRPC_JSON_RPC_TRANSPORT", "http") == "http",
do: EthereumJSONRPC.HTTP,
else: EthereumJSONRPC.IPC
),
transport_options: [
http: EthereumJSONRPC.HTTP.HTTPoison,
url: System.get_env("ETHEREUM_JSONRPC_HTTP_URL") || "https://mainnet.infura.io/8lTvJTKmHPCHazkneJsY",

@ -3,7 +3,12 @@ use Mix.Config
config :indexer,
block_interval: :timer.seconds(5),
json_rpc_named_arguments: [
transport: EthereumJSONRPC.HTTP,
transport:
if(System.get_env("ETHEREUM_JSONRPC_JSON_RPC_TRANSPORT", "http") == "http",
do: EthereumJSONRPC.HTTP,
else: EthereumJSONRPC.IPC
),
else: EthereumJSONRPC.IPC,
transport_options: [
http: EthereumJSONRPC.HTTP.HTTPoison,
url: System.get_env("ETHEREUM_JSONRPC_HTTP_URL") || "http://localhost:8545",

@ -5,7 +5,11 @@ config :indexer,
blocks_concurrency: 1,
receipts_concurrency: 1,
json_rpc_named_arguments: [
transport: EthereumJSONRPC.HTTP,
transport:
if(System.get_env("ETHEREUM_JSONRPC_JSON_RPC_TRANSPORT", "http") == "http",
do: EthereumJSONRPC.HTTP,
else: EthereumJSONRPC.IPC
),
transport_options: [
http: EthereumJSONRPC.HTTP.HTTPoison,
url: System.get_env("ETHEREUM_JSONRPC_HTTP_URL") || "http://localhost:8545",

@ -3,7 +3,11 @@ use Mix.Config
config :indexer,
block_interval: :timer.seconds(5),
json_rpc_named_arguments: [
transport: EthereumJSONRPC.HTTP,
transport:
if(System.get_env("ETHEREUM_JSONRPC_JSON_RPC_TRANSPORT", "http") == "http",
do: EthereumJSONRPC.HTTP,
else: EthereumJSONRPC.IPC
),
transport_options: [
http: EthereumJSONRPC.HTTP.HTTPoison,
url: System.get_env("ETHEREUM_JSONRPC_HTTP_URL") || "http://localhost:7545",

@ -3,7 +3,11 @@ use Mix.Config
config :indexer,
block_interval: :timer.seconds(5),
json_rpc_named_arguments: [
transport: EthereumJSONRPC.HTTP,
transport:
if(System.get_env("ETHEREUM_JSONRPC_JSON_RPC_TRANSPORT", "http") == "http",
do: EthereumJSONRPC.HTTP,
else: EthereumJSONRPC.IPC
),
transport_options: [
http: EthereumJSONRPC.HTTP.HTTPoison,
url: System.get_env("ETHEREUM_JSONRPC_HTTP_URL") || "https://mainnet.infura.io/8lTvJTKmHPCHazkneJsY",

@ -3,7 +3,11 @@ use Mix.Config
config :indexer,
block_interval: :timer.seconds(5),
json_rpc_named_arguments: [
transport: EthereumJSONRPC.HTTP,
transport:
if(System.get_env("ETHEREUM_JSONRPC_JSON_RPC_TRANSPORT", "http") == "http",
do: EthereumJSONRPC.HTTP,
else: EthereumJSONRPC.IPC
),
transport_options: [
http: EthereumJSONRPC.HTTP.HTTPoison,
url: System.get_env("ETHEREUM_JSONRPC_HTTP_URL"),

@ -5,7 +5,11 @@ config :indexer,
blocks_concurrency: 1,
receipts_concurrency: 1,
json_rpc_named_arguments: [
transport: EthereumJSONRPC.HTTP,
transport:
if(System.get_env("ETHEREUM_JSONRPC_JSON_RPC_TRANSPORT", "http") == "http",
do: EthereumJSONRPC.HTTP,
else: EthereumJSONRPC.IPC
),
transport_options: [
http: EthereumJSONRPC.HTTP.HTTPoison,
url: System.get_env("ETHEREUM_JSONRPC_HTTP_URL"),

@ -1,77 +1,5 @@
# BlockScout Docker integration
# BlockScout Docker Integration
For now this integration is not production ready. It made only for local usage only !
## How to use ?
First of all, blockscout requires `PostgreSQL` server for working.
It will be provided by starting script (new docker image will be created named `postgres`)
**Starting command**
`make start` - will set everything up and start blockscout in container.
To connect it to your local environment you will have to configure it using [env variables](#env-variables)
Example connecting to local `ganache` instance running on port `2000` on Mac/Windows:
```bash
COIN=DAI \
ETHEREUM_JSONRPC_VARIANT=ganache \
ETHEREUM_JSONRPC_HTTP_URL=http://host.docker.internal:2000 \
ETHEREUM_JSONRPC_WS_URL=ws://host.docker.internal:2000 \
make start
```
Blockscout will be available on `localhost:4000`
**Note**
On mac/Windows Docker provides with a special URL `host.docker.internal` that will be available into container and routed to your local machine.
On Linux docker is starting using `--network=host` and all services should be available on `localhost`
### Migrations
By default, `Makefile` will do migrations for you on `PostgreSQL` creation.
But you could run migrations manually using `make migrate` command.
**WARNING** Migrations will clean up your local database !
## Env variables
BlockScout supports 3 different JSON RPC Variants.
Variant could be configured using `ETHEREUM_JSONRPC_VARIANT` environment variable.
Example:
```bash
ETHEREUM_JSONRPC_VARIANT=ganache make start
```
Available options are:
* `parity` - Parity JSON RPC (**Default one**)
* `geth` - Geth JSON RPC
* `ganache` - Ganache JSON RPC
| Variable | Description | Default value |
| -------- | ----------- | ------------- |
| `ETHEREUM_JSONRPC_VARIANT` | Variant of your JSON RPC service: `parity`, `geth` or `ganache` | `parity` |
| `ETHEREUM_JSONRPC_HTTP_URL` | HTTP JSON RPC URL Only for `geth` or `ganache` variant | Different per JSONRPC variant |
| `ETHEREUM_JSONRPC_WS_URL` | WS JSON RPC url | Different per JSONRPC variant |
| `ETHEREUM_JSONRPC_TRACE_URL` | Trace URL **Only for `parity` variant** | `http://localhost:8545` |
| `COIN` | Default Coin | `POA` |
| `LOGO` | Coin logo | Empty |
| `NETWORK` | Network | Empty |
| `SUBNETWORK` | Subnetwork | Empty |
| `NETWORK_ICON` | Network icon | Empty |
| `NETWORK_PATH` | Network path | `/` |
`ETHEREUM_JSONRPC_HTTP_URL` default values:
* For `parity` - `http://localhost:8545`
* For `geth` - `https://mainnet.infura.io/8lTvJTKmHPCHazkneJsY`
* For `ganache` - `http://localhost:7545`
`ETHEREUM_JSONRPC_WS_URL` default values:
* For `parity` - `ws://localhost:8546`
* For `geth` - `wss://mainnet.infura.io/8lTvJTKmHPCHazkneJsY/ws`
* For `ganache` - `ws://localhost:7545`
This integration is not production ready, and should be used for local BlockScout deployment only.
For usage instructions and ENV variables, see the [docker integration documentation](https://docs.blockscout.com/for-developers/information-and-settings/docker-integration-local-use-only).
Loading…
Cancel
Save