Search for non-consensus blocks by hash

pull/802/head
Luke Imhoff 6 years ago
parent 8e8b4b5508
commit 49f99b1400
  1. 18
      apps/block_scout_web/lib/block_scout_web/chain.ex
  2. 6
      apps/block_scout_web/lib/phoenix/param.ex
  3. 8
      apps/block_scout_web/test/block_scout_web/controllers/chain_controller_test.exs
  4. 17
      apps/block_scout_web/test/phoenix/param/explorer/chain/block_test.exs
  5. 35
      apps/explorer/lib/explorer/chain.ex

@ -6,9 +6,11 @@ defmodule BlockScoutWeb.Chain do
import Explorer.Chain,
only: [
hash_to_address: 1,
hash_to_block: 1,
hash_to_transaction: 1,
number_to_block: 1,
string_to_address_hash: 1,
string_to_block_hash: 1,
string_to_transaction_hash: 1
]
@ -53,7 +55,7 @@ defmodule BlockScoutWeb.Chain do
def from_param("0x" <> number_string = param) do
case String.length(number_string) do
40 -> address_from_param(param)
64 -> transaction_from_param(param)
64 -> block_or_transaction_from_param(param)
_ -> {:error, :not_found}
end
end
@ -196,6 +198,12 @@ defmodule BlockScoutWeb.Chain do
%{"address_hash" => to_string(address_hash), "value" => Decimal.to_integer(value)}
end
defp block_or_transaction_from_param(param) do
with {:error, :not_found} <- transaction_from_param(param) do
hash_string_to_block(param)
end
end
defp transaction_from_param(param) do
with {:ok, hash} <- string_to_transaction_hash(param) do
hash_to_transaction(hash)
@ -203,4 +211,12 @@ defmodule BlockScoutWeb.Chain do
:error -> {:error, :not_found}
end
end
defp hash_string_to_block(hash_string) do
with {:ok, hash} <- string_to_block_hash(hash_string) do
hash_to_block(hash)
else
:error -> {:error, :not_found}
end
end
end

@ -7,9 +7,13 @@ defimpl Phoenix.Param, for: [Address, Transaction] do
end
defimpl Phoenix.Param, for: Block do
def to_param(%@for{number: number}) do
def to_param(%@for{consensus: true, number: number}) do
to_string(number)
end
def to_param(%@for{consensus: false, hash: hash}) do
to_string(hash)
end
end
defimpl Phoenix.Param, for: Hash do

@ -81,6 +81,14 @@ defmodule BlockScoutWeb.ChainControllerTest do
assert conn.status == 404
end
test "finds non-consensus block by hash", %{conn: conn} do
%Block{hash: hash} = insert(:block, consensus: false)
conn = get(conn, "/search?q=#{hash}")
assert redirected_to(conn) == block_path(conn, :show, hash)
end
test "finds a transaction by hash", %{conn: conn} do
transaction =
:transaction

@ -0,0 +1,17 @@
defmodule Phoenix.Param.Explorer.Chain.BlockTest do
use ExUnit.Case
import Explorer.Factory
test "without consensus" do
block = build(:block, consensus: false)
assert Phoenix.Param.to_param(block) == to_string(block.hash)
end
test "with consensus" do
block = build(:block, consensus: true)
assert Phoenix.Param.to_param(block) == to_string(block.number)
end
end

@ -585,6 +585,41 @@ defmodule Explorer.Chain do
end
end
@doc """
Converts `t:Explorer.Chain.Block.t/0` `hash` to the `t:Explorer.Chain.Block.t/0` with that `hash`.
Unlike `number_to_block/1`, both consensus and non-consensus blocks can be returned when looked up by `hash`.
Returns `{:ok, %Explorer.Chain.Block{}}` if found
iex> %Block{hash: hash} = insert(:block, consensus: false)
iex> {:ok, %Explorer.Chain.Block{hash: found_hash}} = Explorer.Chain.hash_to_block(hash)
iex> found_hash == hash
true
Returns `{:error, :not_found}` if not found
iex> {:ok, hash} = Explorer.Chain.string_to_block_hash(
...> "0x9fc76417374aa880d4449a1f7f31ec597f00b1f6f3dd2d66f4c9c6c445836d8b"
...> )
iex> Explorer.Chain.hash_to_block(hash)
{:error, :not_found}
"""
@spec hash_to_block(Hash.Full.t()) :: {:ok, Block.t()} | {:error, :not_found}
def hash_to_block(%Hash{byte_count: unquote(Hash.Full.byte_count())} = hash) do
Block
|> where(hash: ^hash)
|> Repo.one()
|> case do
nil ->
{:error, :not_found}
block ->
{:ok, block}
end
end
@doc """
Converts the `Explorer.Chain.Hash.t:t/0` to `iodata` representation that can be written efficiently to users.

Loading…
Cancel
Save