commit
016046a29e
@ -0,0 +1,12 @@ |
|||||||
|
defmodule BlockScoutWeb.Resolvers.Block do |
||||||
|
@moduledoc false |
||||||
|
|
||||||
|
alias Explorer.Chain |
||||||
|
|
||||||
|
def get_by(_, %{number: number}, _) do |
||||||
|
case Chain.number_to_block(number) do |
||||||
|
{:ok, _} = result -> result |
||||||
|
{:error, :not_found} -> {:error, "Block number #{number} was not found."} |
||||||
|
end |
||||||
|
end |
||||||
|
end |
@ -0,0 +1,18 @@ |
|||||||
|
defmodule BlockScoutWeb.Schema do |
||||||
|
@moduledoc false |
||||||
|
|
||||||
|
use Absinthe.Schema |
||||||
|
|
||||||
|
alias BlockScoutWeb.Resolvers.Block |
||||||
|
|
||||||
|
import_types(Absinthe.Type.Custom) |
||||||
|
import_types(BlockScoutWeb.Schema.Types) |
||||||
|
|
||||||
|
query do |
||||||
|
@desc "Gets a block by number." |
||||||
|
field :block, :block do |
||||||
|
arg(:number, non_null(:integer)) |
||||||
|
resolve(&Block.get_by/3) |
||||||
|
end |
||||||
|
end |
||||||
|
end |
@ -0,0 +1,24 @@ |
|||||||
|
defmodule BlockScoutWeb.Schema.Types do |
||||||
|
@moduledoc false |
||||||
|
|
||||||
|
use Absinthe.Schema.Notation |
||||||
|
|
||||||
|
@desc """ |
||||||
|
A package of data that contains zero or more transactions, the hash of the previous block ("parent"), and optionally |
||||||
|
other data. Because each block (except for the initial "genesis block") points to the previous block, the data |
||||||
|
structure that they form is called a "blockchain". |
||||||
|
""" |
||||||
|
object :block do |
||||||
|
field(:consensus, :boolean) |
||||||
|
field(:difficulty, :decimal) |
||||||
|
field(:gas_limit, :decimal) |
||||||
|
field(:gas_used, :decimal) |
||||||
|
field(:nonce, :string) |
||||||
|
field(:number, :integer) |
||||||
|
field(:size, :integer) |
||||||
|
field(:timestamp, :datetime) |
||||||
|
field(:total_difficulty, :decimal) |
||||||
|
field(:miner_hash, :string) |
||||||
|
field(:parent_hash, :string) |
||||||
|
end |
||||||
|
end |
@ -0,0 +1,106 @@ |
|||||||
|
defmodule BlockScoutWeb.Schema.Query.BlockTest do |
||||||
|
use BlockScoutWeb.ConnCase |
||||||
|
|
||||||
|
describe "block field" do |
||||||
|
test "with valid argument 'number', returns all expected fields", %{conn: conn} do |
||||||
|
block = insert(:block) |
||||||
|
|
||||||
|
query = """ |
||||||
|
query ($number: Int!) { |
||||||
|
block(number: $number) { |
||||||
|
consensus |
||||||
|
difficulty |
||||||
|
gas_limit |
||||||
|
gas_used |
||||||
|
nonce |
||||||
|
number |
||||||
|
size |
||||||
|
timestamp |
||||||
|
total_difficulty |
||||||
|
miner_hash |
||||||
|
parent_hash |
||||||
|
parent_hash |
||||||
|
} |
||||||
|
} |
||||||
|
""" |
||||||
|
|
||||||
|
variables = %{"number" => block.number} |
||||||
|
|
||||||
|
conn = get(conn, "/graphql", query: query, variables: variables) |
||||||
|
|
||||||
|
assert json_response(conn, 200) == %{ |
||||||
|
"data" => %{ |
||||||
|
"block" => %{ |
||||||
|
"consensus" => block.consensus, |
||||||
|
"difficulty" => to_string(block.difficulty), |
||||||
|
"gas_limit" => to_string(block.gas_limit), |
||||||
|
"gas_used" => to_string(block.gas_used), |
||||||
|
"nonce" => to_string(block.nonce), |
||||||
|
"number" => block.number, |
||||||
|
"size" => block.size, |
||||||
|
"timestamp" => DateTime.to_iso8601(block.timestamp), |
||||||
|
"total_difficulty" => to_string(block.total_difficulty), |
||||||
|
"miner_hash" => to_string(block.miner_hash), |
||||||
|
"parent_hash" => to_string(block.parent_hash) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
end |
||||||
|
|
||||||
|
test "errors for non-existent block number", %{conn: conn} do |
||||||
|
block = insert(:block) |
||||||
|
non_existent_block_number = block.number + 1 |
||||||
|
|
||||||
|
query = """ |
||||||
|
query ($number: Int!) { |
||||||
|
block(number: $number) { |
||||||
|
number |
||||||
|
} |
||||||
|
} |
||||||
|
""" |
||||||
|
|
||||||
|
variables = %{"number" => non_existent_block_number} |
||||||
|
|
||||||
|
conn = get(conn, "/graphql", query: query, variables: variables) |
||||||
|
|
||||||
|
assert %{"errors" => [error]} = json_response(conn, 200) |
||||||
|
assert error["message"] =~ ~s(Block number #{non_existent_block_number} was not found) |
||||||
|
end |
||||||
|
|
||||||
|
test "errors if argument 'number' is missing", %{conn: conn} do |
||||||
|
insert(:block) |
||||||
|
|
||||||
|
query = """ |
||||||
|
{ |
||||||
|
block { |
||||||
|
number |
||||||
|
} |
||||||
|
} |
||||||
|
""" |
||||||
|
|
||||||
|
conn = get(conn, "/graphql", query: query) |
||||||
|
|
||||||
|
assert %{"errors" => [error]} = json_response(conn, 400) |
||||||
|
assert error["message"] == ~s(In argument "number": Expected type "Int!", found null.) |
||||||
|
end |
||||||
|
|
||||||
|
test "errors if argument 'number' is not an integer", %{conn: conn} do |
||||||
|
insert(:block) |
||||||
|
|
||||||
|
query = """ |
||||||
|
query ($number: Int!) { |
||||||
|
block(number: $number) { |
||||||
|
number |
||||||
|
} |
||||||
|
} |
||||||
|
""" |
||||||
|
|
||||||
|
variables = %{"number" => "invalid"} |
||||||
|
|
||||||
|
conn = get(conn, "/graphql", query: query, variables: variables) |
||||||
|
|
||||||
|
assert %{"errors" => [error]} = json_response(conn, 400) |
||||||
|
assert error["message"] =~ ~s(Argument "number" has invalid value) |
||||||
|
end |
||||||
|
end |
||||||
|
end |
Loading…
Reference in new issue