parent
94f31a979d
commit
2ba3cc821e
@ -0,0 +1,42 @@ |
||||
.internal-transaction { |
||||
@extend %paper; |
||||
|
||||
&__container { |
||||
padding: explorer-size(-1) explorer-size(0); |
||||
& + & { padding-top: 0; } |
||||
&--title { padding-top: explorer-size(0); } |
||||
} |
||||
|
||||
&__header { @extend %section-header; } |
||||
&__heading { @extend %section-header__heading; } |
||||
&__subheading { @extend %section-header__subheading; } |
||||
&__tabs { @extend %section-tabs; } |
||||
|
||||
&__tab { |
||||
@extend %section-tabs__tab; |
||||
&--active { @extend %section-tabs__tab--active; } |
||||
} |
||||
|
||||
&__attributes { padding: explorer-size(-1) explorer-size(1); } |
||||
&__link { color: explorer-color("blue", "500"); } |
||||
|
||||
&__table { |
||||
@extend %table; |
||||
@include explorer-typography("body1"); |
||||
color: explorer-color("slate", "900"); |
||||
} |
||||
|
||||
&__to-address, &__from-address { |
||||
max-width: explorer-size(1); |
||||
text-overflow: ellipsis; |
||||
overflow: hidden; |
||||
} |
||||
|
||||
&__column-header { @include explorer-typography("body1"); } |
||||
} |
||||
|
||||
@media (min-width: $explorer-breakpoint-lg) { |
||||
&__to-address, &__from-address { |
||||
max-width: explorer-size(6); |
||||
} |
||||
} |
@ -0,0 +1,13 @@ |
||||
defmodule Explorer.EthereumexExtensions do |
||||
@moduledoc """ |
||||
Downloads the trace for a Transaction from a node. |
||||
""" |
||||
|
||||
alias Ethereumex.HttpClient |
||||
|
||||
def trace_transaction(hash) do |
||||
params = [hash, ["trace"]] |
||||
{:ok, trace} = HttpClient.request("trace_replayTransaction", params, []) |
||||
trace |
||||
end |
||||
end |
@ -0,0 +1,67 @@ |
||||
defmodule Explorer.InternalTransactionImporter do |
||||
@moduledoc "Imports a transaction's internal transactions given its hash." |
||||
|
||||
import Ecto.Query |
||||
|
||||
alias Explorer.EthereumexExtensions |
||||
alias Explorer.InternalTransaction |
||||
alias Explorer.Repo |
||||
alias Explorer.Transaction |
||||
|
||||
def import(hash) do |
||||
transaction = find_transaction(hash) |
||||
hash |
||||
|> download_trace |
||||
|> extract_attrs |
||||
|> persist_internal_transactions(transaction) |
||||
end |
||||
|
||||
defp download_trace(hash) do |
||||
EthereumexExtensions.trace_transaction(hash) |
||||
end |
||||
|
||||
defp find_transaction(hash) do |
||||
query = from t in Transaction, |
||||
where: fragment("lower(?)", t.hash) == ^String.downcase(hash), |
||||
limit: 1 |
||||
Repo.one!(query) |
||||
end |
||||
|
||||
defp extract_attrs(attrs) do |
||||
trace = attrs["trace"] |
||||
trace |> Enum.with_index() |> Enum.map(&extract_trace/1) |
||||
end |
||||
|
||||
def extract_trace({trace, index}) do |
||||
%{ |
||||
index: index, |
||||
call_type: trace["action"]["callType"] || trace["type"], |
||||
to_address_id: address_id(trace["action"]["to"] || trace["result"]["address"]), |
||||
from_address_id: address_id(trace["action"]["from"]), |
||||
trace_address: trace["traceAddress"], |
||||
value: trace["action"]["value"] |> decode_integer_field, |
||||
gas: trace["action"]["gas"] |> decode_integer_field, |
||||
gas_used: trace["result"]["gasUsed"] |> decode_integer_field, |
||||
input: trace["action"]["input"], |
||||
output: trace["result"]["output"], |
||||
} |
||||
end |
||||
|
||||
defp persist_internal_transactions(traces, transaction) do |
||||
Enum.map(traces, fn(trace) -> |
||||
trace = Map.merge(trace, %{transaction_id: transaction.id}) |
||||
%InternalTransaction{} |
||||
|> InternalTransaction.changeset(trace) |
||||
|> Repo.insert() |
||||
end) |
||||
end |
||||
|
||||
defp decode_integer_field(hex) do |
||||
{"0x", base_16} = String.split_at(hex, 2) |
||||
String.to_integer(base_16, 16) |
||||
end |
||||
|
||||
defp address_id(hash) do |
||||
Explorer.Address.find_or_create_by_hash(hash).id |
||||
end |
||||
end |
@ -0,0 +1,44 @@ |
||||
defmodule Explorer.InternalTransaction do |
||||
@moduledoc "Models internal transactions." |
||||
|
||||
use Ecto.Schema |
||||
|
||||
import Ecto.Changeset |
||||
|
||||
alias Explorer.InternalTransaction |
||||
alias Explorer.Transaction |
||||
alias Explorer.Address |
||||
|
||||
@timestamps_opts [type: Timex.Ecto.DateTime, |
||||
autogenerate: {Timex.Ecto.DateTime, :autogenerate, []}] |
||||
|
||||
schema "internal_transactions" do |
||||
belongs_to :transaction, Transaction |
||||
belongs_to :from_address, Address |
||||
belongs_to :to_address, Address |
||||
field :index, :integer |
||||
field :call_type, :string |
||||
field :trace_address, {:array, :integer} |
||||
field :value, :decimal |
||||
field :gas, :decimal |
||||
field :gas_used, :decimal |
||||
field :input, :string |
||||
field :output, :string |
||||
timestamps() |
||||
end |
||||
|
||||
@required_attrs ~w(index call_type trace_address value gas gas_used |
||||
transaction_id from_address_id to_address_id)a |
||||
@optional_attrs ~w(input output) |
||||
|
||||
def changeset(%InternalTransaction{} = internal_transaction, attrs \\ %{}) do |
||||
internal_transaction |
||||
|> cast(attrs, @required_attrs ++ @optional_attrs) |
||||
|> validate_required(@required_attrs) |
||||
|> foreign_key_constraint(:transaction_id) |
||||
|> foreign_key_constraint(:to_address_id) |
||||
|> foreign_key_constraint(:from_address_id) |
||||
end |
||||
|
||||
def null, do: %InternalTransaction{} |
||||
end |
@ -0,0 +1,32 @@ |
||||
defmodule Explorer.Transaction.Service do |
||||
|
||||
alias Explorer.InternalTransaction |
||||
alias Explorer.Repo.NewRelic, as: Repo |
||||
alias Explorer.Transaction.Service.Query |
||||
|
||||
def internal_transactions_from_transaction_hash(hash) do |
||||
InternalTransaction |
||||
|> Query.for_transaction(hash) |
||||
|> Query.join_from_and_to_addresses() |
||||
|> Repo.all() |
||||
end |
||||
|
||||
defmodule Query do |
||||
|
||||
import Ecto.Query, only: [from: 2] |
||||
|
||||
def for_transaction(query, hash) do |
||||
from(child in query, |
||||
inner_join: transaction in assoc(child, :transaction), |
||||
where: fragment("lower(?)", transaction.hash) == ^String.downcase(hash) |
||||
) |
||||
end |
||||
|
||||
def join_from_and_to_addresses(query) do |
||||
from(q in query, |
||||
inner_join: to_address in assoc(q, :to_address), |
||||
inner_join: from_address in assoc(q, :from_address), |
||||
preload: [:to_address, :from_address]) |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,13 @@ |
||||
defmodule ExplorerWeb.InternalTransactionController do |
||||
use ExplorerWeb, :controller |
||||
|
||||
alias Explorer.Transaction.Service, as: Transaction |
||||
|
||||
def index(conn, %{"transaction_id" => transaction_id}) do |
||||
hash = String.downcase(transaction_id) |
||||
|
||||
internal_transactions = Transaction.internal_transactions_from_transaction_hash(hash) |
||||
|
||||
render(conn, internal_transactions: internal_transactions, transaction_hash: hash) |
||||
end |
||||
end |
@ -0,0 +1,43 @@ |
||||
<section class="container__section transaction"> |
||||
<div class="transaction__header"> |
||||
<h1 class="transaction__heading"><%= gettext "Internal Transactions" %></h1> |
||||
<h3 class="transaction__subheading"><%= @transaction_hash %></h3> |
||||
</div> |
||||
<div class="transaction__container"> |
||||
<div class="transaction__tabs"> |
||||
<h2 class="transaction__tab"><%= link(gettext("Overview"), to: transaction_path(@conn, :show, @conn.assigns.locale, @transaction_hash), class: "transaction__link") %></h2> |
||||
<h2 class="transaction__tab transaction__tab--active"><%= link(gettext("Internal Transactions"), to: transaction_internal_transaction_path(@conn, :index, @conn.assigns.locale, @transaction_hash), class: "transaction__link transaction__link--active") %></h2> |
||||
<h2 class="transaction__tab"><%= link(gettext("Logs"), to: transaction_log_path(@conn, :index, @conn.assigns.locale, @transaction_hash), class: "transaction__link") %></h2> |
||||
</div> |
||||
<div class="internal-transaction__container"> |
||||
<table class="internal-transaction__table"> |
||||
<thead> |
||||
<th class="internal-transaction__column-header"><%= gettext "Type" %></th> |
||||
<th class="internal-transaction__column-header"><%= gettext "From" %></th> |
||||
<th class="internal-transaction__column-header"><%= gettext "To" %></th> |
||||
<th class="internal-transaction__column-header"><%= gettext "Value" %></th> |
||||
<th class="internal-transaction__column-header"><%= gettext "Gas Limit" %></th> |
||||
</thead> |
||||
<%= for transaction <- @internal_transactions do %> |
||||
<tgroup> |
||||
<tr> |
||||
<td><%= transaction.call_type %></td> |
||||
<td class="internal-transaction__to-address"> |
||||
<%= link(transaction.to_address.hash, |
||||
to: address_path(@conn, :show, @conn.assigns.locale, transaction.to_address.hash), |
||||
class: "transaction-log__link") %> |
||||
</td> |
||||
<td class="internal-transaction__from-address"> |
||||
<%= link(transaction.from_address.hash, |
||||
to: address_path(@conn, :show, @conn.assigns.locale, transaction.from_address.hash), |
||||
class: "transaction-log__link") %> |
||||
</td> |
||||
<td><%= transaction.value %></td> |
||||
<td><%= ExplorerWeb.TransactionView.format_gas_limit(transaction.gas) %></td> |
||||
</tr> |
||||
</tgroup> |
||||
<% end %> |
||||
</table> |
||||
</div> |
||||
</div> |
||||
</section> |
@ -0,0 +1,4 @@ |
||||
defmodule ExplorerWeb.InternalTransactionView do |
||||
use ExplorerWeb, :view |
||||
@dialyzer :no_match |
||||
end |
@ -1,4 +1,9 @@ |
||||
defmodule ExplorerWeb.TransactionView do |
||||
use ExplorerWeb, :view |
||||
@dialyzer :no_match |
||||
|
||||
def format_gas_limit(gas) do |
||||
gas |
||||
|> Cldr.Number.to_string! |
||||
end |
||||
end |
||||
|
@ -0,0 +1,24 @@ |
||||
defmodule Explorer.Repo.Migrations.CreateInternalTransactions do |
||||
use Ecto.Migration |
||||
|
||||
def change do |
||||
create table(:internal_transactions) do |
||||
add :transaction_id, references(:transactions), null: false |
||||
add :to_address_id, references(:addresses), null: false |
||||
add :from_address_id, references(:addresses), null: false |
||||
add :index, :integer, null: false |
||||
add :call_type, :string, null: false |
||||
add :trace_address, {:array, :integer}, null: false |
||||
add :value, :numeric, precision: 100, null: false |
||||
add :gas, :numeric, precision: 100, null: false |
||||
add :gas_used, :numeric, precision: 100, null: false |
||||
add :input, :string |
||||
add :output, :string |
||||
timestamps null: false |
||||
end |
||||
|
||||
create index(:internal_transactions, :transaction_id) |
||||
create index(:internal_transactions, :to_address_id) |
||||
create index(:internal_transactions, :from_address_id) |
||||
end |
||||
end |
@ -0,0 +1,14 @@ |
||||
defmodule Explorer.EthereumexExtensionsTest do |
||||
use Explorer.DataCase |
||||
alias Explorer.EthereumexExtensions |
||||
|
||||
describe "trace_transaction/1" do |
||||
test "returns a transaction trace" do |
||||
use_cassette "ethereumex_extensions_trace_transaction_1" do |
||||
hash = "0x051e031f05b3b3a5ff73e1189c36e3e2a41fd1c2d9772b2c75349e22ed4d3f68" |
||||
result = EthereumexExtensions.trace_transaction(hash) |
||||
assert(is_list(result["trace"])) |
||||
end |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,78 @@ |
||||
defmodule Explorer.InternalTransactionImporterTest do |
||||
use Explorer.DataCase |
||||
|
||||
alias Explorer.InternalTransaction |
||||
alias Explorer.InternalTransactionImporter |
||||
|
||||
describe "import/1" do |
||||
test "imports and saves an internal transaction to the database" do |
||||
use_cassette "internal_transaction_importer_import_1" do |
||||
transaction = insert(:transaction, hash: "0x051e031f05b3b3a5ff73e1189c36e3e2a41fd1c2d9772b2c75349e22ed4d3f68") |
||||
InternalTransactionImporter.import(transaction.hash) |
||||
internal_transactions = InternalTransaction |> Repo.all() |
||||
assert length(internal_transactions) == 2 |
||||
end |
||||
end |
||||
|
||||
test "imports internal transactions with ordered indexes" do |
||||
use_cassette "internal_transaction_importer_import_1" do |
||||
transaction = insert(:transaction, hash: "0x051e031f05b3b3a5ff73e1189c36e3e2a41fd1c2d9772b2c75349e22ed4d3f68") |
||||
InternalTransactionImporter.import(transaction.hash) |
||||
last_internal_transaction = InternalTransaction |> order_by(desc: :index) |> limit(1) |> Repo.one() |
||||
assert last_internal_transaction.index == 1 |
||||
end |
||||
end |
||||
|
||||
test "imports an internal transaction that creates a contract" do |
||||
use_cassette "internal_transaction_importer_import_1_with_contract_creation" do |
||||
transaction = insert(:transaction, hash: "0x27d64b8e8564d2852c88767e967b88405c99341509cd3a3504fd67a65277116d") |
||||
InternalTransactionImporter.import(transaction.hash) |
||||
last_internal_transaction = InternalTransaction |> order_by(desc: :index) |> limit(1) |> Repo.one() |
||||
assert last_internal_transaction.call_type == "create" |
||||
end |
||||
end |
||||
|
||||
test "import fails if a transaction with the hash doesn't exist" do |
||||
hash = "0x051e031f05b3b3a5ff73e1189c36e3e2a41fd1c2d9772b2c75349e22ed4d3f68" |
||||
assert_raise Ecto.NoResultsError, fn -> InternalTransactionImporter.import(hash) end |
||||
end |
||||
end |
||||
|
||||
describe "extract_trace" do |
||||
test "maps attributes to database record attributes when the trace is a call" do |
||||
trace = %{ |
||||
"action" => %{ |
||||
"callType" => "call", |
||||
"from" => "0xba9f067abbc4315ece8eb33e7a3d01030bb368ef", |
||||
"gas" => "0x4821f", |
||||
"input" => "0xd1f276d3", |
||||
"to" => "0xe213402e637565bb9de0651827517e7554693f53", |
||||
"value" => "0x0", |
||||
}, |
||||
"result" => %{ |
||||
"gasUsed" => "0x4e4", |
||||
"output" => "0x000000000000000000000000ba9f067abbc4315ece8eb33e7a3d01030bb368ef" |
||||
}, |
||||
"subtraces" => 0, |
||||
"traceAddress" => [2, 0], |
||||
"type" => "call" |
||||
} |
||||
|
||||
to_address = insert(:address, hash: "0xe213402e637565bb9de0651827517e7554693f53") |
||||
from_address = insert(:address, hash: "0xba9f067abbc4315ece8eb33e7a3d01030bb368ef") |
||||
|
||||
assert(InternalTransactionImporter.extract_trace({trace, 2}) == %{ |
||||
index: 2, |
||||
to_address_id: to_address.id, |
||||
from_address_id: from_address.id, |
||||
call_type: "call", |
||||
trace_address: [2, 0], |
||||
value: 0, |
||||
gas: 295455, |
||||
gas_used: 1252, |
||||
input: "0xd1f276d3", |
||||
output: "0x000000000000000000000000ba9f067abbc4315ece8eb33e7a3d01030bb368ef", |
||||
}) |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,24 @@ |
||||
defmodule Explorer.InternalTransactionTest do |
||||
use Explorer.DataCase |
||||
|
||||
alias Explorer.InternalTransaction |
||||
|
||||
describe "changeset/2" do |
||||
test "with valid attributes" do |
||||
transaction = insert(:transaction) |
||||
changeset = InternalTransaction.changeset(%InternalTransaction{}, %{transaction_id: transaction.id, index: 0, call_type: "call", trace_address: [0, 1], value: 100, gas: 100, gas_used: 100, input: "pintos", output: "refried", to_address_id: 1, from_address_id: 2}) |
||||
assert changeset.valid? |
||||
end |
||||
|
||||
test "with invalid attributes" do |
||||
changeset = InternalTransaction.changeset(%InternalTransaction{}, %{falala: "falafel"}) |
||||
refute changeset.valid? |
||||
end |
||||
|
||||
test "that a valid changeset is persistable" do |
||||
transaction = insert(:transaction) |
||||
changeset = InternalTransaction.changeset(%InternalTransaction{}, %{transaction: transaction, index: 0, call_type: "call", trace_address: [0, 1], value: 100, gas: 100, gas_used: 100, input: "thin-mints", output: "munchos"}) |
||||
assert Repo.insert(changeset) |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,16 @@ |
||||
defmodule Explorer.Transaction.ServiceTest do |
||||
use Explorer.DataCase |
||||
|
||||
alias Explorer.Transaction.Service |
||||
|
||||
describe "internal_transactions_from_transaction_hash/1" do |
||||
test "it returns all internal transactions for a given hash" do |
||||
transaction = insert(:transaction) |
||||
internal_transaction = insert(:internal_transaction, transaction_id: transaction.id) |
||||
|
||||
result = hd(Service.internal_transactions_from_transaction_hash(transaction.hash)) |
||||
|
||||
assert result.id == internal_transaction.id |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,22 @@ |
||||
defmodule ExplorerWeb.InternalTransactionControllerTest do |
||||
use ExplorerWeb.ConnCase |
||||
|
||||
import ExplorerWeb.Router.Helpers, only: [transaction_internal_transaction_path: 4] |
||||
|
||||
describe "GET index/2" do |
||||
test "returns internal transactions for the transaction", %{conn: conn} do |
||||
transaction = insert(:transaction) |
||||
internal_transaction = insert(:internal_transaction, transaction_id: transaction.id) |
||||
|
||||
path = |
||||
transaction_internal_transaction_path(ExplorerWeb.Endpoint, :index, :en, transaction.hash) |
||||
|
||||
conn = get(conn, path) |
||||
|
||||
first_internal_transaction = List.first(conn.assigns.internal_transactions) |
||||
|
||||
assert conn.assigns.transaction_hash == transaction.hash |
||||
assert first_internal_transaction.id == internal_transaction.id |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,21 @@ |
||||
defmodule Explorer.InternalTransactionFactory do |
||||
defmacro __using__(_opts) do |
||||
quote do |
||||
def internal_transaction_factory do |
||||
%Explorer.InternalTransaction{ |
||||
index: Enum.random(0..9), |
||||
call_type: Enum.random(["call", "creates", "calldelegate"]), |
||||
trace_address: [Enum.random(0..4), Enum.random(0..4)], |
||||
from_address_id: insert(:address).id, |
||||
to_address_id: insert(:address).id, |
||||
transaction_id: insert(:transaction).id, |
||||
value: Enum.random(1..100_000), |
||||
gas: Enum.random(1..100_000), |
||||
gas_used: Enum.random(1..100_000), |
||||
input: sequence("0x"), |
||||
output: sequence("0x"), |
||||
} |
||||
end |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,30 @@ |
||||
[ |
||||
{ |
||||
"request": { |
||||
"body": "{\"params\":[\"0x051e031f05b3b3a5ff73e1189c36e3e2a41fd1c2d9772b2c75349e22ed4d3f68\",[\"trace\"]],\"method\":\"trace_replayTransaction\",\"jsonrpc\":\"2.0\",\"id\":0}", |
||||
"headers": { |
||||
"Content-Type": "application/json" |
||||
}, |
||||
"method": "post", |
||||
"options": [], |
||||
"request_body": "", |
||||
"url": "https://sokol-trace.poa.network" |
||||
}, |
||||
"response": { |
||||
"binary": false, |
||||
"body": "{\"jsonrpc\":\"2.0\",\"result\":{\"output\":\"0x\",\"stateDiff\":null,\"trace\":[{\"action\":{\"callType\":\"call\",\"from\":\"0x82e4e61e7f5139ff0a4157a5bc687ef42294c248\",\"gas\":\"0x63dc\",\"input\":\"0x\",\"to\":\"0x0e8a835861fe709b6100f83628debbc353342734\",\"value\":\"0xf95b28cd2c38000\"},\"result\":{\"gasUsed\":\"0x24a0\",\"output\":\"0x\"},\"subtraces\":1,\"traceAddress\":[],\"type\":\"call\"},{\"action\":{\"callType\":\"call\",\"from\":\"0x0e8a835861fe709b6100f83628debbc353342734\",\"gas\":\"0x8fc\",\"input\":\"0x\",\"to\":\"0x0039f22efb07a647557c7c5d17854cfd6d489ef3\",\"value\":\"0xf95b28cd2c38000\"},\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":0,\"traceAddress\":[0],\"type\":\"call\"}],\"vmTrace\":null},\"id\":0}\n", |
||||
"headers": { |
||||
"Date": "Tue, 20 Feb 2018 22:24:43 GMT", |
||||
"Content-Type": "application/json", |
||||
"Transfer-Encoding": "chunked", |
||||
"Connection": "keep-alive", |
||||
"Set-Cookie": "__cfduid=da335ec956341b09d9fbfd8d02718b03d1519165483; expires=Wed, 20-Feb-19 22:24:43 GMT; path=/; domain=.poa.network; HttpOnly; Secure", |
||||
"Expect-CT": "max-age=604800, report-uri=\"https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct\"", |
||||
"Server": "cloudflare", |
||||
"CF-RAY": "3f04e0b09f386c04-SJC" |
||||
}, |
||||
"status_code": 200, |
||||
"type": "ok" |
||||
} |
||||
} |
||||
] |
@ -0,0 +1,30 @@ |
||||
[ |
||||
{ |
||||
"request": { |
||||
"body": "{\"params\":[\"0x051e031f05b3b3a5ff73e1189c36e3e2a41fd1c2d9772b2c75349e22ed4d3f68\",[\"trace\"]],\"method\":\"trace_replayTransaction\",\"jsonrpc\":\"2.0\",\"id\":0}", |
||||
"headers": { |
||||
"Content-Type": "application/json" |
||||
}, |
||||
"method": "post", |
||||
"options": [], |
||||
"request_body": "", |
||||
"url": "https://sokol-trace.poa.network" |
||||
}, |
||||
"response": { |
||||
"binary": false, |
||||
"body": "{\"jsonrpc\":\"2.0\",\"result\":{\"output\":\"0x\",\"stateDiff\":null,\"trace\":[{\"action\":{\"callType\":\"call\",\"from\":\"0x82e4e61e7f5139ff0a4157a5bc687ef42294c248\",\"gas\":\"0x63dc\",\"input\":\"0x\",\"to\":\"0x0e8a835861fe709b6100f83628debbc353342734\",\"value\":\"0xf95b28cd2c38000\"},\"result\":{\"gasUsed\":\"0x24a0\",\"output\":\"0x\"},\"subtraces\":1,\"traceAddress\":[],\"type\":\"call\"},{\"action\":{\"callType\":\"call\",\"from\":\"0x0e8a835861fe709b6100f83628debbc353342734\",\"gas\":\"0x8fc\",\"input\":\"0x\",\"to\":\"0x0039f22efb07a647557c7c5d17854cfd6d489ef3\",\"value\":\"0xf95b28cd2c38000\"},\"result\":{\"gasUsed\":\"0x0\",\"output\":\"0x\"},\"subtraces\":0,\"traceAddress\":[0],\"type\":\"call\"}],\"vmTrace\":null},\"id\":0}\n", |
||||
"headers": { |
||||
"Date": "Wed, 21 Feb 2018 20:18:17 GMT", |
||||
"Content-Type": "application/json", |
||||
"Transfer-Encoding": "chunked", |
||||
"Connection": "keep-alive", |
||||
"Set-Cookie": "__cfduid=d8935c4b5e8d5f4d7472de76debcc87921519244296; expires=Thu, 21-Feb-19 20:18:16 GMT; path=/; domain=.poa.network; HttpOnly; Secure", |
||||
"Expect-CT": "max-age=604800, report-uri=\"https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct\"", |
||||
"Server": "cloudflare", |
||||
"CF-RAY": "3f0c64d82a9493fc-SJC" |
||||
}, |
||||
"status_code": 200, |
||||
"type": "ok" |
||||
} |
||||
} |
||||
] |
@ -0,0 +1 @@ |
||||
[] |
@ -0,0 +1,30 @@ |
||||
[ |
||||
{ |
||||
"request": { |
||||
"body": "{\"params\":[\"0x27d64b8e8564d2852c88767e967b88405c99341509cd3a3504fd67a65277116d\",[\"trace\"]],\"method\":\"trace_replayTransaction\",\"jsonrpc\":\"2.0\",\"id\":0}", |
||||
"headers": { |
||||
"Content-Type": "application/json" |
||||
}, |
||||
"method": "post", |
||||
"options": [], |
||||
"request_body": "", |
||||
"url": "https://sokol-trace.poa.network" |
||||
}, |
||||
"response": { |
||||
"binary": false, |
||||
"body": "{\"jsonrpc\":\"2.0\",\"result\":{\"output\":\"0x606060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063557ed1ba146044575b600080fd5b3415604e57600080fd5b6054606a565b6040518082815260200191505060405180910390f35b6000429050905600a165627a7a7230582053883c0c39da080adc15a91094921659c200b3bb60aed9e49b79b0274da3f4010029\",\"stateDiff\":null,\"trace\":[{\"action\":{\"from\":\"0x4349bb5579700d2a515cfef9cbdb7bc7f881cdd0\",\"gas\":\"0x273a9\",\"init\":\"0x6060604052341561000f57600080fd5b7fb94ae47ec9f4248692e2ecf9740b67ab493f3dcc8452bedc7d9cd911c28d1ca5426040518082815260200191505060405180910390a1609e806100546000396000f300606060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063557ed1ba146044575b600080fd5b3415604e57600080fd5b6054606a565b6040518082815260200191505060405180910390f35b6000429050905600a165627a7a7230582053883c0c39da080adc15a91094921659c200b3bb60aed9e49b79b0274da3f4010029\",\"value\":\"0x0\"},\"result\":{\"address\":\"0xa8bf4dc1f90efdfd9479d7c633612dfe48589535\",\"code\":\"0x606060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063557ed1ba146044575b600080fd5b3415604e57600080fd5b6054606a565b6040518082815260200191505060405180910390f35b6000429050905600a165627a7a7230582053883c0c39da080adc15a91094921659c200b3bb60aed9e49b79b0274da3f4010029\",\"gasUsed\":\"0x7fe0\"},\"subtraces\":0,\"traceAddress\":[],\"type\":\"create\"}],\"vmTrace\":null},\"id\":0}\n", |
||||
"headers": { |
||||
"Date": "Thu, 22 Feb 2018 23:21:11 GMT", |
||||
"Content-Type": "application/json", |
||||
"Transfer-Encoding": "chunked", |
||||
"Connection": "keep-alive", |
||||
"Set-Cookie": "__cfduid=d0ba210a5363b8aa64b7a5482d937d6ac1519341670; expires=Fri, 22-Feb-19 23:21:10 GMT; path=/; domain=.poa.network; HttpOnly; Secure", |
||||
"Expect-CT": "max-age=604800, report-uri=\"https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct\"", |
||||
"Server": "cloudflare", |
||||
"CF-RAY": "3f15ae22cfb36bfe-SJC" |
||||
}, |
||||
"status_code": 200, |
||||
"type": "ok" |
||||
} |
||||
} |
||||
] |
Loading…
Reference in new issue