Merge branch 'master' into ab-fix-large-numbers-balance

pull/2164/head
Victor Baranov 6 years ago committed by GitHub
commit 94a39eeece
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 8
      CHANGELOG.md
  2. 2
      README.md
  3. 12
      apps/block_scout_web/assets/css/components/_tile.scss
  4. 12
      apps/block_scout_web/assets/static/images/dai_logo.svg
  5. 2
      apps/block_scout_web/lib/block_scout_web/controllers/address_transaction_controller.ex
  6. 8
      apps/block_scout_web/lib/block_scout_web/controllers/pending_transaction_controller.ex
  7. 7
      apps/block_scout_web/lib/block_scout_web/templates/address_decompiled_contract/index.html.eex
  8. 2
      apps/block_scout_web/lib/block_scout_web/templates/layout/_topnav.html.eex
  9. 4
      apps/block_scout_web/lib/block_scout_web/templates/transaction/_tile.html.eex
  10. 6
      apps/block_scout_web/lib/block_scout_web/views/address_decompiled_contract_view.ex
  11. 11
      apps/block_scout_web/priv/gettext/default.pot
  12. 11
      apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po
  13. 4
      apps/block_scout_web/test/block_scout_web/controllers/block_controller_test.exs
  14. 4
      apps/block_scout_web/test/block_scout_web/controllers/chain_controller_test.exs
  15. 9
      apps/block_scout_web/test/block_scout_web/controllers/pending_transaction_controller_test.exs
  16. 4
      apps/block_scout_web/test/block_scout_web/features/viewing_chain_test.exs
  17. 8
      apps/block_scout_web/test/block_scout_web/views/address_decompiled_contract_view_test.exs
  18. 13
      apps/ethereum_jsonrpc/lib/ethereum_jsonrpc.ex
  19. 18
      apps/ethereum_jsonrpc/test/ethereum_jsonrpc_test.exs
  20. 3
      apps/explorer/config/config.exs
  21. 18
      apps/explorer/lib/explorer/application.ex
  22. 101
      apps/explorer/lib/explorer/chain.ex
  23. 70
      apps/explorer/lib/explorer/chain/address.ex
  24. 44
      apps/explorer/lib/explorer/chain/net_version_cache.ex
  25. 37
      apps/explorer/lib/explorer/chain/transaction.ex
  26. 7
      apps/explorer/priv/repo/migrations/20190613065856_add_tx_hash_inserted_at_index.exs
  27. 21
      apps/explorer/test/explorer/chain/address_test.exs
  28. 4
      apps/explorer/test/explorer/chain/blocks_cache_test.exs
  29. 4
      apps/explorer/test/support/data_case.ex

@ -3,9 +3,12 @@
### Features
- [#2109](https://github.com/poanetwork/blockscout/pull/2109) - use bigger updates instead of `Multi` transactions in BlocksTransactionsMismatch
- [#2075](https://github.com/poanetwork/blockscout/pull/2075) - add blocks cache
- [#2151](https://github.com/poanetwork/blockscout/pull/2151) - hide dropdown menu then other networks list is empty
### Fixes
- [#2164](https://github.com/poanetwork/blockscout/pull/2164) - fix large numbers in balance view card
- [#2155](https://github.com/poanetwork/blockscout/pull/2155) - fix pending transaction query
- [#2183](https://github.com/poanetwork/blockscout/pull/2183) - tile content aligning for mobile resolution fix, dai logo fix
- [#2162](https://github.com/poanetwork/blockscout/pull/2162) - contract creation tile color changed
- [#2144](https://github.com/poanetwork/blockscout/pull/2144) - 'page not found' images path fixed for goerli
- [#2142](https://github.com/poanetwork/blockscout/pull/2142) - Removed posdao theme and logo, added 'page not found' image for goerli
@ -20,14 +23,19 @@
- [#2090](https://github.com/poanetwork/blockscout/pull/2090) - updated some ETC theme colors
- [#2096](https://github.com/poanetwork/blockscout/pull/2096) - RSK theme fixes
- [#2093](https://github.com/poanetwork/blockscout/pull/2093) - detect token transfer type for deprecated erc721 spec
- [#2111](https://github.com/poanetwork/blockscout/pull/2111) - improve address transaction controller
- [#2108](https://github.com/poanetwork/blockscout/pull/2108) - fix uncle fetching without full transactions
- [#2128](https://github.com/poanetwork/blockscout/pull/2128) - add new function clause for uncle errors
- [#2123](https://github.com/poanetwork/blockscout/pull/2123) - fix coins percentage view
- [#2119](https://github.com/poanetwork/blockscout/pull/2119) - fix map logging
- [#2130](https://github.com/poanetwork/blockscout/pull/2130) - fix navigation
- [#2147](https://github.com/poanetwork/blockscout/pull/2147) - add rsk format of checksum
- [#2149](https://github.com/poanetwork/blockscout/pull/2149) - remove pending transaction count
- [#2186](https://github.com/poanetwork/blockscout/pull/2186) - fix net version test
### Chore
- [#2127](https://github.com/poanetwork/blockscout/pull/2127) - use previouse chromedriver version
- [#2118](https://github.com/poanetwork/blockscout/pull/2118) - show only the last decompiled contract
### Chore

@ -54,6 +54,8 @@ Currently available block explorers (i.e. Etherscan and Etherchain) are closed s
| [xDai Chain](https://blockscout.com/poa/dai) | | [SafeChain](https://explorer.safechain.io) |
| | | [SpringChain](https://explorer.springrole.com/) |
| | | [Kotti Testnet](https://kottiexplorer.ethernode.io/) |
| | | [Loom](http://plasma-blockexplorer.dappchains.com/) |
| | | [Tenda](https://tenda.network) |
### Visual Interface

@ -104,6 +104,18 @@ $tile-body-a-color: #5959d8 !default;
padding: 0 5px;
}
.tile-transaction-type-block {
.tile-status-label {
padding: 0;
}
}
.tile-bottom {
@media (max-width: 767px) {
justify-content: flex-start !important;
}
}
.tile-bottom-contents {
background-color: #f6f7f9;
font-size: 12px;

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

@ -28,7 +28,7 @@ defmodule BlockScoutWeb.AddressTransactionController do
def index(conn, %{"address_id" => address_hash_string, "type" => "JSON"} = params) do
with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string),
{:ok, address} <- Chain.hash_to_address(address_hash) do
{:ok, address} <- Chain.hash_to_address(address_hash, [:names], false) do
options =
@transaction_necessity_by_association
|> put_in([:necessity_by_association, :block], :required)

@ -13,7 +13,8 @@ defmodule BlockScoutWeb.PendingTransactionController do
[
necessity_by_association: %{
[from_address: :names] => :optional,
[to_address: :names] => :optional
[to_address: :names] => :optional,
[created_contract_address: :names] => :optional
}
],
paging_options(params)
@ -51,10 +52,7 @@ defmodule BlockScoutWeb.PendingTransactionController do
end
def index(conn, _params) do
render(conn, "index.html",
current_path: current_path(conn),
pending_transaction_count: Chain.pending_transaction_count()
)
render(conn, "index.html", current_path: current_path(conn))
end
defp get_pending_transactions_and_next_page(options) do

@ -2,7 +2,8 @@
<%= render BlockScoutWeb.AddressView, "overview.html", assigns %>
<div class="card">
<%= render BlockScoutWeb.AddressView, "_tabs.html", assigns %>
<%= for contract <- sort_contracts_by_version(@address.decompiled_smart_contracts) do %>
<% contract = last_decompiled_contract_version(@address.decompiled_smart_contracts) %>
<%= if contract do %>
<div class="card-body">
<h3><%= gettext "Decompiler version" %></h3>
<div class="tile tile-muted">
@ -21,6 +22,10 @@
</div>
</section>
</div>
<% else %>
<div class="tile tile-muted text-center">
<%= gettext "There is no decompilded contracts for this address." %>
</div>
<% end %>
</div>
</section>

@ -77,7 +77,7 @@
</div>
</li>
<li class="nav-item dropdown nav-item-networks">
<a class="nav-link topnav-nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<a class="nav-link topnav-nav-link <%= if dropdown_nets() == [], do: "disabled", else: "dropdown-toggle" %>" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="nav-link-icon">
<%= render BlockScoutWeb.IconsView, "_active_icon.html" %>
</span>

@ -19,7 +19,7 @@
<!-- Content -->
<div class="col-md-7 col-lg-8 d-flex flex-column pr-2 pr-sm-2 pr-md-0">
<%= render "_link.html", transaction_hash: @transaction.hash %>
<span class="text-nowrap">
<span>
<%= @transaction |> BlockScoutWeb.AddressView.address_partial_selector(:from, assigns[:current_address]) |> BlockScoutWeb.RenderHelpers.render_partial() %>
&rarr;
<%= @transaction |> BlockScoutWeb.AddressView.address_partial_selector(:to, assigns[:current_address]) |> BlockScoutWeb.RenderHelpers.render_partial() %>
@ -58,7 +58,7 @@
<% end %>
</div>
<!-- Block info -->
<div class="col-md-3 col-lg-2 d-flex flex-row flex-md-column flex-nowrap justify-content-center text-md-right mt-3 mt-md-0">
<div class="col-md-3 col-lg-2 d-flex flex-row flex-md-column flex-nowrap justify-content-center text-md-right mt-3 mt-md-0 tile-bottom">
<span class="mr-2 mr-md-0 order-1">
<%= @transaction |> block_number() |> BlockScoutWeb.RenderHelpers.render_partial() %>
</span>

@ -230,10 +230,8 @@ defmodule BlockScoutWeb.AddressDecompiledContractView do
end)
end
def sort_contracts_by_version(decompiled_contracts) do
decompiled_contracts
|> Enum.sort_by(& &1.decompiler_version)
|> Enum.reverse()
def last_decompiled_contract_version(decompiled_contracts) do
Enum.max_by(decompiled_contracts, & &1.decompiler_version)
end
defp add_line_numbers(code) do

@ -1490,7 +1490,7 @@ msgid "EVM Version"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_decompiled_contract/index.html.eex:16
#: lib/block_scout_web/templates/address_decompiled_contract/index.html.eex:17
msgid "Copy Decompiled Contract Code"
msgstr ""
@ -1505,12 +1505,12 @@ msgid "Decompiled code"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_decompiled_contract/index.html.eex:14
#: lib/block_scout_web/templates/address_decompiled_contract/index.html.eex:15
msgid "Decompiled contract code"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_decompiled_contract/index.html.eex:7
#: lib/block_scout_web/templates/address_decompiled_contract/index.html.eex:8
msgid "Decompiler version"
msgstr ""
@ -1697,3 +1697,8 @@ msgstr ""
#: lib/block_scout_web/templates/transaction/overview.html.eex:178
msgid " Token Transfer"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_decompiled_contract/index.html.eex:27
msgid "There is no decompilded contracts for this address."
msgstr ""

@ -1490,7 +1490,7 @@ msgid "EVM Version"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_decompiled_contract/index.html.eex:16
#: lib/block_scout_web/templates/address_decompiled_contract/index.html.eex:17
msgid "Copy Decompiled Contract Code"
msgstr ""
@ -1505,12 +1505,12 @@ msgid "Decompiled code"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_decompiled_contract/index.html.eex:14
#: lib/block_scout_web/templates/address_decompiled_contract/index.html.eex:15
msgid "Decompiled contract code"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_decompiled_contract/index.html.eex:7
#: lib/block_scout_web/templates/address_decompiled_contract/index.html.eex:8
msgid "Decompiler version"
msgstr ""
@ -1697,3 +1697,8 @@ msgstr ""
#: lib/block_scout_web/templates/transaction/overview.html.eex:178
msgid " Token Transfer"
msgstr ""
#, elixir-format, fuzzy
#: lib/block_scout_web/templates/address_decompiled_contract/index.html.eex:27
msgid "There is no decompilded contracts for this address."
msgstr ""

@ -3,8 +3,8 @@ defmodule BlockScoutWeb.BlockControllerTest do
alias Explorer.Chain.Block
setup do
Supervisor.terminate_child(Explorer.Supervisor, ConCache)
Supervisor.restart_child(Explorer.Supervisor, ConCache)
Supervisor.terminate_child(Explorer.Supervisor, {ConCache, :blocks})
Supervisor.restart_child(Explorer.Supervisor, {ConCache, :blocks})
:ok
end

@ -9,8 +9,8 @@ defmodule BlockScoutWeb.ChainControllerTest do
alias Explorer.Counters.AddressesWithBalanceCounter
setup do
Supervisor.terminate_child(Explorer.Supervisor, ConCache)
Supervisor.restart_child(Explorer.Supervisor, ConCache)
Supervisor.terminate_child(Explorer.Supervisor, {ConCache, :blocks})
Supervisor.restart_child(Explorer.Supervisor, {ConCache, :blocks})
start_supervised!(AddressesWithBalanceCounter)
AddressesWithBalanceCounter.consolidate()

@ -37,15 +37,6 @@ defmodule BlockScoutWeb.PendingTransactionControllerTest do
refute hd(json_response(conn, 200)["items"]) =~ to_string(dropped_replaced.hash)
end
test "returns a count of pending transactions", %{conn: conn} do
insert(:transaction)
conn = get(conn, pending_transaction_path(BlockScoutWeb.Endpoint, :index))
assert html_response(conn, 200)
assert 1 == conn.assigns.pending_transaction_count
end
test "works when there are no transactions", %{conn: conn} do
conn = get(conn, pending_transaction_path(conn, :index))

@ -10,8 +10,8 @@ defmodule BlockScoutWeb.ViewingChainTest do
alias Explorer.Counters.AddressesWithBalanceCounter
setup do
Supervisor.terminate_child(Explorer.Supervisor, ConCache)
Supervisor.restart_child(Explorer.Supervisor, ConCache)
Supervisor.terminate_child(Explorer.Supervisor, {ConCache, :blocks})
Supervisor.restart_child(Explorer.Supervisor, {ConCache, :blocks})
Enum.map(401..404, &insert(:block, number: &1))

@ -96,15 +96,15 @@ defmodule BlockScoutWeb.AddressDecompiledContractViewTest do
end
end
describe "sort_contracts_by_version/1" do
test "sorts contracts in lexicographical order" do
describe "last_decompiled_contract_version/1" do
test "returns last version" do
contract2 = insert(:decompiled_smart_contract, decompiler_version: "v2")
contract1 = insert(:decompiled_smart_contract, decompiler_version: "v1")
contract3 = insert(:decompiled_smart_contract, decompiler_version: "v3")
result = AddressDecompiledContractView.sort_contracts_by_version([contract2, contract1, contract3])
result = AddressDecompiledContractView.last_decompiled_contract_version([contract2, contract1, contract3])
assert result == [contract3, contract2, contract1]
assert result == contract3
end
end
end

@ -249,6 +249,19 @@ defmodule EthereumJSONRPC do
|> fetch_blocks_by_params(&Block.ByNephew.request/1, json_rpc_named_arguments)
end
@spec fetch_net_version(json_rpc_named_arguments) :: {:ok, non_neg_integer()} | {:error, reason :: term}
def fetch_net_version(json_rpc_named_arguments) do
result =
%{id: 0, method: "net_version", params: []}
|> request()
|> json_rpc(json_rpc_named_arguments)
case result do
{:ok, bin_number} -> {:ok, String.to_integer(bin_number)}
other -> other
end
end
@doc """
Fetches block number by `t:tag/0`.

@ -886,6 +886,24 @@ defmodule EthereumJSONRPCTest do
end
end
describe "fetch_net_version/1" do
test "fetches net version", %{json_rpc_named_arguments: json_rpc_named_arguments} do
expected_version =
case Keyword.fetch!(json_rpc_named_arguments, :variant) do
EthereumJSONRPC.Parity -> 77
_variant -> 1
end
if json_rpc_named_arguments[:transport] == EthereumJSONRPC.Mox do
expect(EthereumJSONRPC.Mox, :json_rpc, fn _json, _options ->
{:ok, "#{expected_version}"}
end)
end
assert {:ok, ^expected_version} = EthereumJSONRPC.fetch_net_version(json_rpc_named_arguments)
end
end
defp clear_mailbox do
receive do
_ -> clear_mailbox()

@ -80,7 +80,8 @@ if System.get_env("SOURCE_MODULE") == "TransactionAndLog" do
end
config :explorer,
solc_bin_api_url: "https://solc-bin.ethereum.org"
solc_bin_api_url: "https://solc-bin.ethereum.org",
checksum_function: System.get_env("CHECKSUM_FUNCTION") && String.to_atom(System.get_env("CHECKSUM_FUNCTION"))
config :logger, :explorer,
# keep synced with `config/config.exs`

@ -6,7 +6,7 @@ defmodule Explorer.Application do
use Application
alias Explorer.Admin
alias Explorer.Chain.{BlockCountCache, BlockNumberCache, BlocksCache, TransactionCountCache}
alias Explorer.Chain.{BlockCountCache, BlockNumberCache, BlocksCache, NetVersionCache, TransactionCountCache}
alias Explorer.Repo.PrometheusLogger
@impl Application
@ -31,7 +31,8 @@ defmodule Explorer.Application do
{Admin.Recovery, [[], [name: Admin.Recovery]]},
{TransactionCountCache, [[], []]},
{BlockCountCache, []},
{ConCache, [name: BlocksCache.cache_name(), ttl_check_interval: false]}
con_cache_child_spec(BlocksCache.cache_name()),
con_cache_child_spec(NetVersionCache.cache_name())
]
children = base_children ++ configurable_children()
@ -79,4 +80,17 @@ defmodule Explorer.Application do
http: HTTPoison
]
end
defp con_cache_child_spec(name) do
Supervisor.child_spec(
{
ConCache,
[
name: name,
ttl_check_interval: false
]
},
id: {ConCache, name}
)
end
end

@ -227,60 +227,31 @@ defmodule Explorer.Chain do
transaction_hashes_from_token_transfers =
TokenTransfer.where_any_address_fields_match(direction, address_hash, paging_options)
token_transfers_query =
transaction_hashes_from_token_transfers
|> Transaction.where_transaction_hashes_match()
|> join_associations(necessity_by_association)
|> order_by([transaction], desc: transaction.block_number, desc: transaction.index)
|> Transaction.preload_token_transfers(address_hash)
base_query =
transactions_list =
paging_options
|> fetch_transactions()
|> Transaction.where_transaction_matches(transaction_hashes_from_token_transfers, direction, address_hash)
|> join_associations(necessity_by_association)
|> Transaction.preload_token_transfers(address_hash)
|> Repo.all()
from_address_query =
base_query
|> where([t], t.from_address_hash == ^address_hash)
to_address_query =
base_query
|> where([t], t.to_address_hash == ^address_hash)
created_contract_query =
base_query
|> where([t], t.created_contract_address_hash == ^address_hash)
queries =
[token_transfers_query] ++
case direction do
:from -> [from_address_query]
:to -> [to_address_query, created_contract_query]
_ -> [from_address_query, to_address_query, created_contract_query]
if Application.get_env(:block_scout_web, BlockScoutWeb.Chain)[:has_emission_funds] do
address_hash
|> Reward.fetch_emission_rewards_tuples(paging_options)
|> Enum.concat(transactions_list)
|> Enum.sort_by(fn item ->
case item do
{%Reward{} = emission_reward, _} ->
{-emission_reward.block.number, 1}
item ->
{-item.block_number, -item.index}
end
rewards_list =
if Application.get_env(:block_scout_web, BlockScoutWeb.Chain)[:has_emission_funds] do
Reward.fetch_emission_rewards_tuples(address_hash, paging_options)
else
[]
end
queries
|> Stream.flat_map(&Repo.all/1)
|> Stream.uniq_by(& &1.hash)
|> Stream.concat(rewards_list)
|> Enum.sort_by(fn item ->
case item do
{%Reward{} = emission_reward, _} ->
{-emission_reward.block.number, 1}
item ->
{-item.block_number, -item.index}
end
end)
|> Enum.take(paging_options.page_size)
end)
|> Enum.take(paging_options.page_size)
else
transactions_list
end
end
@spec address_to_logs(Address.t(), Keyword.t()) :: [
@ -703,25 +674,32 @@ defmodule Explorer.Chain do
iex> Explorer.Chain.hash_to_address(hash)
{:error, :not_found}
Optionally accepts:
- a list of bindings to preload, just like `Ecto.Query.preload/3`
- a boolean to also fetch the `has_decompiled_code?` virtual field or not
"""
@spec hash_to_address(Hash.Address.t()) :: {:ok, Address.t()} | {:error, :not_found}
def hash_to_address(%Hash{byte_count: unquote(Hash.Address.byte_count())} = hash) do
query =
from(
address in Address,
preload: [
@spec hash_to_address(Hash.Address.t(), [Macro.t()], boolean()) :: {:ok, Address.t()} | {:error, :not_found}
def hash_to_address(
%Hash{byte_count: unquote(Hash.Address.byte_count())} = hash,
preloads \\ [
:contracts_creation_internal_transaction,
:names,
:smart_contract,
:token,
:contracts_creation_transaction
],
query_decompiled_code_flag \\ true
) do
query =
from(
address in Address,
preload: ^preloads,
where: address.hash == ^hash
)
query_with_decompiled_flag = with_decompiled_code_flag(query, hash)
query_with_decompiled_flag
query
|> with_decompiled_code_flag(hash, query_decompiled_code_flag)
|> Repo.one()
|> case do
nil -> {:error, :not_found}
@ -1987,7 +1965,6 @@ defmodule Explorer.Chain do
|> page_pending_transaction(paging_options)
|> limit(^paging_options.page_size)
|> pending_transactions_query()
|> where([transaction], is_nil(transaction.error) or transaction.error != "dropped/replaced")
|> order_by([transaction], desc: transaction.inserted_at, desc: transaction.hash)
|> join_associations(necessity_by_association)
|> preload([{:token_transfers, [:token, :from_address, :to_address]}])
@ -1996,7 +1973,7 @@ defmodule Explorer.Chain do
defp pending_transactions_query(query) do
from(transaction in query,
where: is_nil(transaction.block_hash)
where: is_nil(transaction.block_hash) and (is_nil(transaction.error) or transaction.error != "dropped/replaced")
)
end
@ -3161,7 +3138,11 @@ defmodule Explorer.Chain do
defp staking_pool_filter(query, _), do: query
defp with_decompiled_code_flag(query, hash) do
defp with_decompiled_code_flag(query, hash, use_option \\ true)
defp with_decompiled_code_flag(query, _hash, false), do: query
defp with_decompiled_code_flag(query, hash, true) do
has_decompiled_code_query =
from(decompiled_contract in DecompiledSmartContract,
where: decompiled_contract.address_hash == ^hash,

@ -16,6 +16,7 @@ defmodule Explorer.Chain.Address do
DecompiledSmartContract,
Hash,
InternalTransaction,
NetVersionCache,
SmartContract,
Token,
Transaction,
@ -130,6 +131,21 @@ defmodule Explorer.Chain.Address do
end
def checksum(hash, iodata?) do
checksum_formatted =
case Application.get_env(:explorer, :checksum_function) || :eth do
:eth -> eth_checksum(hash)
:rsk -> rsk_checksum(hash)
end
if iodata? do
["0x" | checksum_formatted]
else
to_string(["0x" | checksum_formatted])
end
end
# https://github.com/rsksmart/RSKIPs/blob/master/IPs/RSKIP60.md
def eth_checksum(hash) do
string_hash =
hash
|> to_string()
@ -137,26 +153,46 @@ defmodule Explorer.Chain.Address do
match_byte_stream = stream_every_four_bytes_of_sha256(string_hash)
checksum_formatted =
string_hash
|> stream_binary()
|> Stream.zip(match_byte_stream)
|> Enum.map(fn
{digit, _} when digit in '0123456789' ->
digit
string_hash
|> stream_binary()
|> Stream.zip(match_byte_stream)
|> Enum.map(fn
{digit, _} when digit in '0123456789' ->
digit
{alpha, 1} ->
alpha - 32
{alpha, 1} ->
alpha - 32
{alpha, _} ->
alpha
end)
{alpha, _} ->
alpha
end)
end
if iodata? do
["0x" | checksum_formatted]
else
to_string(["0x" | checksum_formatted])
end
def rsk_checksum(hash) do
chain_id = NetVersionCache.version()
string_hash =
hash
|> to_string()
|> String.trim_leading("0x")
prefix = "#{chain_id}0x"
match_byte_stream = stream_every_four_bytes_of_sha256("#{prefix}#{string_hash}")
string_hash
|> stream_binary()
|> Stream.zip(match_byte_stream)
|> Enum.map(fn
{digit, _} when digit in '0123456789' ->
digit
{alpha, 1} ->
alpha - 32
{alpha, _} ->
alpha
end)
end
defp stream_every_four_bytes_of_sha256(value) do

@ -0,0 +1,44 @@
defmodule Explorer.Chain.NetVersionCache do
@moduledoc """
Caches chain version.
"""
@cache_name :net_version
@key :version
@spec version() :: non_neg_integer() | {:error, any()}
def version do
cached_value = fetch_from_cache()
if is_nil(cached_value) do
fetch_from_node()
else
cached_value
end
end
def cache_name do
@cache_name
end
defp fetch_from_cache do
ConCache.get(@cache_name, @key)
end
defp cache_value(value) do
ConCache.put(@cache_name, @key, value)
end
defp fetch_from_node do
json_rpc_named_arguments = Application.get_env(:explorer, :json_rpc_named_arguments)
case EthereumJSONRPC.fetch_net_version(json_rpc_named_arguments) do
{:ok, value} ->
cache_value(value)
value
other ->
other
end
end
end

@ -5,7 +5,7 @@ defmodule Explorer.Chain.Transaction do
require Logger
import Ecto.Query, only: [from: 2, order_by: 3, preload: 3, subquery: 1, where: 3]
import Ecto.Query, only: [from: 2, preload: 3, subquery: 1, where: 3]
alias ABI.FunctionSelector
@ -549,15 +549,40 @@ defmodule Explorer.Chain.Transaction do
end
@doc """
Builds a query that will check for transactions within the hashes params.
Modifies a query to filter for transactions whose hash is in a list or that are
linked to the given address_hash through a direction.
Be careful to not pass a large list, because this will lead to performance
problems.
"""
def where_transaction_hashes_match(transaction_hashes) do
Transaction
|> where([t], t.hash == fragment("ANY (?)", ^transaction_hashes))
|> order_by([transaction], desc: transaction.block_number, desc: transaction.index)
def where_transaction_matches(query, transaction_hashes, :from, address_hash) do
where(
query,
[t],
t.hash in ^transaction_hashes or
t.from_address_hash == ^address_hash
)
end
def where_transaction_matches(query, transaction_hashes, :to, address_hash) do
where(
query,
[t],
t.hash in ^transaction_hashes or
t.to_address_hash == ^address_hash or
t.created_contract_address_hash == ^address_hash
)
end
def where_transaction_matches(query, transaction_hashes, _direction, address_hash) do
where(
query,
[t],
t.hash in ^transaction_hashes or
t.from_address_hash == ^address_hash or
t.to_address_hash == ^address_hash or
t.created_contract_address_hash == ^address_hash
)
end
@collated_fields ~w(block_number cumulative_gas_used gas_used index)a

@ -0,0 +1,7 @@
defmodule Explorer.Repo.Migrations.AddTxHashInsertedAtIndex do
use Ecto.Migration
def change do
create(index(:transactions, [:hash, :inserted_at]))
end
end

@ -1,6 +1,8 @@
defmodule Explorer.Chain.AddressTest do
use Explorer.DataCase
import Mox
alias Explorer.Chain.Address
alias Explorer.Repo
@ -28,6 +30,12 @@ defmodule Explorer.Chain.AddressTest do
end
describe "Phoenix.HTML.Safe.to_iodata/1" do
setup do
Application.put_env(:explorer, :checksum_function, :eth)
:ok
end
defp str(value) do
to_string(insert(:address, hash: value))
end
@ -39,5 +47,18 @@ defmodule Explorer.Chain.AddressTest do
assert str("0xdbf03b407c01e7cd3cbea99509d93f8dddc8c6fb") == "0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB"
assert str("0xd1220a0cf47c7b9be7a2e6ba89f429762e7b9adb") == "0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb"
end
test "returns the checksum rsk formatted address" do
expect(EthereumJSONRPC.Mox, :json_rpc, fn _json, _options ->
{:ok, "30"}
end)
Application.put_env(:explorer, :checksum_function, :rsk)
assert str("0x5aaeb6053f3e94c9b9a09f33669435e7ef1beaed") == "0x5aaEB6053f3e94c9b9a09f33669435E7ef1bEAeD"
assert str("0xfb6916095ca1df60bb79ce92ce3ea74c37c5d359") == "0xFb6916095cA1Df60bb79ce92cE3EA74c37c5d359"
assert str("0xdbf03b407c01e7cd3cbea99509d93f8dddc8c6fb") == "0xDBF03B407c01E7CD3cBea99509D93F8Dddc8C6FB"
assert str("0xd1220a0cf47c7b9be7a2e6ba89f429762e7b9adb") == "0xD1220A0Cf47c7B9BE7a2e6ba89F429762E7B9adB"
end
end
end

@ -5,8 +5,8 @@ defmodule Explorer.Chain.BlocksCacheTest do
alias Explorer.Repo
setup do
Supervisor.terminate_child(Explorer.Supervisor, ConCache)
Supervisor.restart_child(Explorer.Supervisor, ConCache)
Supervisor.terminate_child(Explorer.Supervisor, {ConCache, :blocks})
Supervisor.restart_child(Explorer.Supervisor, {ConCache, :blocks})
:ok
end

@ -40,8 +40,8 @@ defmodule Explorer.DataCase do
end
Explorer.Chain.BlockNumberCache.setup()
Supervisor.terminate_child(Explorer.Supervisor, ConCache)
Supervisor.restart_child(Explorer.Supervisor, ConCache)
Supervisor.terminate_child(Explorer.Supervisor, {ConCache, :blocks})
Supervisor.restart_child(Explorer.Supervisor, {ConCache, :blocks})
:ok
end

Loading…
Cancel
Save