fix: search for long integers (#9651)

* fix: search for long integers

* fix: ignore negative block numbers

* chore: move `safe_parse_block_number` to `Explorer.Helper`

* refactor: make function name more generic

* refactor: utilize `safe_parse_non_negative_integer` in `paging_options`
docker-compose-changing-fe-port
Fedor Ivanov 7 months ago committed by GitHub
parent 55144018fe
commit ebe6535fa6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 4
      apps/block_scout_web/lib/block_scout_web/paging_helper.ex
  2. 18
      apps/block_scout_web/test/block_scout_web/controllers/api/v2/search_controller_test.exs
  3. 5
      apps/explorer/lib/explorer/chain/search.ex
  4. 31
      apps/explorer/lib/explorer/helper.ex

@ -40,8 +40,8 @@ defmodule BlockScoutWeb.PagingHelper do
def allowed_stability_validators_states, do: @allowed_stability_validators_states
def paging_options(%{"block_number" => block_number_string, "index" => index_string}, [:validated | _]) do
with {block_number, ""} <- Integer.parse(block_number_string),
{index, ""} <- Integer.parse(index_string) do
with {:ok, block_number} <- Helper.safe_parse_non_negative_integer(block_number_string),
{:ok, index} <- Helper.safe_parse_non_negative_integer(index_string) do
[paging_options: %{@default_paging_options | key: {block_number, index}}]
else
_ ->

@ -272,6 +272,24 @@ defmodule BlockScoutWeb.API.V2.SearchControllerTest do
assert Enum.count(response["items"]) == 4
assert response["next_page_params"] == nil
end
test "search for a big positive integer", %{conn: conn} do
big_integer = :math.pow(2, 64) |> round |> :erlang.integer_to_binary()
request = get(conn, "/api/v2/search?q=#{big_integer}")
assert response = json_response(request, 200)
assert Enum.count(response["items"]) == 0
assert response["next_page_params"] == nil
end
test "search for a big negative integer", %{conn: conn} do
big_integer = (:math.pow(2, 64) - 1) |> round |> :erlang.integer_to_binary()
request = get(conn, "/api/v2/search?q=#{big_integer}")
assert response = json_response(request, 200)
assert Enum.count(response["items"]) == 0
assert response["next_page_params"] == nil
end
end
describe "/search/check-redirect" do

@ -16,6 +16,7 @@ defmodule Explorer.Chain.Search do
import Explorer.Chain, only: [select_repo: 1]
import Explorer.MicroserviceInterfaces.BENS, only: [ens_domain_name_lookup: 1]
alias Explorer.{Chain, PagingOptions}
alias Explorer.Helper, as: ExplorerHelper
alias Explorer.Tags.{AddressTag, AddressToTag}
alias Explorer.Chain.{
@ -488,8 +489,8 @@ defmodule Explorer.Chain.Search do
)
_ ->
case Integer.parse(term) do
{block_number, ""} ->
case ExplorerHelper.safe_parse_non_negative_integer(term) do
{:ok, block_number} ->
from(block in Block,
where: block.number == ^block_number,
select: ^block_search_fields

@ -9,6 +9,8 @@ defmodule Explorer.Helper do
import Ecto.Query, only: [where: 3]
@max_safe_integer round(:math.pow(2, 63)) - 1
@spec decode_data(binary() | map(), list()) :: list() | nil
def decode_data("0x", types) do
for _ <- types, do: nil
@ -67,6 +69,35 @@ defmodule Explorer.Helper do
number
end
@doc """
Converts a string to an integer, ensuring it's non-negative and within the
acceptable range for database insertion.
## Examples
iex> safe_parse_non_negative_integer("0")
{:ok, 0}
iex> safe_parse_non_negative_integer("-1")
{:error, :negative_integer}
iex> safe_parse_non_negative_integer("27606393966689717254124294199939478533331961967491413693980084341759630764504")
{:error, :too_big_integer}
"""
def safe_parse_non_negative_integer(string) do
case Integer.parse(string) do
{num, ""} ->
case num do
_ when num > @max_safe_integer -> {:error, :too_big_integer}
_ when num < 0 -> {:error, :negative_integer}
_ -> {:ok, num}
end
_ ->
{:error, :invalid_integer}
end
end
@doc """
Function to preload a `struct` for each element of the `list`.
You should specify a primary key for a `struct` in `references_field`,

Loading…
Cancel
Save