diff --git a/CHANGELOG.md b/CHANGELOG.md index f77cb5439a..2caacb6bae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ - [#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 ### Chore diff --git a/apps/block_scout_web/test/block_scout_web/controllers/block_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/block_controller_test.exs index 9dea0841f9..e8c4af7de8 100644 --- a/apps/block_scout_web/test/block_scout_web/controllers/block_controller_test.exs +++ b/apps/block_scout_web/test/block_scout_web/controllers/block_controller_test.exs @@ -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 diff --git a/apps/block_scout_web/test/block_scout_web/controllers/chain_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/chain_controller_test.exs index 701a991c55..f902f15ad4 100644 --- a/apps/block_scout_web/test/block_scout_web/controllers/chain_controller_test.exs +++ b/apps/block_scout_web/test/block_scout_web/controllers/chain_controller_test.exs @@ -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() diff --git a/apps/block_scout_web/test/block_scout_web/features/viewing_chain_test.exs b/apps/block_scout_web/test/block_scout_web/features/viewing_chain_test.exs index 1add7ed9d5..a32e4f5da3 100644 --- a/apps/block_scout_web/test/block_scout_web/features/viewing_chain_test.exs +++ b/apps/block_scout_web/test/block_scout_web/features/viewing_chain_test.exs @@ -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)) diff --git a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc.ex b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc.ex index 24fc593d85..71994da56c 100644 --- a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc.ex +++ b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc.ex @@ -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`. diff --git a/apps/ethereum_jsonrpc/test/ethereum_jsonrpc_test.exs b/apps/ethereum_jsonrpc/test/ethereum_jsonrpc_test.exs index 5f82b6a43f..32e1a6f324 100644 --- a/apps/ethereum_jsonrpc/test/ethereum_jsonrpc_test.exs +++ b/apps/ethereum_jsonrpc/test/ethereum_jsonrpc_test.exs @@ -886,6 +886,18 @@ defmodule EthereumJSONRPCTest do end end + describe "fetch_net_version/1" do + test "fetches net version", %{json_rpc_named_arguments: json_rpc_named_arguments} do + if json_rpc_named_arguments[:transport] == EthereumJSONRPC.Mox do + expect(EthereumJSONRPC.Mox, :json_rpc, fn _json, _options -> + {:ok, "1"} + end) + end + + assert {:ok, 1} = EthereumJSONRPC.fetch_net_version(json_rpc_named_arguments) + end + end + defp clear_mailbox do receive do _ -> clear_mailbox() diff --git a/apps/explorer/config/config.exs b/apps/explorer/config/config.exs index 94a1d79c6d..9a7d9f4296 100644 --- a/apps/explorer/config/config.exs +++ b/apps/explorer/config/config.exs @@ -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` diff --git a/apps/explorer/lib/explorer/application.ex b/apps/explorer/lib/explorer/application.ex index 984695b3b4..98a71c7bac 100644 --- a/apps/explorer/lib/explorer/application.ex +++ b/apps/explorer/lib/explorer/application.ex @@ -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 diff --git a/apps/explorer/lib/explorer/chain/address.ex b/apps/explorer/lib/explorer/chain/address.ex index a619d70546..28b67f1d66 100644 --- a/apps/explorer/lib/explorer/chain/address.ex +++ b/apps/explorer/lib/explorer/chain/address.ex @@ -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 diff --git a/apps/explorer/lib/explorer/chain/net_version_cache.ex b/apps/explorer/lib/explorer/chain/net_version_cache.ex new file mode 100644 index 0000000000..c3df467e0c --- /dev/null +++ b/apps/explorer/lib/explorer/chain/net_version_cache.ex @@ -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 diff --git a/apps/explorer/test/explorer/chain/address_test.exs b/apps/explorer/test/explorer/chain/address_test.exs index 22710e88bb..213913c766 100644 --- a/apps/explorer/test/explorer/chain/address_test.exs +++ b/apps/explorer/test/explorer/chain/address_test.exs @@ -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 diff --git a/apps/explorer/test/explorer/chain/blocks_cache_test.exs b/apps/explorer/test/explorer/chain/blocks_cache_test.exs index f030502dc3..687d2ff30a 100644 --- a/apps/explorer/test/explorer/chain/blocks_cache_test.exs +++ b/apps/explorer/test/explorer/chain/blocks_cache_test.exs @@ -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 diff --git a/apps/explorer/test/support/data_case.ex b/apps/explorer/test/support/data_case.ex index ebaf91cf3d..1386a55d36 100644 --- a/apps/explorer/test/support/data_case.ex +++ b/apps/explorer/test/support/data_case.ex @@ -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