|
|
|
@ -2,12 +2,12 @@ defmodule BlockScoutWeb.Schema.Query.AddressTest do |
|
|
|
|
use BlockScoutWeb.ConnCase |
|
|
|
|
|
|
|
|
|
describe "address field" do |
|
|
|
|
test "with valid argument 'hashes', returns all expected fields", %{conn: conn} do |
|
|
|
|
test "with valid argument 'hash', returns all expected fields", %{conn: conn} do |
|
|
|
|
address = insert(:address, fetched_coin_balance: 100) |
|
|
|
|
|
|
|
|
|
query = """ |
|
|
|
|
query ($hashes: [AddressHash!]!) { |
|
|
|
|
addresses(hashes: $hashes) { |
|
|
|
|
query ($hash: AddressHash!) { |
|
|
|
|
address(hash: $hash) { |
|
|
|
|
hash |
|
|
|
|
fetched_coin_balance |
|
|
|
|
fetched_coin_balance_block_number |
|
|
|
@ -16,20 +16,18 @@ defmodule BlockScoutWeb.Schema.Query.AddressTest do |
|
|
|
|
} |
|
|
|
|
""" |
|
|
|
|
|
|
|
|
|
variables = %{"hashes" => to_string(address.hash)} |
|
|
|
|
variables = %{"hash" => to_string(address.hash)} |
|
|
|
|
|
|
|
|
|
conn = get(conn, "/graphql", query: query, variables: variables) |
|
|
|
|
|
|
|
|
|
assert json_response(conn, 200) == %{ |
|
|
|
|
"data" => %{ |
|
|
|
|
"addresses" => [ |
|
|
|
|
%{ |
|
|
|
|
"hash" => to_string(address.hash), |
|
|
|
|
"fetched_coin_balance" => to_string(address.fetched_coin_balance.value), |
|
|
|
|
"fetched_coin_balance_block_number" => address.fetched_coin_balance_block_number, |
|
|
|
|
"contract_code" => nil |
|
|
|
|
} |
|
|
|
|
] |
|
|
|
|
"address" => %{ |
|
|
|
|
"hash" => to_string(address.hash), |
|
|
|
|
"fetched_coin_balance" => to_string(address.fetched_coin_balance.value), |
|
|
|
|
"fetched_coin_balance_block_number" => address.fetched_coin_balance_block_number, |
|
|
|
|
"contract_code" => nil |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
end |
|
|
|
@ -38,24 +36,22 @@ defmodule BlockScoutWeb.Schema.Query.AddressTest do |
|
|
|
|
address = insert(:contract_address, fetched_coin_balance: 100) |
|
|
|
|
|
|
|
|
|
query = """ |
|
|
|
|
query ($hashes: [AddressHash!]!) { |
|
|
|
|
addresses(hashes: $hashes) { |
|
|
|
|
query ($hash: AddressHash!) { |
|
|
|
|
address(hash: $hash) { |
|
|
|
|
contract_code |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
""" |
|
|
|
|
|
|
|
|
|
variables = %{"hashes" => to_string(address.hash)} |
|
|
|
|
variables = %{"hash" => to_string(address.hash)} |
|
|
|
|
|
|
|
|
|
conn = get(conn, "/graphql", query: query, variables: variables) |
|
|
|
|
|
|
|
|
|
assert json_response(conn, 200) == %{ |
|
|
|
|
"data" => %{ |
|
|
|
|
"addresses" => [ |
|
|
|
|
%{ |
|
|
|
|
"contract_code" => to_string(address.contract_code) |
|
|
|
|
} |
|
|
|
|
] |
|
|
|
|
"address" => %{ |
|
|
|
|
"contract_code" => to_string(address.contract_code) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
end |
|
|
|
@ -65,8 +61,8 @@ defmodule BlockScoutWeb.Schema.Query.AddressTest do |
|
|
|
|
smart_contract = insert(:smart_contract, address_hash: address.hash) |
|
|
|
|
|
|
|
|
|
query = """ |
|
|
|
|
query ($hashes: [AddressHash!]!) { |
|
|
|
|
addresses(hashes: $hashes) { |
|
|
|
|
query ($hash: AddressHash!) { |
|
|
|
|
address(hash: $hash) { |
|
|
|
|
fetched_coin_balance |
|
|
|
|
smart_contract { |
|
|
|
|
name |
|
|
|
@ -80,52 +76,50 @@ defmodule BlockScoutWeb.Schema.Query.AddressTest do |
|
|
|
|
} |
|
|
|
|
""" |
|
|
|
|
|
|
|
|
|
variables = %{"hashes" => to_string(address.hash)} |
|
|
|
|
variables = %{"hash" => to_string(address.hash)} |
|
|
|
|
|
|
|
|
|
conn = get(conn, "/graphql", query: query, variables: variables) |
|
|
|
|
|
|
|
|
|
assert json_response(conn, 200) == %{ |
|
|
|
|
"data" => %{ |
|
|
|
|
"addresses" => [ |
|
|
|
|
%{ |
|
|
|
|
"fetched_coin_balance" => to_string(address.fetched_coin_balance.value), |
|
|
|
|
"smart_contract" => %{ |
|
|
|
|
"name" => smart_contract.name, |
|
|
|
|
"compiler_version" => smart_contract.compiler_version, |
|
|
|
|
"optimization" => smart_contract.optimization, |
|
|
|
|
"contract_source_code" => smart_contract.contract_source_code, |
|
|
|
|
"abi" => Jason.encode!(smart_contract.abi), |
|
|
|
|
"address_hash" => to_string(address.hash) |
|
|
|
|
} |
|
|
|
|
"address" => %{ |
|
|
|
|
"fetched_coin_balance" => to_string(address.fetched_coin_balance.value), |
|
|
|
|
"smart_contract" => %{ |
|
|
|
|
"name" => smart_contract.name, |
|
|
|
|
"compiler_version" => smart_contract.compiler_version, |
|
|
|
|
"optimization" => smart_contract.optimization, |
|
|
|
|
"contract_source_code" => smart_contract.contract_source_code, |
|
|
|
|
"abi" => Jason.encode!(smart_contract.abi), |
|
|
|
|
"address_hash" => to_string(address.hash) |
|
|
|
|
} |
|
|
|
|
] |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
test "errors for non-existent address hashes", %{conn: conn} do |
|
|
|
|
test "errors for non-existent address hash", %{conn: conn} do |
|
|
|
|
address = build(:address) |
|
|
|
|
|
|
|
|
|
query = """ |
|
|
|
|
query ($hashes: [AddressHash!]!) { |
|
|
|
|
addresses(hashes: $hashes) { |
|
|
|
|
query ($hash: AddressHash!) { |
|
|
|
|
address(hash: $hash) { |
|
|
|
|
fetched_coin_balance |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
""" |
|
|
|
|
|
|
|
|
|
variables = %{"hashes" => [to_string(address.hash)]} |
|
|
|
|
variables = %{"hash" => to_string(address.hash)} |
|
|
|
|
|
|
|
|
|
conn = get(conn, "/graphql", query: query, variables: variables) |
|
|
|
|
|
|
|
|
|
assert %{"errors" => [error]} = json_response(conn, 200) |
|
|
|
|
assert error["message"] =~ ~s(Addresses not found.) |
|
|
|
|
assert error["message"] =~ ~s(Address not found.) |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
test "errors if argument 'hashes' is missing", %{conn: conn} do |
|
|
|
|
test "errors if argument 'hash' is missing", %{conn: conn} do |
|
|
|
|
query = """ |
|
|
|
|
query { |
|
|
|
|
addresses { |
|
|
|
|
address { |
|
|
|
|
fetched_coin_balance |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -136,50 +130,423 @@ defmodule BlockScoutWeb.Schema.Query.AddressTest do |
|
|
|
|
conn = get(conn, "/graphql", query: query, variables: variables) |
|
|
|
|
|
|
|
|
|
assert %{"errors" => [error]} = json_response(conn, 200) |
|
|
|
|
assert error["message"] == ~s(In argument "hashes": Expected type "[AddressHash!]!", found null.) |
|
|
|
|
assert error["message"] == ~s(In argument "hash": Expected type "AddressHash!", found null.) |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
test "errors if argument 'hashes' is not a list of address hashes", %{conn: conn} do |
|
|
|
|
test "errors if argument 'hash' is not a valid address hash", %{conn: conn} do |
|
|
|
|
query = """ |
|
|
|
|
query ($hashes: [AddressHash!]!) { |
|
|
|
|
addresses(hashes: $hashes) { |
|
|
|
|
query ($hash: AddressHash!) { |
|
|
|
|
address(hash: $hash) { |
|
|
|
|
fetched_coin_balance |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
""" |
|
|
|
|
|
|
|
|
|
variables = %{"hashes" => ["someInvalidHash"]} |
|
|
|
|
variables = %{"hash" => "someInvalidHash"} |
|
|
|
|
|
|
|
|
|
conn = get(conn, "/graphql", query: query, variables: variables) |
|
|
|
|
|
|
|
|
|
assert %{"errors" => [error]} = json_response(conn, 200) |
|
|
|
|
assert error["message"] =~ ~s(Argument "hashes" has invalid value) |
|
|
|
|
assert error["message"] =~ ~s(Argument "hash" has invalid value) |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
describe "address transactions field" do |
|
|
|
|
test "returns all expected transaction fields", %{conn: conn} do |
|
|
|
|
address = insert(:address) |
|
|
|
|
|
|
|
|
|
test "correlates complexity to size of 'hashes' argument", %{conn: conn} do |
|
|
|
|
# max of 50 addresses with four fields of complexity 1 can be fetched |
|
|
|
|
# per query: |
|
|
|
|
# 50 * 4 = 200, which is equal to a max complexity of 200 |
|
|
|
|
hashes = 51 |> build_list(:address) |> Enum.map(&to_string(&1.hash)) |
|
|
|
|
transaction = insert(:transaction, from_address: address) |
|
|
|
|
|
|
|
|
|
query = """ |
|
|
|
|
query ($hashes: [AddressHash!]!) { |
|
|
|
|
addresses(hashes: $hashes) { |
|
|
|
|
hash |
|
|
|
|
fetched_coin_balance |
|
|
|
|
fetched_coin_balance_block_number |
|
|
|
|
contract_code |
|
|
|
|
query ($hash: AddressHash!, $first: Int!) { |
|
|
|
|
address(hash: $hash) { |
|
|
|
|
transactions(first: $first) { |
|
|
|
|
edges { |
|
|
|
|
node { |
|
|
|
|
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(address.hash), |
|
|
|
|
"first" => 1 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
conn = get(conn, "/graphql", query: query, variables: variables) |
|
|
|
|
|
|
|
|
|
assert json_response(conn, 200) == %{ |
|
|
|
|
"data" => %{ |
|
|
|
|
"address" => %{ |
|
|
|
|
"transactions" => %{ |
|
|
|
|
"edges" => [ |
|
|
|
|
%{ |
|
|
|
|
"node" => %{ |
|
|
|
|
"hash" => to_string(transaction.hash), |
|
|
|
|
"block_number" => transaction.block_number, |
|
|
|
|
"cumulative_gas_used" => nil, |
|
|
|
|
"error" => transaction.error, |
|
|
|
|
"gas" => to_string(transaction.gas), |
|
|
|
|
"gas_price" => to_string(transaction.gas_price.value), |
|
|
|
|
"gas_used" => nil, |
|
|
|
|
"index" => transaction.index, |
|
|
|
|
"input" => to_string(transaction.input), |
|
|
|
|
"nonce" => to_string(transaction.nonce), |
|
|
|
|
"r" => to_string(transaction.r), |
|
|
|
|
"s" => to_string(transaction.s), |
|
|
|
|
"status" => nil, |
|
|
|
|
"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 "with address with zero transactions", %{conn: conn} do |
|
|
|
|
address = insert(:address) |
|
|
|
|
|
|
|
|
|
query = """ |
|
|
|
|
query ($hash: AddressHash!, $first: Int!) { |
|
|
|
|
address(hash: $hash) { |
|
|
|
|
transactions(first: $first) { |
|
|
|
|
edges { |
|
|
|
|
node { |
|
|
|
|
hash |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
""" |
|
|
|
|
|
|
|
|
|
variables = %{ |
|
|
|
|
"hash" => to_string(address.hash), |
|
|
|
|
"first" => 1 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
conn = get(conn, "/graphql", query: query, variables: variables) |
|
|
|
|
|
|
|
|
|
assert json_response(conn, 200) == %{ |
|
|
|
|
"data" => %{ |
|
|
|
|
"address" => %{ |
|
|
|
|
"transactions" => %{ |
|
|
|
|
"edges" => [] |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
test "transactions are ordered by descending block and index", %{conn: conn} do |
|
|
|
|
first_block = insert(:block) |
|
|
|
|
second_block = insert(:block) |
|
|
|
|
third_block = insert(:block) |
|
|
|
|
|
|
|
|
|
address = insert(:address) |
|
|
|
|
|
|
|
|
|
3 |
|
|
|
|
|> insert_list(:transaction, from_address: address) |
|
|
|
|
|> with_block(second_block) |
|
|
|
|
|
|
|
|
|
3 |
|
|
|
|
|> insert_list(:transaction, from_address: address) |
|
|
|
|
|> with_block(third_block) |
|
|
|
|
|
|
|
|
|
3 |
|
|
|
|
|> insert_list(:transaction, from_address: address) |
|
|
|
|
|> with_block(first_block) |
|
|
|
|
|
|
|
|
|
query = """ |
|
|
|
|
query ($hash: AddressHash!, $first: Int!) { |
|
|
|
|
address(hash: $hash) { |
|
|
|
|
transactions(first: $first) { |
|
|
|
|
edges { |
|
|
|
|
node { |
|
|
|
|
hash |
|
|
|
|
block_number |
|
|
|
|
index |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
""" |
|
|
|
|
|
|
|
|
|
variables = %{ |
|
|
|
|
"hash" => to_string(address.hash), |
|
|
|
|
"first" => 3 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
conn = get(conn, "/graphql", query: query, variables: variables) |
|
|
|
|
|
|
|
|
|
%{ |
|
|
|
|
"data" => %{ |
|
|
|
|
"address" => %{ |
|
|
|
|
"transactions" => %{ |
|
|
|
|
"edges" => transactions |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} = json_response(conn, 200) |
|
|
|
|
|
|
|
|
|
block_number_and_index_order = |
|
|
|
|
Enum.map(transactions, fn transaction -> |
|
|
|
|
{transaction["node"]["block_number"], transaction["node"]["index"]} |
|
|
|
|
end) |
|
|
|
|
|
|
|
|
|
assert block_number_and_index_order == Enum.sort(block_number_and_index_order, &(&1 >= &2)) |
|
|
|
|
assert length(transactions) == 3 |
|
|
|
|
assert Enum.all?(transactions, &(&1["node"]["block_number"] == third_block.number)) |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
test "complexity correlates to 'first' or 'last' arguments", %{conn: conn} do |
|
|
|
|
address = build(:address) |
|
|
|
|
|
|
|
|
|
query = """ |
|
|
|
|
query ($hash: AddressHash!, $first: Int!) { |
|
|
|
|
address(hash: $hash) { |
|
|
|
|
transactions(first: $first) { |
|
|
|
|
edges { |
|
|
|
|
node { |
|
|
|
|
hash |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
""" |
|
|
|
|
|
|
|
|
|
variables = %{"hashes" => hashes} |
|
|
|
|
variables = %{ |
|
|
|
|
"hash" => to_string(address.hash), |
|
|
|
|
"first" => 67 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
conn = get(conn, "/graphql", query: query, variables: variables) |
|
|
|
|
|
|
|
|
|
assert %{"errors" => [error1, error2, error3]} = json_response(conn, 200) |
|
|
|
|
assert error1["message"] =~ ~s(Field transactions is too complex) |
|
|
|
|
assert error2["message"] =~ ~s(Field address is too complex) |
|
|
|
|
assert error3["message"] =~ ~s(Operation is too complex) |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
test "with 'last' and 'count' arguments", %{conn: conn} do |
|
|
|
|
# "`last: N` must always be acompanied by either a `before:` argument to |
|
|
|
|
# the query, or an explicit `count:` option to the `from_query` call. |
|
|
|
|
# Otherwise it is impossible to derive the required offset." |
|
|
|
|
# https://hexdocs.pm/absinthe_relay/Absinthe.Relay.Connection.html#from_query/4 |
|
|
|
|
# |
|
|
|
|
# This test ensures support of a 'count' argument. |
|
|
|
|
|
|
|
|
|
first_block = insert(:block) |
|
|
|
|
second_block = insert(:block) |
|
|
|
|
third_block = insert(:block) |
|
|
|
|
|
|
|
|
|
address = insert(:address) |
|
|
|
|
|
|
|
|
|
3 |
|
|
|
|
|> insert_list(:transaction, from_address: address) |
|
|
|
|
|> with_block(second_block) |
|
|
|
|
|
|
|
|
|
3 |
|
|
|
|
|> insert_list(:transaction, from_address: address) |
|
|
|
|
|> with_block(third_block) |
|
|
|
|
|
|
|
|
|
3 |
|
|
|
|
|> insert_list(:transaction, from_address: address) |
|
|
|
|
|> with_block(first_block) |
|
|
|
|
|
|
|
|
|
query = """ |
|
|
|
|
query ($hash: AddressHash!, $last: Int!, $count: Int!) { |
|
|
|
|
address(hash: $hash) { |
|
|
|
|
transactions(last: $last, count: $count) { |
|
|
|
|
edges { |
|
|
|
|
node { |
|
|
|
|
hash |
|
|
|
|
block_number |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
""" |
|
|
|
|
|
|
|
|
|
variables = %{ |
|
|
|
|
"hash" => to_string(address.hash), |
|
|
|
|
"last" => 3, |
|
|
|
|
"count" => 9 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
conn = get(conn, "/graphql", query: query, variables: variables) |
|
|
|
|
|
|
|
|
|
assert %{"errors" => [error1, error2]} = json_response(conn, 200) |
|
|
|
|
assert error1["message"] =~ ~s(Field addresses is too complex) |
|
|
|
|
assert error2["message"] =~ ~s(Operation is too complex) |
|
|
|
|
%{ |
|
|
|
|
"data" => %{ |
|
|
|
|
"address" => %{ |
|
|
|
|
"transactions" => %{ |
|
|
|
|
"edges" => transactions |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} = json_response(conn, 200) |
|
|
|
|
|
|
|
|
|
assert length(transactions) == 3 |
|
|
|
|
assert Enum.all?(transactions, &(&1["node"]["block_number"] == first_block.number)) |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
test "pagination support with 'first' and 'after' arguments", %{conn: conn} do |
|
|
|
|
first_block = insert(:block) |
|
|
|
|
second_block = insert(:block) |
|
|
|
|
third_block = insert(:block) |
|
|
|
|
|
|
|
|
|
address = insert(:address) |
|
|
|
|
|
|
|
|
|
3 |
|
|
|
|
|> insert_list(:transaction, from_address: address) |
|
|
|
|
|> with_block(second_block) |
|
|
|
|
|
|
|
|
|
3 |
|
|
|
|
|> insert_list(:transaction, from_address: address) |
|
|
|
|
|> with_block(third_block) |
|
|
|
|
|
|
|
|
|
3 |
|
|
|
|
|> insert_list(:transaction, from_address: address) |
|
|
|
|
|> with_block(first_block) |
|
|
|
|
|
|
|
|
|
query1 = """ |
|
|
|
|
query ($hash: AddressHash!, $first: Int!) { |
|
|
|
|
address(hash: $hash) { |
|
|
|
|
transactions(first: $first) { |
|
|
|
|
page_info { |
|
|
|
|
has_next_page |
|
|
|
|
has_previous_page |
|
|
|
|
} |
|
|
|
|
edges { |
|
|
|
|
node { |
|
|
|
|
hash |
|
|
|
|
block_number |
|
|
|
|
} |
|
|
|
|
cursor |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
""" |
|
|
|
|
|
|
|
|
|
variables1 = %{ |
|
|
|
|
"hash" => to_string(address.hash), |
|
|
|
|
"first" => 3 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
conn = get(conn, "/graphql", query: query1, variables: variables1) |
|
|
|
|
|
|
|
|
|
%{"data" => %{"address" => %{"transactions" => page1}}} = json_response(conn, 200) |
|
|
|
|
|
|
|
|
|
assert page1["page_info"] == %{"has_next_page" => true, "has_previous_page" => false} |
|
|
|
|
assert Enum.all?(page1["edges"], &(&1["node"]["block_number"] == third_block.number)) |
|
|
|
|
|
|
|
|
|
last_cursor_page1 = |
|
|
|
|
page1 |
|
|
|
|
|> Map.get("edges") |
|
|
|
|
|> List.last() |
|
|
|
|
|> Map.get("cursor") |
|
|
|
|
|
|
|
|
|
query2 = """ |
|
|
|
|
query ($hash: AddressHash!, $first: Int!, $after: Int!) { |
|
|
|
|
address(hash: $hash) { |
|
|
|
|
transactions(first: $first, after: $after) { |
|
|
|
|
page_info { |
|
|
|
|
has_next_page |
|
|
|
|
has_previous_page |
|
|
|
|
} |
|
|
|
|
edges { |
|
|
|
|
node { |
|
|
|
|
hash |
|
|
|
|
block_number |
|
|
|
|
} |
|
|
|
|
cursor |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
""" |
|
|
|
|
|
|
|
|
|
variables2 = %{ |
|
|
|
|
"hash" => to_string(address.hash), |
|
|
|
|
"first" => 3, |
|
|
|
|
"after" => last_cursor_page1 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
conn = get(conn, "/graphql", query: query2, variables: variables2) |
|
|
|
|
|
|
|
|
|
%{"data" => %{"address" => %{"transactions" => page2}}} = json_response(conn, 200) |
|
|
|
|
|
|
|
|
|
assert page2["page_info"] == %{"has_next_page" => true, "has_previous_page" => true} |
|
|
|
|
assert Enum.all?(page2["edges"], &(&1["node"]["block_number"] == second_block.number)) |
|
|
|
|
|
|
|
|
|
last_cursor_page2 = |
|
|
|
|
page2 |
|
|
|
|
|> Map.get("edges") |
|
|
|
|
|> List.last() |
|
|
|
|
|> Map.get("cursor") |
|
|
|
|
|
|
|
|
|
query3 = """ |
|
|
|
|
query ($hash: AddressHash!, $first: Int!, $after: Int!) { |
|
|
|
|
address(hash: $hash) { |
|
|
|
|
transactions(first: $first, after: $after) { |
|
|
|
|
page_info { |
|
|
|
|
has_next_page |
|
|
|
|
has_previous_page |
|
|
|
|
} |
|
|
|
|
edges { |
|
|
|
|
node { |
|
|
|
|
hash |
|
|
|
|
block_number |
|
|
|
|
} |
|
|
|
|
cursor |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
""" |
|
|
|
|
|
|
|
|
|
variables3 = %{ |
|
|
|
|
"hash" => to_string(address.hash), |
|
|
|
|
"first" => 3, |
|
|
|
|
"after" => last_cursor_page2 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
conn = get(conn, "/graphql", query: query3, variables: variables3) |
|
|
|
|
|
|
|
|
|
%{"data" => %{"address" => %{"transactions" => page3}}} = json_response(conn, 200) |
|
|
|
|
|
|
|
|
|
assert page3["page_info"] == %{"has_next_page" => false, "has_previous_page" => true} |
|
|
|
|
assert Enum.all?(page3["edges"], &(&1["node"]["block_number"] == first_block.number)) |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|