From b4376e027c022e4be7943dbb363f3e88401dac32 Mon Sep 17 00:00:00 2001 From: saneery Date: Wed, 12 Jun 2019 15:18:36 +0300 Subject: [PATCH 01/16] filter pending logs --- .../lib/ethereum_jsonrpc/receipts.ex | 4 +++- .../test/indexer/block/fetcher/receipts_test.exs | 16 +++++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/receipts.ex b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/receipts.ex index e5d706589c..896cd14e1a 100644 --- a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/receipts.ex +++ b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/receipts.ex @@ -61,7 +61,9 @@ defmodule EthereumJSONRPC.Receipts do """ @spec elixir_to_logs(elixir) :: Logs.elixir() def elixir_to_logs(elixir) when is_list(elixir) do - Enum.flat_map(elixir, &Receipt.elixir_to_logs/1) + elixir + |> Enum.flat_map(&Receipt.elixir_to_logs/1) + |> Enum.filter(& Map.get(&1, "type") != "pending") end @doc """ diff --git a/apps/indexer/test/indexer/block/fetcher/receipts_test.exs b/apps/indexer/test/indexer/block/fetcher/receipts_test.exs index 95570db4a2..61e37df06d 100644 --- a/apps/indexer/test/indexer/block/fetcher/receipts_test.exs +++ b/apps/indexer/test/indexer/block/fetcher/receipts_test.exs @@ -84,7 +84,19 @@ defmodule Indexer.Block.Fetcher.ReceiptsTest do "transactionIndex" => "0x0", "transactionLogIndex" => "0x0", "type" => "mined" - } + }, + %{ + "address" => "0x8bf38d4764929064f2d4d3a56520a76ab3df415c", + "blockHash" => "0xf6b4b8c88df3ebd252ec476328334dc026cf66606a84fb769b3d3cbccc8471bd", + "blockNumber" => "0x25", + "data" => "0x000000000000000000000000862d67cb0773ee3f8ce7ea89b328ffea861ab3ef", + "logIndex" => "0x1", + "topics" => ["0x600bcf04a13e752d1e3670a5a9f1c21177ca2a93c6f5391d4f1298d098097c22"], + "transactionHash" => "0x53bd884872de3e488692881baeec262e7b95234d3965248c39fe992fffd433e5", + "transactionIndex" => "0x0", + "transactionLogIndex" => "0x0", + "type" => "pending" + } ], "logsBloom" => "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000200000000000000000000020000000000000000200000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", @@ -146,6 +158,8 @@ defmodule Indexer.Block.Fetcher.ReceiptsTest do log[:transaction_hash] == "0x43bd884872de3e488692881baeec262e7b95234d3965248c39fe992fffd433e5" && log[:block_number] == 46147 end) + + refute Enum.find(logs, fn log -> log[:type] == "pending" end) end end end From 0af99b88145112fa385d5638e5c7e1a1c86e82f1 Mon Sep 17 00:00:00 2001 From: saneery Date: Wed, 12 Jun 2019 15:38:19 +0300 Subject: [PATCH 02/16] format --- apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/receipts.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/receipts.ex b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/receipts.ex index 896cd14e1a..7028423f7a 100644 --- a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/receipts.ex +++ b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/receipts.ex @@ -63,7 +63,7 @@ defmodule EthereumJSONRPC.Receipts do def elixir_to_logs(elixir) when is_list(elixir) do elixir |> Enum.flat_map(&Receipt.elixir_to_logs/1) - |> Enum.filter(& Map.get(&1, "type") != "pending") + |> Enum.filter(&(Map.get(&1, "type") != "pending")) end @doc """ From 489396e2db1800aaaffd20b755d3d4e19ba245e1 Mon Sep 17 00:00:00 2001 From: saneery Date: Wed, 12 Jun 2019 15:39:05 +0300 Subject: [PATCH 03/16] add changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a1c4814ac3..363175e9a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,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 +- [#2148](https://github.com/poanetwork/blockscout/pull/2148) - filter pending logs ### Chore - [#2127](https://github.com/poanetwork/blockscout/pull/2127) - use previouse chromedriver version From 741d0005bd8b29f8b8d3d371abd72467da76e743 Mon Sep 17 00:00:00 2001 From: saneery Date: Wed, 12 Jun 2019 15:52:47 +0300 Subject: [PATCH 04/16] mix format --- .../indexer/block/fetcher/receipts_test.exs | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/apps/indexer/test/indexer/block/fetcher/receipts_test.exs b/apps/indexer/test/indexer/block/fetcher/receipts_test.exs index 61e37df06d..03b481b960 100644 --- a/apps/indexer/test/indexer/block/fetcher/receipts_test.exs +++ b/apps/indexer/test/indexer/block/fetcher/receipts_test.exs @@ -86,17 +86,17 @@ defmodule Indexer.Block.Fetcher.ReceiptsTest do "type" => "mined" }, %{ - "address" => "0x8bf38d4764929064f2d4d3a56520a76ab3df415c", - "blockHash" => "0xf6b4b8c88df3ebd252ec476328334dc026cf66606a84fb769b3d3cbccc8471bd", - "blockNumber" => "0x25", - "data" => "0x000000000000000000000000862d67cb0773ee3f8ce7ea89b328ffea861ab3ef", - "logIndex" => "0x1", - "topics" => ["0x600bcf04a13e752d1e3670a5a9f1c21177ca2a93c6f5391d4f1298d098097c22"], - "transactionHash" => "0x53bd884872de3e488692881baeec262e7b95234d3965248c39fe992fffd433e5", - "transactionIndex" => "0x0", - "transactionLogIndex" => "0x0", - "type" => "pending" - } + "address" => "0x8bf38d4764929064f2d4d3a56520a76ab3df415c", + "blockHash" => "0xf6b4b8c88df3ebd252ec476328334dc026cf66606a84fb769b3d3cbccc8471bd", + "blockNumber" => "0x25", + "data" => "0x000000000000000000000000862d67cb0773ee3f8ce7ea89b328ffea861ab3ef", + "logIndex" => "0x1", + "topics" => ["0x600bcf04a13e752d1e3670a5a9f1c21177ca2a93c6f5391d4f1298d098097c22"], + "transactionHash" => "0x53bd884872de3e488692881baeec262e7b95234d3965248c39fe992fffd433e5", + "transactionIndex" => "0x0", + "transactionLogIndex" => "0x0", + "type" => "pending" + } ], "logsBloom" => "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000200000000000000000000020000000000000000200000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", From 2aec1f4c9fd4187e54bac63dfc443f2a93665192 Mon Sep 17 00:00:00 2001 From: pasqu4le Date: Fri, 14 Jun 2019 17:57:30 +0200 Subject: [PATCH 05/16] Removes duplicate entries from Indexer.Fetcher.UncleBlock --- CHANGELOG.md | 1 + .../lib/indexer/fetcher/uncle_block.ex | 10 ++++--- .../test/indexer/fetcher/uncle_block_test.exs | 30 +++++++++++++++++++ 3 files changed, 37 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f77cb5439a..39596363b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ - [#2119](https://github.com/poanetwork/blockscout/pull/2119) - fix map logging - [#2130](https://github.com/poanetwork/blockscout/pull/2130) - fix navigation - [#2149](https://github.com/poanetwork/blockscout/pull/2149) - remove pending transaction count +- [#2177](https://github.com/poanetwork/blockscout/pull/2177) - remove duplicate entries from UncleBlock's Fetcher ### Chore - [#2127](https://github.com/poanetwork/blockscout/pull/2127) - use previouse chromedriver version diff --git a/apps/indexer/lib/indexer/fetcher/uncle_block.ex b/apps/indexer/lib/indexer/fetcher/uncle_block.ex index 213604a73e..e9300d1e39 100644 --- a/apps/indexer/lib/indexer/fetcher/uncle_block.ex +++ b/apps/indexer/lib/indexer/fetcher/uncle_block.ex @@ -71,17 +71,19 @@ defmodule Indexer.Fetcher.UncleBlock do @impl BufferedTask @decorate trace(name: "fetch", resource: "Indexer.Fetcher.UncleBlock.run/2", service: :indexer, tracer: Tracer) def run(entries, %Block.Fetcher{json_rpc_named_arguments: json_rpc_named_arguments} = block_fetcher) do - entry_count = Enum.count(entries) + unique_entries = Enum.uniq(entries) + + entry_count = Enum.count(unique_entries) Logger.metadata(count: entry_count) Logger.debug("fetching") - entries + unique_entries |> Enum.map(&entry_to_params/1) |> EthereumJSONRPC.fetch_uncle_blocks(json_rpc_named_arguments) |> case do {:ok, blocks} -> - run_blocks(blocks, block_fetcher, entries) + run_blocks(blocks, block_fetcher, unique_entries) {:error, reason} -> Logger.error( @@ -91,7 +93,7 @@ defmodule Indexer.Fetcher.UncleBlock do error_count: entry_count ) - {:retry, entries} + {:retry, unique_entries} end end diff --git a/apps/indexer/test/indexer/fetcher/uncle_block_test.exs b/apps/indexer/test/indexer/fetcher/uncle_block_test.exs index f3350b8de7..93a11b0b64 100644 --- a/apps/indexer/test/indexer/fetcher/uncle_block_test.exs +++ b/apps/indexer/test/indexer/fetcher/uncle_block_test.exs @@ -169,6 +169,36 @@ defmodule Indexer.Fetcher.UncleBlockTest do assert {:retry, ^entries} = UncleBlock.run(entries, %Block.Fetcher{json_rpc_named_arguments: json_rpc_named_arguments}) end + + test "retries only unique uncles on failed request", %{json_rpc_named_arguments: json_rpc_named_arguments} do + %Hash{bytes: block_hash_bytes} = block_hash() + entry = {block_hash_bytes, 0} + entries = [entry, entry] + + EthereumJSONRPC.Mox + |> expect(:json_rpc, fn [ + %{ + id: id, + method: "eth_getUncleByBlockHashAndIndex" + } + ], + _ -> + {:ok, + [ + %{ + id: id, + error: %{ + code: 404, + data: %{index: 0, nephew_hash: "0xa0814f0478fe90c82852f812fd74c96df148654c326d2600d836e6908ebb62b4"}, + message: "Not Found" + } + } + ]} + end) + + assert {:retry, [entry]} = + UncleBlock.run(entries, %Block.Fetcher{json_rpc_named_arguments: json_rpc_named_arguments}) + end end describe "run_blocks/2" do From 2551fd5f6855acaefde46f9576701f18d8712a83 Mon Sep 17 00:00:00 2001 From: zachdaniel Date: Tue, 11 Jun 2019 15:47:46 -0400 Subject: [PATCH 06/16] feat: add eth_getLogs rpc endpoint --- CHANGELOG.md | 1 + .../controllers/api/rpc/eth_controller.ex | 268 ++++++++++++++-- .../api/rpc/eth_controller_test.exs | 286 ++++++++++++++++++ apps/explorer/lib/explorer/chain.ex | 26 ++ apps/explorer/lib/explorer/etherscan/logs.ex | 41 ++- 5 files changed, 593 insertions(+), 29 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f77cb5439a..5ab0be411d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - [#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 +- [#2146](https://github.com/poanetwork/blockscout/pull/2146) - feat: add eth_getLogs rpc endpoint ### Fixes - [#2162](https://github.com/poanetwork/blockscout/pull/2162) - contract creation tile color changed diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/eth_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/eth_controller.ex index 693772ed8c..9446aad1f7 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/eth_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/eth_controller.ex @@ -1,8 +1,33 @@ defmodule BlockScoutWeb.API.RPC.EthController do use BlockScoutWeb, :controller - alias Explorer.Chain - alias Explorer.Chain.Wei + alias Ecto.Type, as: EctoType + alias Explorer.{Chain, Repo} + alias Explorer.Chain.{Block, Data, Hash, Hash.Address, Wei} + alias Explorer.Etherscan.Logs + + @methods %{ + "eth_getBalance" => %{ + action: :eth_get_balance, + notes: """ + the `earliest` parameter will not work as expected currently, because genesis block balances + are not currently imported + """ + }, + "eth_getLogs" => %{ + action: :eth_get_logs, + notes: """ + Will never return more than 1000 log entries. + """ + } + } + + @index_to_word %{ + 0 => "first", + 1 => "second", + 2 => "third", + 3 => "fourth" + } def eth_request(%{body_params: %{"_json" => requests}} = conn, _) when is_list(requests) do responses = responses(requests) @@ -39,6 +64,138 @@ defmodule BlockScoutWeb.API.RPC.EthController do |> render("response.json", %{response: response}) end + def eth_get_balance(address_param, block_param \\ nil) do + with {:address, {:ok, address}} <- {:address, Chain.string_to_address_hash(address_param)}, + {:block, {:ok, block}} <- {:block, block_param(block_param)}, + {:balance, {:ok, balance}} <- {:balance, Chain.get_balance_as_of_block(address, block)} do + {:ok, Wei.hex_format(balance)} + else + {:address, :error} -> + {:error, "Query parameter 'address' is invalid"} + + {:block, :error} -> + {:error, "Query parameter 'block' is invalid"} + + {:balance, {:error, :not_found}} -> + {:error, "Balance not found"} + end + end + + def eth_get_logs(filter_options) do + with {:ok, address_or_topic_params} <- address_or_topic_params(filter_options), + {:ok, from_block_param, to_block_param} <- logs_blocks_filter(filter_options), + {:ok, from_block} <- cast_block(from_block_param), + {:ok, to_block} <- cast_block(to_block_param) do + filter = + address_or_topic_params + |> Map.put(:from_block, from_block) + |> Map.put(:to_block, to_block) + |> Map.put(:allow_non_consensus, true) + + {:ok, filter |> Logs.list_logs() |> Enum.map(&render_log/1)} + else + {:error, message} when is_bitstring(message) -> + {:error, message} + + {:error, :empty} -> + {:ok, []} + + _ -> + {:error, "Something went wrong."} + end + end + + defp render_log(log) do + topics = Enum.reject([log.first_topic, log.second_topic, log.third_topic, log.fourth_topic], &is_nil/1) + + %{ + "address" => to_string(log.address_hash), + "blockHash" => to_string(log.block_hash), + "blockNumber" => Integer.to_string(log.block_number, 16), + "data" => to_string(log.data), + "logIndex" => Integer.to_string(log.index, 16), + "removed" => log.block_consensus == false, + "topics" => topics, + "transactionHash" => to_string(log.transaction_hash), + "transactionIndex" => log.transaction_index, + "transactionLogIndex" => log.index, + "type" => "mined" + } + end + + defp cast_block("0x" <> hexadecimal_digits = input) do + case Integer.parse(hexadecimal_digits, 16) do + {integer, ""} -> {:ok, integer} + _ -> {:error, input <> " is not a valid block number"} + end + end + + defp cast_block(integer) when is_integer(integer), do: {:ok, integer} + defp cast_block(_), do: {:error, "invalid block number"} + + defp address_or_topic_params(filter_options) do + address_param = Map.get(filter_options, "address") + topics_param = Map.get(filter_options, "topics") + + with {:ok, address} <- validate_address(address_param), + {:ok, topics} <- validate_topics(topics_param) do + address_and_topics(address, topics) + end + end + + defp address_and_topics(nil, nil), do: {:error, "Must supply one of address and topics"} + defp address_and_topics(address, nil), do: {:ok, %{address_hash: address}} + defp address_and_topics(nil, topics), do: {:ok, topics} + defp address_and_topics(address, topics), do: {:ok, Map.put(topics, :address_hash, address)} + + defp validate_address(nil), do: {:ok, nil} + + defp validate_address(address) do + case Address.cast(address) do + {:ok, address} -> {:ok, address} + :error -> {:error, "invalid address"} + end + end + + defp validate_topics(nil), do: {:ok, nil} + defp validate_topics([]), do: [] + + defp validate_topics(topics) when is_list(topics) do + topics + |> Stream.with_index() + |> Enum.reduce({:ok, %{}}, fn {topic, index}, {:ok, acc} -> + case cast_topics(topic) do + {:ok, data} -> + with_filter = Map.put(acc, String.to_existing_atom("#{@index_to_word[index]}_topic"), data) + + {:ok, add_operator(with_filter, index)} + + :error -> + {:error, "invalid topics"} + end + end) + end + + defp add_operator(filters, 0), do: filters + + defp add_operator(filters, index) do + Map.put(filters, String.to_existing_atom("topic#{index - 1}_#{index}_opr"), "and") + end + + defp cast_topics(topics) when is_list(topics) do + case EctoType.cast({:array, Data}, topics) do + {:ok, data} -> {:ok, Enum.map(data, &to_string/1)} + :error -> :error + end + end + + defp cast_topics(topic) do + case Data.cast(topic) do + {:ok, data} -> {:ok, to_string(data)} + :error -> :error + end + end + defp responses(requests) do Enum.map(requests, fn request -> with {:id, {:ok, id}} <- {:id, Map.fetch(request, "id")}, @@ -51,6 +208,85 @@ defmodule BlockScoutWeb.API.RPC.EthController do end) end + defp logs_blocks_filter(filter_options) do + with {:filter, %{"blockHash" => block_hash_param}} <- {:filter, filter_options}, + {:block_hash, {:ok, block_hash}} <- {:block_hash, Hash.Full.cast(block_hash_param)}, + {:block, %{number: number}} <- {:block, Repo.get(Block, block_hash)} do + {:ok, number, number} + else + {:filter, filters} -> + from_block = Map.get(filters, "fromBlock", "latest") + to_block = Map.get(filters, "toBlock", "latest") + + max_block_number = + if from_block == "latest" || to_block == "latest" do + max_consensus_block_number() + end + + pending_block_number = + if from_block == "pending" || to_block == "pending" do + max_non_consensus_block_number(max_block_number) + end + + if is_nil(pending_block_number) && from_block == "pending" && to_block == "pending" do + {:error, :empty} + else + to_block_numbers(from_block, to_block, max_block_number, pending_block_number) + end + + {:block, _} -> + {:error, "Invalid Block Hash"} + + {:block_hash, _} -> + {:error, "Invalid Block Hash"} + end + end + + defp to_block_numbers(from_block, to_block, max_block_number, pending_block_number) do + actual_pending_block_number = pending_block_number || max_block_number + + with {:ok, from} <- to_block_number(from_block, max_block_number, actual_pending_block_number), + {:ok, to} <- to_block_number(to_block, max_block_number, actual_pending_block_number) do + {:ok, from, to} + end + end + + defp to_block_number(integer, _, _) when is_integer(integer), do: {:ok, integer} + defp to_block_number("latest", max_block_number, _), do: {:ok, max_block_number || 0} + defp to_block_number("earliest", _, _), do: {:ok, 0} + defp to_block_number("pending", max_block_number, nil), do: {:ok, max_block_number || 0} + defp to_block_number("pending", _, pending), do: {:ok, pending} + + defp to_block_number("0x" <> number, _, _) do + case Integer.parse(number, 16) do + {integer, ""} -> {:ok, integer} + _ -> {:error, "invalid block number"} + end + end + + defp to_block_number(number, _, _) when is_bitstring(number) do + case Integer.parse(number, 16) do + {integer, ""} -> {:ok, integer} + _ -> {:error, "invalid block number"} + end + end + + defp to_block_number(_, _, _), do: {:error, "invalid block number"} + + defp max_non_consensus_block_number(max) do + case Chain.max_non_consensus_block_number(max) do + {:ok, number} -> number + _ -> nil + end + end + + defp max_consensus_block_number do + case Chain.max_consensus_block_number() do + {:ok, number} -> number + _ -> nil + end + end + defp format_success(result, id) do %{result: result, id: id} end @@ -66,9 +302,13 @@ defmodule BlockScoutWeb.API.RPC.EthController do defp do_eth_request(%{"jsonrpc" => "2.0", "method" => method, "params" => params}) when is_list(params) do with {:ok, action} <- get_action(method), - true <- :erlang.function_exported(__MODULE__, action, Enum.count(params)) do + {:correct_arity, true} <- + {:correct_arity, :erlang.function_exported(__MODULE__, action, Enum.count(params))} do apply(__MODULE__, action, params) else + {:correct_arity, _} -> + {:error, "Incorrect number of params."} + _ -> {:error, "Action not found."} end @@ -82,26 +322,16 @@ defmodule BlockScoutWeb.API.RPC.EthController do {:error, "Method, params, and jsonrpc, are all required parameters."} end - def eth_get_balance(address_param, block_param \\ nil) do - with {:address, {:ok, address}} <- {:address, Chain.string_to_address_hash(address_param)}, - {:block, {:ok, block}} <- {:block, block_param(block_param)}, - {:balance, {:ok, balance}} <- {:balance, Chain.get_balance_as_of_block(address, block)} do - {:ok, Wei.hex_format(balance)} - else - {:address, :error} -> - {:error, "Query parameter 'address' is invalid"} - - {:block, :error} -> - {:error, "Query parameter 'block' is invalid"} + defp get_action(action) do + case Map.get(@methods, action) do + %{action: action} -> + {:ok, action} - {:balance, {:error, :not_found}} -> - {:error, "Balance not found"} + _ -> + :error end end - defp get_action("eth_getBalance"), do: {:ok, :eth_get_balance} - defp get_action(_), do: :error - defp block_param("latest"), do: {:ok, :latest} defp block_param("earliest"), do: {:ok, :earliest} defp block_param("pending"), do: {:ok, :pending} diff --git a/apps/block_scout_web/test/block_scout_web/controllers/api/rpc/eth_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/api/rpc/eth_controller_test.exs index b26becee2f..1b9273c66c 100644 --- a/apps/block_scout_web/test/block_scout_web/controllers/api/rpc/eth_controller_test.exs +++ b/apps/block_scout_web/test/block_scout_web/controllers/api/rpc/eth_controller_test.exs @@ -2,6 +2,7 @@ defmodule BlockScoutWeb.API.RPC.EthControllerTest do use BlockScoutWeb.ConnCase, async: false alias Explorer.Counters.{AddressesWithBalanceCounter, AverageBlockTime} + alias Explorer.Repo alias Indexer.Fetcher.CoinBalanceOnDemand setup do @@ -26,6 +27,291 @@ defmodule BlockScoutWeb.API.RPC.EthControllerTest do defp params(api_params, params), do: Map.put(api_params, "params", params) + describe "eth_get_logs" do + setup do + %{ + api_params: %{ + "method" => "eth_getLogs", + "jsonrpc" => "2.0", + "id" => 0 + } + } + end + + test "with an invalid address", %{conn: conn, api_params: api_params} do + assert response = + conn + |> post("/api/eth_rpc", params(api_params, [%{"address" => "badhash"}])) + |> json_response(200) + + assert %{"error" => "invalid address"} = response + end + + test "address with no logs", %{conn: conn, api_params: api_params} do + insert(:block) + address = insert(:address) + + assert response = + conn + |> post("/api/eth_rpc", params(api_params, [%{"address" => to_string(address.hash)}])) + |> json_response(200) + + assert %{"result" => []} = response + end + + test "address but no logs and no toBlock provided", %{conn: conn, api_params: api_params} do + address = insert(:address) + + assert response = + conn + |> post("/api/eth_rpc", params(api_params, [%{"address" => to_string(address.hash)}])) + |> json_response(200) + + assert %{"result" => []} = response + end + + test "with a matching address", %{conn: conn, api_params: api_params} do + address = insert(:address) + + block = insert(:block, number: 0) + + transaction = insert(:transaction, from_address: address) |> with_block(block) + insert(:log, address: address, transaction: transaction, data: "0x010101") + + params = params(api_params, [%{"address" => to_string(address.hash)}]) + + assert response = + conn + |> post("/api/eth_rpc", params) + |> json_response(200) + + assert %{"result" => [%{"data" => "0x010101"}]} = response + end + + test "with a matching address and matching topic", %{conn: conn, api_params: api_params} do + address = insert(:address) + + block = insert(:block, number: 0) + + transaction = insert(:transaction, from_address: address) |> with_block(block) + insert(:log, address: address, transaction: transaction, data: "0x010101", first_topic: "0x01") + + params = params(api_params, [%{"address" => to_string(address.hash), "topics" => ["0x01"]}]) + + assert response = + conn + |> post("/api/eth_rpc", params) + |> json_response(200) + + assert %{"result" => [%{"data" => "0x010101"}]} = response + end + + test "with a matching address and multiple topic matches", %{conn: conn, api_params: api_params} do + address = insert(:address) + + block = insert(:block, number: 0) + + transaction = insert(:transaction, from_address: address) |> with_block(block) + insert(:log, address: address, transaction: transaction, data: "0x010101", first_topic: "0x01") + insert(:log, address: address, transaction: transaction, data: "0x020202", first_topic: "0x00") + + params = params(api_params, [%{"address" => to_string(address.hash), "topics" => [["0x01", "0x00"]]}]) + + assert response = + conn + |> post("/api/eth_rpc", params) + |> json_response(200) + + assert [%{"data" => "0x010101"}, %{"data" => "0x020202"}] = Enum.sort_by(response["result"], &Map.get(&1, "data")) + end + + test "with a matching address and multiple topic matches in different positions", %{ + conn: conn, + api_params: api_params + } do + address = insert(:address) + + block = insert(:block, number: 0) + + transaction = insert(:transaction, from_address: address) |> with_block(block) + + insert(:log, + address: address, + transaction: transaction, + data: "0x010101", + first_topic: "0x01", + second_topic: "0x02" + ) + + insert(:log, address: address, transaction: transaction, data: "0x020202", first_topic: "0x01") + + params = params(api_params, [%{"address" => to_string(address.hash), "topics" => ["0x01", "0x02"]}]) + + assert response = + conn + |> post("/api/eth_rpc", params) + |> json_response(200) + + assert [%{"data" => "0x010101"}] = response["result"] + end + + test "with a matching address and multiple topic matches in different positions and multiple matches in the second position", + %{conn: conn, api_params: api_params} do + address = insert(:address) + + block = insert(:block, number: 0) + + transaction = insert(:transaction, from_address: address) |> with_block(block) + + insert(:log, + address: address, + transaction: transaction, + data: "0x010101", + first_topic: "0x01", + second_topic: "0x02" + ) + + insert(:log, + address: address, + transaction: transaction, + data: "0x020202", + first_topic: "0x01", + second_topic: "0x03" + ) + + params = params(api_params, [%{"address" => to_string(address.hash), "topics" => ["0x01", ["0x02", "0x03"]]}]) + + assert response = + conn + |> post("/api/eth_rpc", params) + |> json_response(200) + + assert [%{"data" => "0x010101"}, %{"data" => "0x020202"}] = Enum.sort_by(response["result"], &Map.get(&1, "data")) + end + + test "with a block range filter", + %{conn: conn, api_params: api_params} do + address = insert(:address) + + block1 = insert(:block, number: 0) + block2 = insert(:block, number: 1) + block3 = insert(:block, number: 2) + block4 = insert(:block, number: 3) + + transaction1 = insert(:transaction, from_address: address) |> with_block(block1) + transaction2 = insert(:transaction, from_address: address) |> with_block(block2) + transaction3 = insert(:transaction, from_address: address) |> with_block(block3) + transaction4 = insert(:transaction, from_address: address) |> with_block(block4) + + insert(:log, address: address, transaction: transaction1, data: "0x010101") + + insert(:log, address: address, transaction: transaction2, data: "0x020202") + + insert(:log, address: address, transaction: transaction3, data: "0x030303") + + insert(:log, address: address, transaction: transaction4, data: "0x040404") + + params = params(api_params, [%{"address" => to_string(address.hash), "fromBlock" => 1, "toBlock" => 2}]) + + assert response = + conn + |> post("/api/eth_rpc", params) + |> json_response(200) + + assert [%{"data" => "0x020202"}, %{"data" => "0x030303"}] = Enum.sort_by(response["result"], &Map.get(&1, "data")) + end + + test "with a block hash filter", + %{conn: conn, api_params: api_params} do + address = insert(:address) + + block1 = insert(:block, number: 0) + block2 = insert(:block, number: 1) + block3 = insert(:block, number: 2) + + transaction1 = insert(:transaction, from_address: address) |> with_block(block1) + transaction2 = insert(:transaction, from_address: address) |> with_block(block2) + transaction3 = insert(:transaction, from_address: address) |> with_block(block3) + + insert(:log, address: address, transaction: transaction1, data: "0x010101") + + insert(:log, address: address, transaction: transaction2, data: "0x020202") + + insert(:log, address: address, transaction: transaction3, data: "0x030303") + + params = params(api_params, [%{"address" => to_string(address.hash), "blockHash" => to_string(block2.hash)}]) + + assert response = + conn + |> post("/api/eth_rpc", params) + |> json_response(200) + + assert [%{"data" => "0x020202"}] = response["result"] + end + + test "with an earliest block filter", + %{conn: conn, api_params: api_params} do + address = insert(:address) + + block1 = insert(:block, number: 0) + block2 = insert(:block, number: 1) + block3 = insert(:block, number: 2) + + transaction1 = insert(:transaction, from_address: address) |> with_block(block1) + transaction2 = insert(:transaction, from_address: address) |> with_block(block2) + transaction3 = insert(:transaction, from_address: address) |> with_block(block3) + + insert(:log, address: address, transaction: transaction1, data: "0x010101") + + insert(:log, address: address, transaction: transaction2, data: "0x020202") + + insert(:log, address: address, transaction: transaction3, data: "0x030303") + + params = + params(api_params, [%{"address" => to_string(address.hash), "fromBlock" => "earliest", "toBlock" => "earliest"}]) + + assert response = + conn + |> post("/api/eth_rpc", params) + |> json_response(200) + + assert [%{"data" => "0x010101"}] = response["result"] + end + + test "with a pending block filter", + %{conn: conn, api_params: api_params} do + address = insert(:address) + + block1 = insert(:block, number: 0) + block2 = insert(:block, number: 1) + block3 = insert(:block, number: 2) + + transaction1 = insert(:transaction, from_address: address) |> with_block(block1) + transaction2 = insert(:transaction, from_address: address) |> with_block(block2) + transaction3 = insert(:transaction, from_address: address) |> with_block(block3) + + insert(:log, address: address, transaction: transaction1, data: "0x010101") + + insert(:log, address: address, transaction: transaction2, data: "0x020202") + + insert(:log, address: address, transaction: transaction3, data: "0x030303") + + changeset = Ecto.Changeset.change(block3, %{consensus: false}) + + Repo.update!(changeset) + + params = + params(api_params, [%{"address" => to_string(address.hash), "fromBlock" => "pending", "toBlock" => "pending"}]) + + assert response = + conn + |> post("/api/eth_rpc", params) + |> json_response(200) + + assert [%{"data" => "0x030303"}] = response["result"] + end + end + describe "eth_get_balance" do setup do %{ diff --git a/apps/explorer/lib/explorer/chain.ex b/apps/explorer/lib/explorer/chain.ex index 9c203ad3e4..3a891be485 100644 --- a/apps/explorer/lib/explorer/chain.ex +++ b/apps/explorer/lib/explorer/chain.ex @@ -1700,6 +1700,32 @@ defmodule Explorer.Chain do end end + @spec max_non_consensus_block_number(integer | nil) :: {:ok, Block.block_number()} | {:error, :not_found} + def max_non_consensus_block_number(max_consensus_block_number \\ nil) do + max = + if max_consensus_block_number do + {:ok, max_consensus_block_number} + else + max_consensus_block_number() + end + + case max do + {:ok, number} -> + query = + from(block in Block, + where: block.consensus == false, + where: block.number > ^number + ) + + query + |> Repo.aggregate(:max, :number) + |> case do + nil -> {:error, :not_found} + number -> {:ok, number} + end + end + end + @doc """ The height of the chain. diff --git a/apps/explorer/lib/explorer/etherscan/logs.ex b/apps/explorer/lib/explorer/etherscan/logs.ex index 124199be72..9e9d70ae02 100644 --- a/apps/explorer/lib/explorer/etherscan/logs.ex +++ b/apps/explorer/lib/explorer/etherscan/logs.ex @@ -34,7 +34,8 @@ defmodule Explorer.Etherscan.Logs do :fourth_topic, :index, :address_hash, - :transaction_hash + :transaction_hash, + :type ] @doc """ @@ -114,16 +115,26 @@ defmodule Explorer.Etherscan.Logs do from(log_transaction_data in subquery(all_transaction_logs_query), join: block in Block, on: block.number == log_transaction_data.block_number, - where: block.consensus == true, where: log_transaction_data.address_hash == ^address_hash, order_by: block.number, limit: 1000, select_merge: %{ - block_timestamp: block.timestamp + block_timestamp: block.timestamp, + block_consensus: block.consensus, + block_hash: block.hash } ) - Repo.all(query_with_blocks) + query_with_consensus = + if Map.get(filter, :allow_non_consensus) do + query_with_blocks + else + from([_, block] in query_with_blocks, + where: block.consensus == true + ) + end + + Repo.all(query_with_consensus) end # Since address_hash was not present, we know that a @@ -140,20 +151,30 @@ defmodule Explorer.Etherscan.Logs do join: block in assoc(transaction, :block), where: block.number >= ^prepared_filter.from_block, where: block.number <= ^prepared_filter.to_block, - where: block.consensus == true, select: %{ transaction_hash: transaction.hash, gas_price: transaction.gas_price, gas_used: transaction.gas_used, transaction_index: transaction.index, + block_hash: block.hash, block_number: block.number, - block_timestamp: block.timestamp + block_timestamp: block.timestamp, + block_consensus: block.consensus } ) + query_with_consensus = + if Map.get(filter, :allow_non_consensus) do + block_transaction_query + else + from([_, block] in block_transaction_query, + where: block.consensus == true + ) + end + query_with_block_transaction_data = from(log in logs_query, - join: block_transaction_data in subquery(block_transaction_query), + join: block_transaction_data in subquery(query_with_consensus), on: block_transaction_data.transaction_hash == log.transaction_hash, order_by: block_transaction_data.block_number, limit: 1000, @@ -186,7 +207,7 @@ defmodule Explorer.Etherscan.Logs do query [topic] -> - where(query, [l], field(l, ^topic) == ^filter[topic]) + where(query, [l], field(l, ^topic) in ^List.wrap(filter[topic])) _ -> where_multiple_topics_match(query, filter) @@ -201,12 +222,12 @@ defmodule Explorer.Etherscan.Logs do defp where_multiple_topics_match(query, filter, topic_operation, "and") do {topic_a, topic_b} = @topic_operations[topic_operation] - where(query, [l], field(l, ^topic_a) == ^filter[topic_a] and field(l, ^topic_b) == ^filter[topic_b]) + where(query, [l], field(l, ^topic_a) == ^filter[topic_a] and field(l, ^topic_b) in ^List.wrap(filter[topic_b])) end defp where_multiple_topics_match(query, filter, topic_operation, "or") do {topic_a, topic_b} = @topic_operations[topic_operation] - where(query, [l], field(l, ^topic_a) == ^filter[topic_a] or field(l, ^topic_b) == ^filter[topic_b]) + where(query, [l], field(l, ^topic_a) == ^filter[topic_a] or field(l, ^topic_b) in ^List.wrap(filter[topic_b])) end defp where_multiple_topics_match(query, _, _, _), do: query From 50794d8a4357f1d2cf652956de835d71053ea84e Mon Sep 17 00:00:00 2001 From: saneery Date: Tue, 18 Jun 2019 08:39:09 +0300 Subject: [PATCH 07/16] fix test --- apps/indexer/test/indexer/block/fetcher/receipts_test.exs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/indexer/test/indexer/block/fetcher/receipts_test.exs b/apps/indexer/test/indexer/block/fetcher/receipts_test.exs index 03b481b960..35371b7c4a 100644 --- a/apps/indexer/test/indexer/block/fetcher/receipts_test.exs +++ b/apps/indexer/test/indexer/block/fetcher/receipts_test.exs @@ -87,8 +87,8 @@ defmodule Indexer.Block.Fetcher.ReceiptsTest do }, %{ "address" => "0x8bf38d4764929064f2d4d3a56520a76ab3df415c", - "blockHash" => "0xf6b4b8c88df3ebd252ec476328334dc026cf66606a84fb769b3d3cbccc8471bd", - "blockNumber" => "0x25", + "blockHash" => nil, + "blockNumber" => nil, "data" => "0x000000000000000000000000862d67cb0773ee3f8ce7ea89b328ffea861ab3ef", "logIndex" => "0x1", "topics" => ["0x600bcf04a13e752d1e3670a5a9f1c21177ca2a93c6f5391d4f1298d098097c22"], From 2f627354b7b8d21494958432efabeb4a56cc67e7 Mon Sep 17 00:00:00 2001 From: Andrew Gross Date: Tue, 18 Jun 2019 13:28:11 -0600 Subject: [PATCH 08/16] Added additional chains, wobserver info --- docs/metrics.md | 12 +++++++++++- docs/projects.md | 2 ++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/docs/metrics.md b/docs/metrics.md index de8a77bb00..dd8ea62886 100644 --- a/docs/metrics.md +++ b/docs/metrics.md @@ -2,16 +2,24 @@ ## Metrics -BlockScout is setup to export [Prometheus](https://prometheus.io/) metrics at `/metrics`. +### Wobserver + +[Wobserver](https://github.com/shinyscorpion/wobserver) is configured to display data from the `/metrics` endpoint in a web interface. To view, go to `/wobserver` for the chain you would like to view. + +For example `https://blockscout.com/eth/mainnet/wobserver` ### Prometheus +BlockScout is setup to export [Prometheus](https://prometheus.io/) metrics at `/metrics`. + 1. Install prometheus: `brew install prometheus` 2. Start the web server `iex -S mix phx.server` 3. Start prometheus: `prometheus --config.file=prometheus.yml` ### Grafana +The Grafana dashboard may also be used for metrics display. + 1. Install grafana: `brew install grafana` 2. Install Pie Chart panel plugin: `grafana-cli plugins install grafana-piechart-panel` 3. Start grafana: `brew services start grafana` @@ -28,3 +36,5 @@ BlockScout is setup to export [Prometheus](https://prometheus.io/) metrics at `/ 2. Copy the contents of the JSON file in the "Or paste JSON" entry 3. Click "Load" 6. View the dashboards. (You will need to click-around and use BlockScout for the web-related metrics to show up.) + + diff --git a/docs/projects.md b/docs/projects.md index ecb9a03308..49ace8c26b 100644 --- a/docs/projects.md +++ b/docs/projects.md @@ -13,6 +13,8 @@ | [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) | Current BlockScout versions for hosted projects are available [on the forum](https://forum.poa.network/t/deployed-instances-on-blockscout-com/1938). \ No newline at end of file From 0690851b80c1fc711d6822f485835a9763d47f78 Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Wed, 19 Jun 2019 11:15:15 +0300 Subject: [PATCH 09/16] increase request idle timeout --- apps/block_scout_web/config/config.exs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/apps/block_scout_web/config/config.exs b/apps/block_scout_web/config/config.exs index f38ed779b5..f310e5996e 100644 --- a/apps/block_scout_web/config/config.exs +++ b/apps/block_scout_web/config/config.exs @@ -35,6 +35,16 @@ config :block_scout_web, BlockScoutWeb.Counters.BlocksIndexedCounter, enabled: t # Configures the endpoint config :block_scout_web, BlockScoutWeb.Endpoint, instrumenters: [BlockScoutWeb.Prometheus.Instrumenter, SpandexPhoenix.Instrumenter], + http: [ + protocol_options: [ + idle_timeout: 90_000 + ] + ], + https: [ + protocol_options: [ + idle_timeout: 90_000 + ] + ], url: [ host: "localhost", path: System.get_env("NETWORK_PATH") || "/" From ea940de593257973f5122338fa84c13cd8ed49c8 Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Wed, 19 Jun 2019 11:23:23 +0300 Subject: [PATCH 10/16] fix config --- apps/block_scout_web/config/config.exs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/block_scout_web/config/config.exs b/apps/block_scout_web/config/config.exs index f310e5996e..9c59194f2a 100644 --- a/apps/block_scout_web/config/config.exs +++ b/apps/block_scout_web/config/config.exs @@ -43,7 +43,10 @@ config :block_scout_web, BlockScoutWeb.Endpoint, https: [ protocol_options: [ idle_timeout: 90_000 - ] + ], + cipher_suite: :strong, + certfile: System.get_env("CERTFILE") || "priv/cert/selfsigned.pem", + keyfile: System.get_env("KEYFILE") || "priv/cert/selfsigned_key.pem" ], url: [ host: "localhost", From 4b38147afe0f96792051ef8af6bb5c86e068a757 Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Wed, 19 Jun 2019 16:08:45 +0300 Subject: [PATCH 11/16] fix tests --- apps/block_scout_web/config/config.exs | 8 -------- apps/block_scout_web/config/dev.exs | 10 +++++++++- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/apps/block_scout_web/config/config.exs b/apps/block_scout_web/config/config.exs index 9c59194f2a..e601e299f8 100644 --- a/apps/block_scout_web/config/config.exs +++ b/apps/block_scout_web/config/config.exs @@ -40,14 +40,6 @@ config :block_scout_web, BlockScoutWeb.Endpoint, idle_timeout: 90_000 ] ], - https: [ - protocol_options: [ - idle_timeout: 90_000 - ], - cipher_suite: :strong, - certfile: System.get_env("CERTFILE") || "priv/cert/selfsigned.pem", - keyfile: System.get_env("KEYFILE") || "priv/cert/selfsigned_key.pem" - ], url: [ host: "localhost", path: System.get_env("NETWORK_PATH") || "/" diff --git a/apps/block_scout_web/config/dev.exs b/apps/block_scout_web/config/dev.exs index 27ce5aff40..ce955a764c 100644 --- a/apps/block_scout_web/config/dev.exs +++ b/apps/block_scout_web/config/dev.exs @@ -15,8 +15,16 @@ port = end config :block_scout_web, BlockScoutWeb.Endpoint, - http: [port: port || 4000], + http: [ + protocol_options: [ + idle_timeout: 90_000 + ], + port: port || 4000 + ], https: [ + protocol_options: [ + idle_timeout: 90_000 + ], port: (port && port + 1) || 4001, cipher_suite: :strong, certfile: System.get_env("CERTFILE") || "priv/cert/selfsigned.pem", From 0a5153a4ccaaefc5c24678fb50706b81449e71e9 Mon Sep 17 00:00:00 2001 From: maxgrapps <50101080+maxgrapps@users.noreply.github.com> Date: Thu, 20 Jun 2019 12:15:46 +0300 Subject: [PATCH 12/16] Update _footer.html.eex --- .../lib/block_scout_web/templates/layout/_footer.html.eex | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/block_scout_web/lib/block_scout_web/templates/layout/_footer.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/layout/_footer.html.eex index 1058654d49..7188f283a1 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/layout/_footer.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/layout/_footer.html.eex @@ -10,10 +10,10 @@ <% other_explorers = other_explorers() %> - <% col_size = if Enum.empty?(other_explorers), do: 3, else: 4 %> + <% col_size = if Enum.empty?(other_explorers), do: 3, else: 2 %>
-
+
<% end %>
- \ No newline at end of file + From 4f1e2fd28d3cd80e31e4806c890edaf761c962b0 Mon Sep 17 00:00:00 2001 From: maxgrapps <50101080+maxgrapps@users.noreply.github.com> Date: Thu, 20 Jun 2019 13:09:57 +0300 Subject: [PATCH 13/16] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ed9ca13594..48f4cf4e68 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - [#2151](https://github.com/poanetwork/blockscout/pull/2151) - hide dropdown menu then other networks list is empty ### Fixes +- [#2201](https://github.com/poanetwork/blockscout/pull/2201) - footer columns fix - [#2179](https://github.com/poanetwork/blockscout/pull/2179) - fix docker build error - [#2165](https://github.com/poanetwork/blockscout/pull/2165) - sort blocks by timestamp when calculating average block time - [#2175](https://github.com/poanetwork/blockscout/pull/2175) - fix coinmarketcap response errors From 4c394a3fc74ffbbe81f6eaa2446d0d868b9c8492 Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Thu, 20 Jun 2019 13:21:12 +0300 Subject: [PATCH 14/16] fix parity test --- apps/ethereum_jsonrpc/test/ethereum_jsonrpc_test.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/ethereum_jsonrpc/test/ethereum_jsonrpc_test.exs b/apps/ethereum_jsonrpc/test/ethereum_jsonrpc_test.exs index 3a6bb6f046..fb854601f5 100644 --- a/apps/ethereum_jsonrpc/test/ethereum_jsonrpc_test.exs +++ b/apps/ethereum_jsonrpc/test/ethereum_jsonrpc_test.exs @@ -57,7 +57,7 @@ defmodule EthereumJSONRPCTest do "invalid argument 0: json: cannot unmarshal hex string of odd length into Go value of type common.Address" EthereumJSONRPC.Parity -> - "Invalid params: invalid length 1, expected a 0x-prefixed, padded, hex-encoded hash with length 40." + "Invalid params: invalid length 1, expected a 0x-prefixed hex string with length of 40." _ -> raise ArgumentError, "Unsupported variant (#{variant}})" From 01176f25f32c78f5aaa6d5140d3988ad0b8dad9d Mon Sep 17 00:00:00 2001 From: maxgrapps Date: Thu, 20 Jun 2019 14:33:29 +0300 Subject: [PATCH 15/16] sokol and eth classic logo fix --- apps/block_scout_web/assets/css/theme/_sokol_variables.scss | 4 ++++ .../assets/static/images/classic_ethereum_logo.svg | 5 ++++- apps/block_scout_web/assets/static/images/sokol_logo.svg | 4 +++- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/apps/block_scout_web/assets/css/theme/_sokol_variables.scss b/apps/block_scout_web/assets/css/theme/_sokol_variables.scss index 71822bdc5a..5b704992e6 100644 --- a/apps/block_scout_web/assets/css/theme/_sokol_variables.scss +++ b/apps/block_scout_web/assets/css/theme/_sokol_variables.scss @@ -40,6 +40,10 @@ $dropdown-menu-item-hover-background: rgba($sub-accent-color, .1) !default; $header-icon-color-hover: $sub-accent-color; $header-icon-border-color-hover: $sub-accent-color; +// Logo size +$footer-logo-height: 20px; +$navbar-logo-height: 20px; + // buttons $btn-line-bg: #fff; // button bg $btn-line-color: $sub-accent-color; // button border and font color && hover bg color diff --git a/apps/block_scout_web/assets/static/images/classic_ethereum_logo.svg b/apps/block_scout_web/assets/static/images/classic_ethereum_logo.svg index 51ef19cc31..426ea29c82 100644 --- a/apps/block_scout_web/assets/static/images/classic_ethereum_logo.svg +++ b/apps/block_scout_web/assets/static/images/classic_ethereum_logo.svg @@ -1 +1,4 @@ - + + + + \ No newline at end of file diff --git a/apps/block_scout_web/assets/static/images/sokol_logo.svg b/apps/block_scout_web/assets/static/images/sokol_logo.svg index d57d1f08f0..6970589644 100644 --- a/apps/block_scout_web/assets/static/images/sokol_logo.svg +++ b/apps/block_scout_web/assets/static/images/sokol_logo.svg @@ -1 +1,3 @@ - + + + \ No newline at end of file From 1e90228e839e9b8a1017f2962edc3714a8fa8fab Mon Sep 17 00:00:00 2001 From: maxgrapps Date: Thu, 20 Jun 2019 14:35:41 +0300 Subject: [PATCH 16/16] eth classic and sokol logos fix --- apps/block_scout_web/assets/css/theme/_sokol_variables.scss | 2 +- .../assets/static/images/classic_ethereum_logo.svg | 2 +- apps/block_scout_web/assets/static/images/sokol_logo.svg | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/block_scout_web/assets/css/theme/_sokol_variables.scss b/apps/block_scout_web/assets/css/theme/_sokol_variables.scss index 5b704992e6..444cdff178 100644 --- a/apps/block_scout_web/assets/css/theme/_sokol_variables.scss +++ b/apps/block_scout_web/assets/css/theme/_sokol_variables.scss @@ -40,7 +40,7 @@ $dropdown-menu-item-hover-background: rgba($sub-accent-color, .1) !default; $header-icon-color-hover: $sub-accent-color; $header-icon-border-color-hover: $sub-accent-color; -// Logo size +// Logo Size $footer-logo-height: 20px; $navbar-logo-height: 20px; diff --git a/apps/block_scout_web/assets/static/images/classic_ethereum_logo.svg b/apps/block_scout_web/assets/static/images/classic_ethereum_logo.svg index 426ea29c82..83bf9ed4ee 100644 --- a/apps/block_scout_web/assets/static/images/classic_ethereum_logo.svg +++ b/apps/block_scout_web/assets/static/images/classic_ethereum_logo.svg @@ -1,4 +1,4 @@ - \ No newline at end of file + diff --git a/apps/block_scout_web/assets/static/images/sokol_logo.svg b/apps/block_scout_web/assets/static/images/sokol_logo.svg index 6970589644..adf2baac7d 100644 --- a/apps/block_scout_web/assets/static/images/sokol_logo.svg +++ b/apps/block_scout_web/assets/static/images/sokol_logo.svg @@ -1,3 +1,3 @@ - \ No newline at end of file +