Merge pull request #1003 from poanetwork/sa-graphql-get-transaction-by-hash

GraphQL API get transaction by hash
pull/1013/head
Luke Imhoff 6 years ago committed by GitHub
commit 35da159443
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 12
      apps/block_scout_web/lib/block_scout_web/resolvers/transaction.ex
  2. 8
      apps/block_scout_web/lib/block_scout_web/schema.ex
  3. 29
      apps/block_scout_web/lib/block_scout_web/schema/scalars.ex
  4. 24
      apps/block_scout_web/lib/block_scout_web/schema/types.ex
  5. 119
      apps/block_scout_web/test/block_scout_web/schema/query/transaction_test.exs

@ -0,0 +1,12 @@
defmodule BlockScoutWeb.Resolvers.Transaction do
@moduledoc false
alias Explorer.Chain
def get_by(_, %{hash: hash}, _) do
case Chain.hash_to_transaction(hash) do
{:ok, transaction} -> {:ok, transaction}
{:error, :not_found} -> {:error, "Transaction hash #{hash} was not found."}
end
end
end

@ -3,7 +3,7 @@ defmodule BlockScoutWeb.Schema do
use Absinthe.Schema use Absinthe.Schema
alias BlockScoutWeb.Resolvers.Block alias BlockScoutWeb.Resolvers.{Block, Transaction}
import_types(BlockScoutWeb.Schema.Types) import_types(BlockScoutWeb.Schema.Types)
@ -13,5 +13,11 @@ defmodule BlockScoutWeb.Schema do
arg(:number, non_null(:integer)) arg(:number, non_null(:integer))
resolve(&Block.get_by/3) resolve(&Block.get_by/3)
end end
@desc "Gets a transaction by hash."
field :transaction, :transaction do
arg(:hash, non_null(:full_hash))
resolve(&Transaction.get_by/3)
end
end end
end end

@ -3,7 +3,7 @@ defmodule BlockScoutWeb.Schema.Scalars do
use Absinthe.Schema.Notation use Absinthe.Schema.Notation
alias Explorer.Chain.Hash alias Explorer.Chain.{Hash, Wei}
alias Explorer.Chain.Hash.{Address, Full, Nonce} alias Explorer.Chain.Hash.{Address, Full, Nonce}
@desc """ @desc """
@ -53,4 +53,31 @@ defmodule BlockScoutWeb.Schema.Scalars do
serialize(&to_string/1) serialize(&to_string/1)
end end
@desc """
The smallest fractional unit of Ether. Using wei instead of ether allows code to do integer match instead of using
floats.
See [Ethereum Homestead Documentation](http://ethdocs.org/en/latest/ether.html) for examples of various denominations of wei.
Etymology of "wei" comes from [Wei Dai ()](https://en.wikipedia.org/wiki/Wei_Dai), a
[cypherpunk](https://en.wikipedia.org/wiki/Cypherpunk) who came up with b-money, which outlined modern
cryptocurrencies.
"""
scalar :wei do
parse(fn
%Absinthe.Blueprint.Input.String{value: value} ->
Wei.cast(value)
_ ->
:error
end)
serialize(&to_string(&1.value))
end
enum :status do
value(:ok)
value(:error)
end
end end

@ -24,4 +24,28 @@ defmodule BlockScoutWeb.Schema.Types do
field(:miner_hash, :address_hash) field(:miner_hash, :address_hash)
field(:parent_hash, :full_hash) field(:parent_hash, :full_hash)
end end
@desc """
Models a Web3 transaction.
"""
object :transaction do
field(:hash, :full_hash)
field(:block_number, :integer)
field(:cumulative_gas_used, :decimal)
field(:error, :string)
field(:gas, :decimal)
field(:gas_price, :wei)
field(:gas_used, :decimal)
field(:index, :integer)
field(:input, :string)
field(:nonce, :nonce_hash)
field(:r, :decimal)
field(:s, :decimal)
field(:status, :status)
field(:v, :integer)
field(:value, :wei)
field(:from_address_hash, :address_hash)
field(:to_address_hash, :address_hash)
field(:created_contract_address_hash, :address_hash)
end
end end

@ -0,0 +1,119 @@
defmodule BlockScoutWeb.Schema.Query.TransactionTest do
use BlockScoutWeb.ConnCase
describe "transaction field" do
test "with valid argument 'hash', returns all expected fields", %{conn: conn} do
block = insert(:block)
transaction =
:transaction
|> insert()
|> with_block(block, status: :ok)
query = """
query ($hash: FullHash!) {
transaction(hash: $hash) {
hash
block_number
cumulative_gas_used
error
gas
gas_price
gas_used
index
input
nonce
r
s
status
v
value
from_address_hash
to_address_hash
created_contract_address_hash
}
}
"""
variables = %{"hash" => to_string(transaction.hash)}
conn = get(conn, "/graphql", query: query, variables: variables)
assert json_response(conn, 200) == %{
"data" => %{
"transaction" => %{
"hash" => to_string(transaction.hash),
"block_number" => transaction.block_number,
"cumulative_gas_used" => to_string(transaction.cumulative_gas_used),
"error" => transaction.error,
"gas" => to_string(transaction.gas),
"gas_price" => to_string(transaction.gas_price.value),
"gas_used" => to_string(transaction.gas_used),
"index" => transaction.index,
"input" => to_string(transaction.input),
"nonce" => to_string(transaction.nonce),
"r" => to_string(transaction.r),
"s" => to_string(transaction.s),
"status" => transaction.status |> to_string() |> String.upcase(),
"v" => transaction.v,
"value" => to_string(transaction.value.value),
"from_address_hash" => to_string(transaction.from_address_hash),
"to_address_hash" => to_string(transaction.to_address_hash),
"created_contract_address_hash" => nil
}
}
}
end
test "errors for non-existent transaction hash", %{conn: conn} do
transaction = build(:transaction)
query = """
query ($hash: FullHash!) {
transaction(hash: $hash) {
status
}
}
"""
variables = %{"hash" => to_string(transaction.hash)}
conn = get(conn, "/graphql", query: query, variables: variables)
assert %{"errors" => [error]} = json_response(conn, 200)
assert error["message"] =~ ~s(Transaction hash #{transaction.hash} was not found)
end
test "errors if argument 'hash' is missing", %{conn: conn} do
query = """
{
transaction {
status
}
}
"""
conn = get(conn, "/graphql", query: query)
assert %{"errors" => [error]} = json_response(conn, 400)
assert error["message"] == ~s(In argument "hash": Expected type "FullHash!", found null.)
end
test "errors if argument 'hash' is not a 'FullHash'", %{conn: conn} do
query = """
query ($hash: FullHash!) {
transaction(hash: $hash) {
status
}
}
"""
variables = %{"hash" => "0x000"}
conn = get(conn, "/graphql", query: query, variables: variables)
assert %{"errors" => [error]} = json_response(conn, 400)
assert error["message"] =~ ~s(Argument "hash" has invalid value)
end
end
end
Loading…
Cancel
Save