fix: Multiple json rpc urls fixes (#11264)

pull/11279/head
Qwerty5Uiop 1 week ago committed by GitHub
parent a6e2ac88a6
commit 4124d621f5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 26
      apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/http.ex
  2. 25
      apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/utility/common_helper.ex
  3. 2
      apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/utility/endpoint_availability_checker.ex
  4. 4
      apps/ethereum_jsonrpc/test/ethereum_jsonrpc/http/mox_test.exs
  5. 52
      apps/ethereum_jsonrpc/test/ethereum_jsonrpc/utility/common_helper_test.exs
  6. 2
      apps/ethereum_jsonrpc/test/support/ethereum_jsonrpc/case/geth/http_websocket.ex
  7. 2
      apps/ethereum_jsonrpc/test/support/ethereum_jsonrpc/case/nethermind/http_websocket.ex
  8. 2
      apps/ethereum_jsonrpc/test/support/ethereum_jsonrpc/http/case.ex
  9. 17
      apps/explorer/lib/explorer/chain/bridged_token.ex
  10. 3
      apps/explorer/lib/explorer/smart_contract/stylus/verifier.ex
  11. 2
      apps/indexer/lib/indexer/block/catchup/bound_interval_supervisor.ex

@ -240,35 +240,13 @@ defmodule EthereumJSONRPC.HTTP do
with {:ok, method_to_url} <- Keyword.fetch(options, :method_to_url),
{:ok, method_atom} <- to_existing_atom(method),
{:ok, url_type} <- Keyword.fetch(method_to_url, method_atom) do
fallback_urls = CommonHelper.url_type_to_urls(url_type, options, :fallback)
url =
url_type
|> CommonHelper.url_type_to_urls(options)
|> EndpointAvailabilityObserver.maybe_replace_urls(fallback_urls, url_type)
|> select_single_url()
{url_type, url}
{url_type, CommonHelper.get_available_url(options, url_type)}
else
_ ->
url_type = :http
url =
url_type
|> CommonHelper.url_type_to_urls(options)
|> EndpointAvailabilityObserver.maybe_replace_urls(options[:fallback_urls], url_type)
|> select_single_url()
{url_type, url}
{:http, CommonHelper.get_available_url(options, :http)}
end
end
defp select_single_url([]), do: nil
defp select_single_url(urls) do
Enum.random(urls)
end
defp to_existing_atom(string) do
{:ok, String.to_existing_atom(string)}
rescue

@ -3,6 +3,8 @@ defmodule EthereumJSONRPC.Utility.CommonHelper do
Common helper functions
"""
alias EthereumJSONRPC.Utility.EndpointAvailabilityObserver
# converts duration like "5s", "2m", "1h5m" to milliseconds
@duration_regex ~r/(\d+)([smhSMH]?)/
def parse_duration(duration) do
@ -30,6 +32,23 @@ defmodule EthereumJSONRPC.Utility.CommonHelper do
Keyword.put(keyword || [], nearest_path, put_in_keyword_nested(keyword[nearest_path], rest_path, value))
end
@doc """
Get available json rpc url from `json_rpc_transport_options` (or global `json_rpc_named_arguments`) of `url_type` type
based on `EthereumJSONRPC.Utility.EndpointAvailabilityObserver`.
"""
@spec get_available_url(Keyword.t() | nil, atom()) :: String.t() | nil
def get_available_url(json_rpc_transport_options \\ nil, url_type \\ :http) do
transport_options =
json_rpc_transport_options || Application.get_env(:explorer, :json_rpc_named_arguments)[:transport_options]
fallback_urls = url_type_to_urls(url_type, transport_options, :fallback)
url_type
|> url_type_to_urls(transport_options)
|> EndpointAvailabilityObserver.maybe_replace_urls(fallback_urls, url_type)
|> select_single_url()
end
@doc """
Extracts urls corresponding to `url_type` from json rpc transport options
"""
@ -41,6 +60,12 @@ defmodule EthereumJSONRPC.Utility.CommonHelper do
json_rpc_transport_options[urls_key]
end
defp select_single_url([]), do: nil
defp select_single_url(urls) do
Enum.random(urls)
end
defp convert_to_ms(number, "s"), do: :timer.seconds(number)
defp convert_to_ms(number, "m"), do: :timer.minutes(number)
defp convert_to_ms(number, "h"), do: :timer.hours(number)

@ -38,7 +38,7 @@ defmodule EthereumJSONRPC.Utility.EndpointAvailabilityChecker do
Enum.reduce(unavailable_endpoints_arguments, [], fn {json_rpc_named_arguments, url_type}, acc ->
case fetch_latest_block_number(json_rpc_named_arguments) do
{:ok, _number} ->
url = json_rpc_named_arguments[:transport_options][:url]
[url] = json_rpc_named_arguments[:transport_options][:urls]
EndpointAvailabilityObserver.enable_endpoint(url, url_type, json_rpc_named_arguments)
acc

@ -16,7 +16,7 @@ defmodule EthereumJSONRPC.HTTP.MoxTest do
transport: EthereumJSONRPC.HTTP,
transport_options: [
http: EthereumJSONRPC.HTTP.Mox,
url: url(),
urls: [url()],
http_options: http_options()
],
# Which one does not matter, so pick one
@ -289,7 +289,7 @@ defmodule EthereumJSONRPC.HTTP.MoxTest do
transport_options = Keyword.fetch!(json_rpc_named_arguments, :transport_options)
http = Keyword.fetch!(transport_options, :http)
url = Keyword.fetch!(transport_options, :url)
url = transport_options |> Keyword.fetch!(:urls) |> List.first()
json = Jason.encode_to_iodata!(payload)
http_options = Keyword.fetch!(transport_options, :http_options)

@ -0,0 +1,52 @@
defmodule EthereumJSONRPC.Utility.CommonHelperTest do
use ExUnit.Case, async: true
alias EthereumJSONRPC.Utility.{EndpointAvailabilityObserver, CommonHelper}
@options [
urls: ["url_1", "url_2"],
trace_urls: ["trace_url_1", "trace_url_2"],
eth_call_urls: ["eth_call_url_1", "eth_call_url_2"],
fallback_urls: ["fallback_url_1", "fallback_url_2"],
fallback_trace_urls: ["fallback_trace_url_1", "fallback_trace_url_2"],
fallback_eth_call_urls: ["fallback_ec_url_1", "fallback_ec_url_2"]
]
test "url_type_to_urls/3" do
assert ["url_1", "url_2"] = CommonHelper.url_type_to_urls(:http, @options)
assert ["trace_url_1", "trace_url_2"] = CommonHelper.url_type_to_urls(:trace, @options)
assert ["eth_call_url_1", "eth_call_url_2"] = CommonHelper.url_type_to_urls(:eth_call, @options)
assert ["fallback_url_1", "fallback_url_2"] = CommonHelper.url_type_to_urls(:http, @options, :fallback)
assert ["fallback_trace_url_1", "fallback_trace_url_2"] = CommonHelper.url_type_to_urls(:trace, @options, :fallback)
assert ["fallback_ec_url_1", "fallback_ec_url_2"] = CommonHelper.url_type_to_urls(:eth_call, @options, :fallback)
end
test "get_available_url/2" do
EndpointAvailabilityObserver.start_link([])
assert CommonHelper.get_available_url(@options, :http) in @options[:urls]
assert CommonHelper.get_available_url(@options, :trace) in @options[:trace_urls]
assert CommonHelper.get_available_url(@options, :eth_call) in @options[:eth_call_urls]
set_url_unavailable("url_1", :http)
set_url_unavailable("url_2", :http)
assert CommonHelper.get_available_url(@options, :http) in @options[:fallback_urls]
set_url_unavailable("trace_url_1", :trace)
set_url_unavailable("trace_url_2", :trace)
assert CommonHelper.get_available_url(@options, :trace) in @options[:fallback_trace_urls]
set_url_unavailable("eth_call_url_1", :eth_call)
set_url_unavailable("eth_call_url_2", :eth_call)
assert CommonHelper.get_available_url(@options, :eth_call) in @options[:fallback_eth_call_urls]
end
defp set_url_unavailable(url, url_type) do
Enum.each(1..3, fn _ ->
EndpointAvailabilityObserver.inc_error_count(url, [transport_options: @options], url_type)
end)
end
end

@ -12,7 +12,7 @@ defmodule EthereumJSONRPC.Case.Geth.HTTPWebSocket do
transport_options: [
http: EthereumJSONRPC.HTTP.HTTPoison,
http_options: [recv_timeout: 60_000, timeout: 60_000, hackney: [pool: :ethereum_jsonrpc]],
url: "https://mainnet.infura.io/8lTvJTKmHPCHazkneJsY"
urls: ["https://mainnet.infura.io/8lTvJTKmHPCHazkneJsY"]
],
variant: EthereumJSONRPC.Geth
)

@ -12,7 +12,7 @@ defmodule EthereumJSONRPC.Case.Nethermind.HTTPWebSocket do
transport_options: [
http: EthereumJSONRPC.HTTP.HTTPoison,
http_options: [recv_timeout: 60_000, timeout: 60_000, hackney: [pool: :ethereum_jsonrpc]],
url: "http://3.85.253.242:8545"
urls: ["http://3.85.253.242:8545"]
],
variant: EthereumJSONRPC.Nethermind
)

@ -9,7 +9,7 @@ defmodule EthereumJSONRPC.HTTP.Case do
transport: EthereumJSONRPC.HTTP,
transport_options: [
http: http(),
url: url(),
urls: [url()],
http_options: http_options()
]
]

@ -828,13 +828,18 @@ defmodule Explorer.Chain.BridgedToken do
end
defp update_transport_options_set_foreign_json_rpc(transport_options, foreign_json_rpc) do
Keyword.get_and_update(transport_options, :method_to_url, fn method_to_url ->
{_, updated_method_to_url} =
Keyword.get_and_update(method_to_url, :eth_call, fn eth_call ->
{eth_call, foreign_json_rpc}
end)
{_, updated_transport_options} =
Keyword.get_and_update(transport_options, :method_to_url, fn method_to_url ->
{_, updated_method_to_url} =
Keyword.get_and_update(method_to_url, :eth_call, fn eth_call ->
{eth_call, :eth_call}
end)
{method_to_url, updated_method_to_url}
end)
{method_to_url, updated_method_to_url}
Keyword.get_and_update(updated_transport_options, :eth_call_urls, fn eth_call_urls ->
{eth_call_urls, [foreign_json_rpc]}
end)
end

@ -9,6 +9,7 @@ defmodule Explorer.SmartContract.Stylus.Verifier do
- Compares the resulting bytecode against the deployed contract bytecode
- Returns verification details including ABI and contract metadata
"""
alias EthereumJSONRPC.Utility.CommonHelper
alias Explorer.Chain.{Hash, SmartContract}
alias Explorer.SmartContract.StylusVerifierInterface
@ -68,7 +69,7 @@ defmodule Explorer.SmartContract.Stylus.Verifier do
{:ok, map()} | {:error, any()}
defp evaluate_authenticity_inner(true, address_hash, params) do
transaction_hash = fetch_data_for_stylus_verification(address_hash)
rpc_endpoint = Application.get_env(:explorer, :json_rpc_named_arguments)[:transport_options][:urls] |> List.first()
rpc_endpoint = CommonHelper.get_available_url()
params
|> Map.take(["cargo_stylus_version", "repository_url", "commit", "path_prefix"])

@ -311,7 +311,7 @@ defmodule Indexer.Block.Catchup.BoundIntervalSupervisor do
} = state
) do
Logger.error(fn ->
"Catchup index stream exited because the archive node endpoint at #{Keyword.get(options, :url)} is unavailable. Restarting"
"Catchup index stream exited because the archive node endpoint at #{Keyword.get(options, :urls)} is unavailable. Restarting"
end)
send(self(), :catchup_index)

Loading…
Cancel
Save