Merge branch 'master' into 922-network-themes

pull/1005/head
Andrew Cravenho 6 years ago committed by GitHub
commit 016046a29e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 12
      apps/block_scout_web/lib/block_scout_web/resolvers/block.ex
  2. 7
      apps/block_scout_web/lib/block_scout_web/router.ex
  3. 18
      apps/block_scout_web/lib/block_scout_web/schema.ex
  4. 24
      apps/block_scout_web/lib/block_scout_web/schema/types.ex
  5. 6
      apps/block_scout_web/mix.exs
  6. 106
      apps/block_scout_web/test/block_scout_web/schema/query/block_test.exs
  7. 2
      apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/request_coordinator.ex
  8. 4
      apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/transaction.ex
  9. 3
      mix.lock

@ -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

@ -38,6 +38,13 @@ defmodule BlockScoutWeb.Router do
}) })
end end
forward("/graphql", Absinthe.Plug, schema: BlockScoutWeb.Schema)
forward("/graphiql", Absinthe.Plug.GraphiQL,
schema: BlockScoutWeb.Schema,
interface: :playground
)
scope "/", BlockScoutWeb do scope "/", BlockScoutWeb do
pipe_through(:browser) pipe_through(:browser)

@ -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

@ -62,6 +62,12 @@ defmodule BlockScoutWeb.Mixfile do
# Type `mix help deps` for examples and options. # Type `mix help deps` for examples and options.
defp deps do defp deps do
[ [
# GraphQL toolkit
{:absinthe, "~> 1.4"},
# Integrates Absinthe subscriptions with Phoenix
{:absinthe_phoenix, "~> 1.4"},
# Plug support for Absinthe
{:absinthe_plug, "~> 1.4"},
{:bypass, "~> 0.8", only: :test}, {:bypass, "~> 0.8", only: :test},
{:cowboy, "~> 1.0"}, {:cowboy, "~> 1.0"},
{:credo, "0.9.2", only: [:dev, :test], runtime: false}, {:credo, "0.9.2", only: [:dev, :test], runtime: false},

@ -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

@ -67,6 +67,8 @@ defmodule EthereumJSONRPC.RequestCoordinator do
|> transport.json_rpc(transport_options) |> transport.json_rpc(transport_options)
|> handle_transport_response() |> handle_transport_response()
else else
:timer.sleep(throttle_timeout)
{:error, :timeout} {:error, :timeout}
end end
end end

@ -257,8 +257,10 @@ defmodule EthereumJSONRPC.Transaction do
# double check that no new keys are being missed by requiring explicit match for passthrough # double check that no new keys are being missed by requiring explicit match for passthrough
# `t:EthereumJSONRPC.address/0` and `t:EthereumJSONRPC.hash/0` pass through as `Explorer.Chain` can verify correct # `t:EthereumJSONRPC.address/0` and `t:EthereumJSONRPC.hash/0` pass through as `Explorer.Chain` can verify correct
# hash format # hash format
#
# "txType": to avoid FunctionClauseError when indexing Wanchain
defp entry_to_elixir({key, value}) defp entry_to_elixir({key, value})
when key in ~w(blockHash condition creates from hash input jsonrpc publicKey raw to), when key in ~w(blockHash condition creates from hash input jsonrpc publicKey raw to txType),
do: {key, value} do: {key, value}
defp entry_to_elixir({key, quantity}) when key in ~w(gas gasPrice nonce r s standardV v value) and quantity != nil do defp entry_to_elixir({key, quantity}) when key in ~w(gas gasPrice nonce r s standardV v value) and quantity != nil do

@ -1,6 +1,9 @@
%{ %{
"abi": {:hex, :abi, "0.1.12", "87ae04cb09e2308db7b3c350584dc3934de0e308f6a056ba82be5756b081a1ca", [:mix], [{:exth_crypto, "~> 0.1.4", [hex: :exth_crypto, repo: "hexpm", optional: false]}], "hexpm"}, "abi": {:hex, :abi, "0.1.12", "87ae04cb09e2308db7b3c350584dc3934de0e308f6a056ba82be5756b081a1ca", [:mix], [{:exth_crypto, "~> 0.1.4", [hex: :exth_crypto, repo: "hexpm", optional: false]}], "hexpm"},
"abnf2": {:hex, :abnf2, "0.1.2", "6f8792b8ac3288dba5fc889c2bceae9fe78f74e1a7b36bea9726ffaa9d7bef95", [:mix], []}, "abnf2": {:hex, :abnf2, "0.1.2", "6f8792b8ac3288dba5fc889c2bceae9fe78f74e1a7b36bea9726ffaa9d7bef95", [:mix], []},
"absinthe": {:hex, :absinthe, "1.4.13", "81eb2ff41f1b62cd6e992955f62c22c042d1079b7936c27f5f7c2c806b8fc436", [:mix], [{:dataloader, "~> 1.0.0", [hex: :dataloader, repo: "hexpm", optional: true]}, {:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"},
"absinthe_phoenix": {:hex, :absinthe_phoenix, "1.4.3", "cea34e7ebbc9a252038c1f1164878ee86bcb108905fe462be77efacda15c1e70", [:mix], [{:absinthe, "~> 1.4.0", [hex: :absinthe, repo: "hexpm", optional: false]}, {:absinthe_plug, "~> 1.4.0", [hex: :absinthe_plug, repo: "hexpm", optional: false]}, {:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.2", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.10.5 or ~> 2.11", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 1.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:poison, "~> 2.0 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm"},
"absinthe_plug": {:hex, :absinthe_plug, "1.4.5", "f63d52a76c870cd5f11d4bed8f61351ab5c5f572c5eb0479a0137f9f730ba33d", [:mix], [{:absinthe, "~> 1.4.11", [hex: :absinthe, repo: "hexpm", optional: false]}, {:plug, "~> 1.3.2 or ~> 1.4", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
"accept": {:hex, :accept, "0.3.3", "548ebb6fb2e8b0d170e75bb6123aea6ceecb0189bb1231eeadf52eac08384a97", [:rebar3], [], "hexpm"}, "accept": {:hex, :accept, "0.3.3", "548ebb6fb2e8b0d170e75bb6123aea6ceecb0189bb1231eeadf52eac08384a97", [:rebar3], [], "hexpm"},
"bcrypt_elixir": {:hex, :bcrypt_elixir, "1.0.6", "58a865939b3106d5ad4841f660955b958be6db955dda034fbbc1069dbacb97fa", [:make, :mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, optional: false]}]}, "bcrypt_elixir": {:hex, :bcrypt_elixir, "1.0.6", "58a865939b3106d5ad4841f660955b958be6db955dda034fbbc1069dbacb97fa", [:make, :mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, optional: false]}]},
"benchee": {:hex, :benchee, "0.13.1", "bd93ca05be78bcb6159c7176230efeda2f724f7ffd485515175ca411dff4893e", [:mix], [{:deep_merge, "~> 0.1", [hex: :deep_merge, optional: false]}]}, "benchee": {:hex, :benchee, "0.13.1", "bd93ca05be78bcb6159c7176230efeda2f724f7ffd485515175ca411dff4893e", [:mix], [{:deep_merge, "~> 0.1", [hex: :deep_merge, optional: false]}]},

Loading…
Cancel
Save