Improve transaction#getstatus API endpoint

Why:

* To increase the accuracy of `transaction#getstatus` API endpoint
results.
* Issue link: https://github.com/poanetwork/blockscout/issues/743

This change addresses the need by:

* Editing `transaction#getstatus` API endpoint to use the recently added
`Chain.transaction_to_status/1` function. This improves the accuracy of
the errors by providing a reason of `awaiting internal transactions` for
transactions with a failed status but for which the final "real" error
message will only become available after processing the internal
transactions.
* Deleting `Explorer.Etherscan.get_transaction_error/1`. It's no longer
needed.
pull/756/head
Sebastian Abondano 6 years ago
parent 0ba232b8c8
commit 36d3d95e68
  1. 13
      apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/transaction_controller.ex
  2. 11
      apps/block_scout_web/lib/block_scout_web/views/api/rpc/transaction_view.ex
  3. 49
      apps/block_scout_web/test/block_scout_web/controllers/api/rpc/transaction_controller_test.exs
  4. 18
      apps/explorer/lib/explorer/etherscan.ex
  5. 32
      apps/explorer/test/explorer/etherscan_test.exs

@ -1,7 +1,7 @@
defmodule BlockScoutWeb.API.RPC.TransactionController do
use BlockScoutWeb, :controller
alias Explorer.{Chain, Etherscan}
alias Explorer.Chain
def gettxreceiptstatus(conn, params) do
with {:txhash_param, {:ok, txhash_param}} <- fetch_txhash(params),
@ -20,7 +20,7 @@ defmodule BlockScoutWeb.API.RPC.TransactionController do
def getstatus(conn, params) do
with {:txhash_param, {:ok, txhash_param}} <- fetch_txhash(params),
{:format, {:ok, transaction_hash}} <- to_transaction_hash(txhash_param) do
error = Etherscan.get_transaction_error(transaction_hash)
error = to_transaction_error(transaction_hash)
render(conn, :getstatus, %{error: error})
else
{:txhash_param, :error} ->
@ -45,4 +45,13 @@ defmodule BlockScoutWeb.API.RPC.TransactionController do
{:ok, transaction} -> transaction.status
end
end
defp to_transaction_error(transaction_hash) do
with {:ok, transaction} <- Chain.hash_to_transaction(transaction_hash),
{:error, error} <- Chain.transaction_to_status(transaction) do
error
else
_ -> ""
end
end
end

@ -24,17 +24,24 @@ defmodule BlockScoutWeb.API.RPC.TransactionView do
defp prepare_tx_receipt_status(_), do: "0"
defp prepare_error(nil) do
defp prepare_error("") do
%{
"isError" => "0",
"errDescription" => ""
}
end
defp prepare_error(error) do
defp prepare_error(error) when is_binary(error) do
%{
"isError" => "1",
"errDescription" => error
}
end
defp prepare_error(error) when is_atom(error) do
%{
"isError" => "1",
"errDescription" => error |> Atom.to_string() |> String.replace("_", " ")
}
end
end

@ -209,17 +209,25 @@ defmodule BlockScoutWeb.API.RPC.TransactionControllerTest do
assert response["message"] == "OK"
end
test "with a txhash with error status", %{conn: conn} do
test "with a txhash with error", %{conn: conn} do
error = "some error"
transaction_details = [
status: :error,
error: error,
internal_transactions_indexed_at: DateTime.utc_now()
]
transaction =
:transaction
|> insert()
|> with_block(status: :error)
|> with_block(transaction_details)
internal_transaction_details = [
transaction: transaction,
index: 0,
type: :reward,
error: "some error"
error: error
]
insert(:internal_transaction, internal_transaction_details)
@ -232,7 +240,40 @@ defmodule BlockScoutWeb.API.RPC.TransactionControllerTest do
expected_result = %{
"isError" => "1",
"errDescription" => "some error"
"errDescription" => error
}
response =
conn
|> get("/api", params)
|> json_response(200)
assert response["result"] == expected_result
assert response["status"] == "1"
assert response["message"] == "OK"
end
test "with a txhash with failed status but awaiting internal transactions", %{conn: conn} do
transaction_details = [
status: :error,
error: nil,
internal_transactions_indexed_at: nil
]
transaction =
:transaction
|> insert()
|> with_block(transaction_details)
params = %{
"module" => "transaction",
"action" => "getstatus",
"txhash" => "#{transaction.hash}"
}
expected_result = %{
"isError" => "1",
"errDescription" => "awaiting internal transactions"
}
assert response =

@ -183,24 +183,6 @@ defmodule Explorer.Etherscan do
Repo.one(query)
end
@doc """
Gets the error for a given transaction hash
(`t:Explorer.Chain.Hash.Full.t/0`). Returns nil if no error is found.
"""
@spec get_transaction_error(Hash.Full.t()) :: String.t() | nil
def get_transaction_error(%Hash{byte_count: unquote(Hash.Full.byte_count())} = transaction_hash) do
query =
from(it in InternalTransaction,
where: it.transaction_hash == ^transaction_hash,
order_by: [desc: :index],
limit: 1,
select: it.error
)
Repo.one(query)
end
@transaction_fields ~w(
block_hash
block_number

@ -1103,36 +1103,4 @@ defmodule Explorer.EtherscanTest do
assert found_token_balance.id == token_balance2.id
end
end
describe "get_transaction_error/1" do
test "with a transaction that doesn't exist" do
transaction = build(:transaction)
refute Etherscan.get_transaction_error(transaction.hash)
end
test "with a transaction with no errors" do
transaction = insert(:transaction)
refute Etherscan.get_transaction_error(transaction.hash)
end
test "with a transaction with an error" do
transaction =
:transaction
|> insert()
|> with_block(status: :error)
internal_transaction_details = [
transaction: transaction,
index: 0,
type: :reward,
error: "some error"
]
insert(:internal_transaction, internal_transaction_details)
assert Etherscan.get_transaction_error(transaction.hash) == "some error"
end
end
end

Loading…
Cancel
Save