Merge pull request #7532 from blockscout/handle-empty-id-in-json-rpc-response

Handle empty id in json rpc responses
pull/7541/head
Victor Baranov 2 years ago committed by GitHub
commit 3d7e425649
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      CHANGELOG.md
  2. 33
      apps/ethereum_jsonrpc/lib/ethereum_jsonrpc.ex
  3. 1
      apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/blocks.ex
  4. 1
      apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/fetched_balances.ex
  5. 1
      apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/fetched_beneficiaries.ex
  6. 1
      apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/fetched_codes.ex
  7. 1
      apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/geth.ex
  8. 11
      apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/http.ex
  9. 1
      apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/receipts.ex
  10. 2
      apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/trace_replay_block_transactions.ex
  11. 2
      apps/ethereum_jsonrpc/test/ethereum_jsonrpc_test.exs

@ -4,6 +4,8 @@
### Features
- [#7532](https://github.com/blockscout/blockscout/pull/7532) - Handle empty id in json rpc responses
### Fixes
- [#7516](https://github.com/blockscout/blockscout/pull/7516) - Fix shrinking logo in Safari

@ -25,6 +25,8 @@ defmodule EthereumJSONRPC do
documentation for `EthereumJSONRPC.RequestCoordinator`.
"""
require Logger
alias EthereumJSONRPC.{
Block,
Blocks,
@ -381,6 +383,29 @@ defmodule EthereumJSONRPC do
|> Enum.into(%{}, fn {params, id} -> {id, params} end)
end
@doc """
Assigns not matched ids between requests and responses to responses with incorrect ids
"""
def sanitize_responses(responses, id_to_params) do
responses
|> Enum.reduce(
{[], Map.keys(id_to_params) -- Enum.map(responses, & &1.id)},
fn
%{id: nil} = res, {result_res, [id | rest]} ->
Logger.error(
"Empty id in response: #{inspect(res)}, stacktrace: #{inspect(Process.info(self(), :current_stacktrace))}"
)
{[%{res | id: id} | result_res], rest}
res, {result_res, non_matched} ->
{[res | result_res], non_matched}
end
)
|> elem(0)
|> Enum.reverse()
end
@doc """
1. POSTs JSON `payload` to `url`
2. Decodes the response
@ -422,7 +447,7 @@ defmodule EthereumJSONRPC do
@doc """
Converts `t:quantity/0` to `t:non_neg_integer/0`.
"""
@spec quantity_to_integer(quantity) :: non_neg_integer() | :error
@spec quantity_to_integer(quantity) :: non_neg_integer() | nil
def quantity_to_integer("0x" <> hexadecimal_digits) do
String.to_integer(hexadecimal_digits, 16)
end
@ -432,10 +457,12 @@ defmodule EthereumJSONRPC do
def quantity_to_integer(string) when is_binary(string) do
case Integer.parse(string) do
{integer, ""} -> integer
_ -> :error
_ -> nil
end
end
def quantity_to_integer(_), do: nil
@doc """
Converts `t:non_neg_integer/0` to `t:quantity/0`
"""
@ -503,7 +530,7 @@ defmodule EthereumJSONRPC do
"""
def timestamp_to_datetime(timestamp) do
case quantity_to_integer(timestamp) do
:error ->
nil ->
nil
quantity ->

@ -34,6 +34,7 @@ defmodule EthereumJSONRPC.Blocks do
def from_responses(responses, id_to_params) when is_list(responses) and is_map(id_to_params) do
%{errors: errors, blocks: blocks} =
responses
|> EthereumJSONRPC.sanitize_responses(id_to_params)
|> Enum.map(&Block.from_response(&1, id_to_params))
|> Enum.reduce(%{errors: [], blocks: []}, fn
{:ok, block}, %{blocks: blocks} = acc ->

@ -19,6 +19,7 @@ defmodule EthereumJSONRPC.FetchedBalances do
"""
def from_responses(responses, id_to_params) do
responses
|> EthereumJSONRPC.sanitize_responses(id_to_params)
|> Enum.map(&FetchedBalance.from_response(&1, id_to_params))
|> Enum.reduce(
%__MODULE__{},

@ -77,6 +77,7 @@ defmodule EthereumJSONRPC.FetchedBeneficiaries do
"""
def from_responses(responses, id_to_params) when is_list(responses) and is_map(id_to_params) do
responses
|> EthereumJSONRPC.sanitize_responses(id_to_params)
|> Enum.map(&response_to_params_set(&1, id_to_params))
|> Enum.reduce(
%EthereumJSONRPC.FetchedBeneficiaries{},

@ -34,6 +34,7 @@ defmodule EthereumJSONRPC.FetchedCodes do
"""
def from_responses(responses, id_to_params) do
responses
|> EthereumJSONRPC.sanitize_responses(id_to_params)
|> Enum.map(&FetchedCode.from_response(&1, id_to_params))
|> Enum.reduce(
%__MODULE__{},

@ -145,6 +145,7 @@ defmodule EthereumJSONRPC.Geth do
)
when is_list(responses) and is_map(id_to_params) do
responses
|> EthereumJSONRPC.sanitize_responses(id_to_params)
|> Enum.map(&debug_trace_transaction_response_to_internal_transactions_params(&1, id_to_params))
|> reduce_internal_transactions_params()
end

@ -156,15 +156,18 @@ defmodule EthereumJSONRPC.HTTP do
standardized = %{jsonrpc: jsonrpc, id: id}
case unstandardized do
%{"result" => _, "error" => _} ->
case {id, unstandardized} do
{_id, %{"result" => _, "error" => _}} ->
raise ArgumentError,
"result and error keys are mutually exclusive in JSONRPC 2.0 response objects, but got #{inspect(unstandardized)}"
%{"result" => result} ->
{nil, %{"result" => error}} ->
Map.put(standardized, :error, standardize_error(error))
{_id, %{"result" => result}} ->
Map.put(standardized, :result, result)
%{"error" => error} ->
{_id, %{"error" => error}} ->
Map.put(standardized, :error, standardize_error(error))
end
end

@ -240,6 +240,7 @@ defmodule EthereumJSONRPC.Receipts do
defp reduce_responses(responses, id_to_transaction_params)
when is_list(responses) and is_map(id_to_transaction_params) do
responses
|> EthereumJSONRPC.sanitize_responses(id_to_transaction_params)
|> Stream.map(&response_to_receipt(&1, id_to_transaction_params))
|> Enum.reduce({:ok, []}, &reduce_receipt(&1, &2))
end

@ -66,6 +66,7 @@ defmodule EthereumJSONRPC.TraceReplayBlockTransactions do
defp trace_replay_block_transactions_responses_to_traces(responses, id_to_params)
when is_list(responses) and is_map(id_to_params) do
responses
|> EthereumJSONRPC.sanitize_responses(id_to_params)
|> Enum.map(&trace_replay_block_transactions_response_to_traces(&1, id_to_params))
|> Enum.reduce(
{:ok, []},
@ -158,6 +159,7 @@ defmodule EthereumJSONRPC.TraceReplayBlockTransactions do
defp trace_replay_transaction_responses_to_first_trace(responses, id_to_params)
when is_list(responses) and is_map(id_to_params) do
responses
|> EthereumJSONRPC.sanitize_responses(id_to_params)
|> Enum.map(&trace_replay_transaction_response_to_first_trace(&1, id_to_params))
|> Enum.reduce(
{:ok, []},

@ -967,7 +967,7 @@ defmodule EthereumJSONRPCSyncTest do
params_list: [
%{
address_hash: hash,
block_number: :error,
block_number: nil,
value: expected_fetched_balance
}
]

Loading…
Cancel
Save