Merge pull request #3000 from poanetwork/vb-first-trace-of-trivial-tx

Get rid of storing of first trace for all types of transactions for Parity variant
pull/3026/head
Victor Baranov 5 years ago committed by GitHub
commit 77de43be16
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      CHANGELOG.md
  2. 159
      apps/explorer/lib/explorer/chain/import/runner/internal_transactions.ex
  3. 171
      apps/explorer/test/explorer/chain/import/runner/internal_transactions_test.exs
  4. 232
      apps/explorer/test/explorer/chain/import_test.exs
  5. 14
      apps/explorer/test/explorer/chain_test.exs
  6. 14
      apps/indexer/config/test.exs
  7. 8
      apps/indexer/config/test/ganache.exs
  8. 8
      apps/indexer/config/test/geth.exs
  9. 8
      apps/indexer/config/test/parity.exs
  10. 8
      apps/indexer/config/test/rsk.exs
  11. 19
      apps/indexer/test/indexer/fetcher/internal_transaction_test.exs

@ -2,6 +2,7 @@
### Features ### Features
- [#3013](https://github.com/poanetwork/blockscout/pull/3013) - Raw trace of transaction on-demand - [#3013](https://github.com/poanetwork/blockscout/pull/3013) - Raw trace of transaction on-demand
- [#3000](https://github.com/poanetwork/blockscout/pull/3000) - Get rid of storing of internal transactions for simple coin transfers
- [#2875](https://github.com/poanetwork/blockscout/pull/2875) - Save contract code from Parity genesis file - [#2875](https://github.com/poanetwork/blockscout/pull/2875) - Save contract code from Parity genesis file
- [#2834](https://github.com/poanetwork/blockscout/pull/2834) - always redirect to checksummed hash - [#2834](https://github.com/poanetwork/blockscout/pull/2834) - always redirect to checksummed hash

@ -65,19 +65,40 @@ defmodule Explorer.Chain.Import.Runner.InternalTransactions do
|> Multi.run(:invalid_block_numbers, fn _, %{acquire_transactions: transactions} -> |> Multi.run(:invalid_block_numbers, fn _, %{acquire_transactions: transactions} ->
invalid_block_numbers(transactions, internal_transactions_params) invalid_block_numbers(transactions, internal_transactions_params)
end) end)
|> Multi.run(:valid_internal_transactions_without_first_traces_of_trivial_transactions, fn _,
%{
acquire_transactions:
transactions,
invalid_block_numbers:
invalid_block_numbers
} ->
valid_internal_transactions_without_first_trace(
transactions,
internal_transactions_params,
invalid_block_numbers
)
end)
|> Multi.run(:valid_internal_transactions, fn _, |> Multi.run(:valid_internal_transactions, fn _,
%{ %{
acquire_transactions: transactions, acquire_transactions: transactions,
invalid_block_numbers: invalid_block_numbers invalid_block_numbers: invalid_block_numbers
} -> } ->
valid_internal_transactions(transactions, internal_transactions_params, invalid_block_numbers) valid_internal_transactions(
transactions,
internal_transactions_params,
invalid_block_numbers
)
end) end)
|> Multi.run(:remove_left_over_internal_transactions, fn repo, |> Multi.run(:remove_left_over_internal_transactions, fn repo,
%{valid_internal_transactions: valid_internal_transactions} -> %{valid_internal_transactions: valid_internal_transactions} ->
remove_left_over_internal_transactions(repo, valid_internal_transactions) remove_left_over_internal_transactions(repo, valid_internal_transactions)
end) end)
|> Multi.run(:internal_transactions, fn repo, %{valid_internal_transactions: valid_internal_transactions} -> |> Multi.run(:internal_transactions, fn repo,
insert(repo, valid_internal_transactions, insert_options) %{
valid_internal_transactions_without_first_traces_of_trivial_transactions:
valid_internal_transactions_without_first_traces_of_trivial_transactions
} ->
insert(repo, valid_internal_transactions_without_first_traces_of_trivial_transactions, insert_options)
end) end)
|> Multi.run(:update_transactions, fn repo, %{valid_internal_transactions: valid_internal_transactions} -> |> Multi.run(:update_transactions, fn repo, %{valid_internal_transactions: valid_internal_transactions} ->
update_transactions(repo, valid_internal_transactions, update_transactions_options) update_transactions(repo, valid_internal_transactions, update_transactions_options)
@ -291,6 +312,31 @@ defmodule Explorer.Chain.Import.Runner.InternalTransactions do
{:ok, valid_internal_txs} {:ok, valid_internal_txs}
end end
defp valid_internal_transactions_without_first_trace(
transactions,
internal_transactions_params,
invalid_block_numbers
) do
with {:ok, valid_internal_txs} <-
valid_internal_transactions(transactions, internal_transactions_params, invalid_block_numbers) do
json_rpc_named_arguments = Application.fetch_env!(:indexer, :json_rpc_named_arguments)
variant = Keyword.fetch!(json_rpc_named_arguments, :variant)
# we exclude first traces from storing in the DB only in case of Parity variant (Parity/Nethermind). todo: to the same for Geth
if variant == EthereumJSONRPC.Parity do
valid_internal_txs_without_first_trace =
valid_internal_txs
|> Enum.reject(fn trace ->
trace[:index] == 0
end)
{:ok, valid_internal_txs_without_first_trace}
else
{:ok, valid_internal_txs}
end
end
end
def defer_internal_transactions_primary_key(repo) do def defer_internal_transactions_primary_key(repo) do
# Allows internal_transactions primary key to not be checked during the # Allows internal_transactions primary key to not be checked during the
# DB transactions and instead be checked only at the end of it. # DB transactions and instead be checked only at the end of it.
@ -317,7 +363,7 @@ defmodule Explorer.Chain.Import.Runner.InternalTransactions do
or_where(acc, [it], it.block_hash == ^block_hash and it.block_index > ^max_index) or_where(acc, [it], it.block_hash == ^block_hash and it.block_index > ^max_index)
end) end)
# removes old recoreds with the same primary key (transaction hash, transaction index) # removes old records with the same primary key (transaction hash, transaction index)
delete_query = delete_query =
valid_internal_transactions valid_internal_transactions
|> Enum.map(fn params -> {params.transaction_hash, params.index} end) |> Enum.map(fn params -> {params.transaction_hash, params.index} end)
@ -338,49 +384,72 @@ defmodule Explorer.Chain.Import.Runner.InternalTransactions do
defp update_transactions(repo, valid_internal_transactions, %{ defp update_transactions(repo, valid_internal_transactions, %{
timeout: timeout, timeout: timeout,
timestamps: timestamps timestamps: timestamps
}) }) do
when is_list(valid_internal_transactions) do valid_internal_transactions_count = Enum.count(valid_internal_transactions)
transaction_hashes =
valid_internal_transactions if valid_internal_transactions_count == 0 do
|> MapSet.new(& &1.transaction_hash) {:ok, nil}
|> MapSet.to_list() else
params =
update_query = valid_internal_transactions
from( |> Enum.filter(fn internal_tx ->
t in Transaction, internal_tx[:index] == 0
where: t.hash in ^transaction_hashes, end)
# ShareLocks order already enforced by `acquire_transactions` (see docs: sharelocks.md) |> Enum.map(fn trace ->
update: [ %{
set: [ transaction_hash: Map.get(trace, :transaction_hash),
created_contract_address_hash: created_contract_address_hash: Map.get(trace, :created_contract_address_hash),
fragment( error: Map.get(trace, :error),
"(SELECT it.created_contract_address_hash FROM internal_transactions AS it WHERE it.transaction_hash = ? ORDER BY it.index ASC LIMIT 1)", status: if(is_nil(Map.get(trace, :error)), do: :ok, else: :error)
t.hash }
), end)
error: |> Enum.filter(fn transaction_hash -> transaction_hash != nil end)
fragment(
"(SELECT it.error FROM internal_transactions AS it WHERE it.transaction_hash = ? ORDER BY it.index ASC LIMIT 1)", transaction_hashes =
t.hash valid_internal_transactions
), |> MapSet.new(& &1.transaction_hash)
status: |> MapSet.to_list()
fragment(
"CASE WHEN (SELECT it.error FROM internal_transactions AS it WHERE it.transaction_hash = ? ORDER BY it.index ASC LIMIT 1) IS NULL THEN ? ELSE ? END", result =
t.hash, Enum.reduce_while(params, 0, fn first_trace, transaction_hashes_iterator ->
type(^:ok, t.status), update_query =
type(^:error, t.status) from(
), t in Transaction,
updated_at: ^timestamps.updated_at where: t.hash == ^first_trace.transaction_hash,
] # ShareLocks order already enforced by `acquire_transactions` (see docs: sharelocks.md)
] update: [
) set: [
created_contract_address_hash: ^first_trace.created_contract_address_hash,
error: ^first_trace.error,
status: ^first_trace.status,
updated_at: ^timestamps.updated_at
]
]
)
transaction_hashes_iterator = transaction_hashes_iterator + 1
try do
{_transaction_count, result} = repo.update_all(update_query, [], timeout: timeout)
if valid_internal_transactions_count == transaction_hashes_iterator do
{:halt, result}
else
{:cont, transaction_hashes_iterator}
end
rescue
postgrex_error in Postgrex.Error ->
{:halt, %{exception: postgrex_error, transaction_hashes: transaction_hashes}}
end
end)
try do case result do
{_transaction_count, result} = repo.update_all(update_query, [], timeout: timeout) %{exception: _} ->
{:error, result}
{:ok, result} _ ->
rescue {:ok, result}
postgrex_error in Postgrex.Error -> end
{:error, %{exception: postgrex_error, transaction_hashes: transaction_hashes}}
end end
end end

@ -22,6 +22,133 @@ defmodule Explorer.Chain.Import.Runner.InternalTransactionsTest do
assert :error == Repo.get(Transaction, transaction.hash).status assert :error == Repo.get(Transaction, transaction.hash).status
end end
test "simple coin transfer's status becomes :error when its internal_transaction has an error" do
transaction = insert(:transaction) |> with_block(status: :ok)
insert(:pending_block_operation, block_hash: transaction.block_hash, fetch_internal_transactions: true)
assert :ok == transaction.status
index = 0
error = "Out of gas"
internal_transaction_changes =
make_internal_transaction_changes_for_simple_coin_transfers(transaction, index, error)
assert {:ok, _} = run_internal_transactions([internal_transaction_changes])
assert :error == Repo.get(Transaction, transaction.hash).status
end
test "for block with 2 simple coin transfer's statuses become :error when its both internal_transactions has an error" do
a_block = insert(:block, number: 1000)
transaction1 = insert(:transaction) |> with_block(a_block, status: :ok)
transaction2 = insert(:transaction) |> with_block(a_block, status: :ok)
insert(:pending_block_operation, block_hash: a_block.hash, fetch_internal_transactions: true)
assert :ok == transaction1.status
assert :ok == transaction2.status
index = 0
error = "Out of gas"
internal_transaction_changes_1 =
make_internal_transaction_changes_for_simple_coin_transfers(transaction1, index, error)
internal_transaction_changes_2 =
make_internal_transaction_changes_for_simple_coin_transfers(transaction2, index, error)
assert {:ok, _} = run_internal_transactions([internal_transaction_changes_1, internal_transaction_changes_2])
assert :error == Repo.get(Transaction, transaction1.hash).status
assert :error == Repo.get(Transaction, transaction2.hash).status
end
test "for block with 2 simple coin transfer's only status become :error for tx where internal_transactions has an error" do
a_block = insert(:block, number: 1000)
transaction1 = insert(:transaction) |> with_block(a_block, status: :ok)
transaction2 = insert(:transaction) |> with_block(a_block, status: :ok)
insert(:pending_block_operation, block_hash: a_block.hash, fetch_internal_transactions: true)
assert :ok == transaction1.status
assert :ok == transaction2.status
index = 0
error = "Out of gas"
internal_transaction_changes_1 =
make_internal_transaction_changes_for_simple_coin_transfers(transaction1, index, error)
internal_transaction_changes_2 =
make_internal_transaction_changes_for_simple_coin_transfers(transaction2, index, nil)
assert {:ok, _} = run_internal_transactions([internal_transaction_changes_1, internal_transaction_changes_2])
assert :error == Repo.get(Transaction, transaction1.hash).status
assert :ok == Repo.get(Transaction, transaction2.hash).status
end
test "for block with simple coin transfer and method calls, method calls internal txs have correct block_index" do
a_block = insert(:block, number: 1000)
transaction0 = insert(:transaction) |> with_block(a_block, status: :ok)
transaction1 = insert(:transaction) |> with_block(a_block, status: :ok)
transaction2 = insert(:transaction) |> with_block(a_block, status: :ok)
insert(:pending_block_operation, block_hash: a_block.hash, fetch_internal_transactions: true)
assert :ok == transaction0.status
assert :ok == transaction1.status
assert :ok == transaction2.status
index = 0
internal_transaction_changes_0 = make_internal_transaction_changes(transaction0, index, nil)
internal_transaction_changes_0_1 = make_internal_transaction_changes(transaction0, 1, nil)
internal_transaction_changes_1 =
make_internal_transaction_changes_for_simple_coin_transfers(transaction1, index, nil)
internal_transaction_changes_2 = make_internal_transaction_changes(transaction2, index, nil)
internal_transaction_changes_2_1 = make_internal_transaction_changes(transaction2, 1, nil)
assert {:ok, _} =
run_internal_transactions([
internal_transaction_changes_0,
internal_transaction_changes_0_1,
internal_transaction_changes_1,
internal_transaction_changes_2,
internal_transaction_changes_2_1
])
assert from(i in InternalTransaction, where: i.transaction_hash == ^transaction0.hash, where: i.index == 0)
|> Repo.one()
|> is_nil()
assert 1 == Repo.get_by!(InternalTransaction, transaction_hash: transaction0.hash, index: 1).block_index
assert from(i in InternalTransaction, where: i.transaction_hash == ^transaction1.hash) |> Repo.one() |> is_nil()
assert from(i in InternalTransaction, where: i.transaction_hash == ^transaction2.hash, where: i.index == 0)
|> Repo.one()
|> is_nil()
assert 4 == Repo.get_by!(InternalTransaction, transaction_hash: transaction2.hash, index: 1).block_index
end
test "simple coin transfer has no internal transaction inserted" do
transaction = insert(:transaction) |> with_block(status: :ok)
insert(:pending_block_operation, block_hash: transaction.block_hash, fetch_internal_transactions: true)
assert :ok == transaction.status
index = 0
internal_transaction_changes =
make_internal_transaction_changes_for_simple_coin_transfers(transaction, index, nil)
assert {:ok, _} = run_internal_transactions([internal_transaction_changes])
assert !Repo.exists?(from(i in InternalTransaction, where: i.transaction_hash == ^transaction.hash))
end
test "pending transactions don't get updated not its internal_transactions inserted" do test "pending transactions don't get updated not its internal_transactions inserted" do
transaction = insert(:transaction) |> with_block(status: :ok) transaction = insert(:transaction) |> with_block(status: :ok)
pending = insert(:transaction) pending = insert(:transaction)
@ -31,7 +158,7 @@ defmodule Explorer.Chain.Import.Runner.InternalTransactionsTest do
assert :ok == transaction.status assert :ok == transaction.status
assert is_nil(pending.block_hash) assert is_nil(pending.block_hash)
index = 0 index = 1
transaction_changes = make_internal_transaction_changes(transaction, index, nil) transaction_changes = make_internal_transaction_changes(transaction, index, nil)
pending_changes = make_internal_transaction_changes(pending, index, nil) pending_changes = make_internal_transaction_changes(pending, index, nil)
@ -62,7 +189,7 @@ defmodule Explorer.Chain.Import.Runner.InternalTransactionsTest do
assert full_block.hash == inserted.block_hash assert full_block.hash == inserted.block_hash
index = 0 index = 1
pending_transaction_changes = pending_transaction_changes =
pending pending
@ -142,17 +269,23 @@ defmodule Explorer.Chain.Import.Runner.InternalTransactionsTest do
assert full_block.hash == inserted.block_hash assert full_block.hash == inserted.block_hash
index = 0 transaction_changes = make_internal_transaction_changes(inserted, 0, nil)
transaction_changes_2 = make_internal_transaction_changes(inserted, 1, nil)
transaction_changes = make_internal_transaction_changes(inserted, index, nil)
empty_changes = make_empty_block_changes(empty_block.number) empty_changes = make_empty_block_changes(empty_block.number)
assert {:ok, _} = run_internal_transactions([empty_changes, transaction_changes]) assert {:ok, _} = run_internal_transactions([empty_changes, transaction_changes, transaction_changes_2])
assert %{consensus: true} = Repo.get(Block, empty_block.hash) assert %{consensus: true} = Repo.get(Block, empty_block.hash)
assert PendingBlockOperation |> Repo.get(empty_block.hash) |> is_nil() assert PendingBlockOperation |> Repo.get(empty_block.hash) |> is_nil()
assert from(i in InternalTransaction, where: i.transaction_hash == ^inserted.hash) |> Repo.one() |> is_nil() == assert from(i in InternalTransaction, where: i.transaction_hash == ^inserted.hash, where: i.index == 0)
|> Repo.one()
|> is_nil() ==
true
assert from(i in InternalTransaction, where: i.transaction_hash == ^inserted.hash, where: i.index == 1)
|> Repo.one()
|> is_nil() ==
false false
assert %{consensus: true} = Repo.get(Block, full_block.hash) assert %{consensus: true} = Repo.get(Block, full_block.hash)
@ -199,4 +332,28 @@ defmodule Explorer.Chain.Import.Runner.InternalTransactionsTest do
block_number: transaction.block_number block_number: transaction.block_number
} }
end end
defp make_internal_transaction_changes_for_simple_coin_transfers(transaction, index, error) do
%{
from_address_hash: insert(:address).hash,
to_address_hash: insert(:address).hash,
call_type: :call,
gas: 0,
gas_used: nil,
input: %Data{bytes: <<>>},
output:
if is_nil(error) do
%Data{bytes: <<0>>}
else
nil
end,
index: index,
trace_address: [],
transaction_hash: transaction.hash,
type: :call,
value: Wei.from(Decimal.new(1), :wei),
error: error,
block_number: transaction.block_number
}
end
end end

@ -61,7 +61,7 @@ defmodule Explorer.Chain.ImportTest do
to_address_hash: "0x8bf38d4764929064f2d4d3a56520a76ab3df415b", to_address_hash: "0x8bf38d4764929064f2d4d3a56520a76ab3df415b",
gas: 4_677_320, gas: 4_677_320,
gas_used: 27770, gas_used: 27770,
input: "0x", input: "0x10855269000000000000000000000000862d67cb0773ee3f8ce7ea89b328ffea861ab3ef",
output: "0x", output: "0x",
value: 0 value: 0
}, },
@ -77,7 +77,7 @@ defmodule Explorer.Chain.ImportTest do
to_address_hash: "0x8bf38d4764929064f2d4d3a56520a76ab3df415b", to_address_hash: "0x8bf38d4764929064f2d4d3a56520a76ab3df415b",
gas: 4_677_320, gas: 4_677_320,
gas_used: 27770, gas_used: 27770,
input: "0x", input: "0x10855269000000000000000000000000862d67cb0773ee3f8ce7ea89b328ffea861ab3ef",
output: "0x", output: "0x",
value: 0 value: 0
} }
@ -252,15 +252,6 @@ defmodule Explorer.Chain.ImportTest do
} }
], ],
internal_transactions: [ internal_transactions: [
%{
index: 0,
transaction_hash: %Hash{
byte_count: 32,
bytes:
<<83, 189, 136, 72, 114, 222, 62, 72, 134, 146, 136, 27, 174, 236, 38, 46, 123, 149, 35, 77, 57,
101, 36, 140, 57, 254, 153, 47, 255, 212, 51, 229>>
}
},
%{ %{
index: 1, index: 1,
transaction_hash: %Hash{ transaction_hash: %Hash{
@ -485,8 +476,7 @@ defmodule Explorer.Chain.ImportTest do
Subscriber.to(:internal_transactions, :realtime) Subscriber.to(:internal_transactions, :realtime)
Import.all(@import_data) Import.all(@import_data)
assert_receive {:chain_event, :internal_transactions, :realtime, assert_receive {:chain_event, :internal_transactions, :realtime, [%{transaction_hash: _, index: _}]}
[%{transaction_hash: _, index: _}, %{transaction_hash: _, index: _}]}
end end
test "publishes transactions data to subscribers on insert" do test "publishes transactions data to subscribers on insert" do
@ -612,7 +602,8 @@ defmodule Explorer.Chain.ImportTest do
gas_used: 269_607, gas_used: 269_607,
hash: transaction_hash, hash: transaction_hash,
index: 0, index: 0,
input: "0x", input:
"0x6060604052341561000f57600080fd5b7fb94ae47ec9f4248692e2ecf9740b67ab493f3dcc8452bedc7d9cd911c28d1ca5426040518082815260200191505060405180910390a1609e806100546000396000f300606060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063557ed1ba146044575b600080fd5b3415604e57600080fd5b6054606a565b6040518082815260200191505060405180910390f35b6000429050905600a165627a7a7230582053883c0c39da080adc15a91094921659c200b3bb60aed9e49b79b0274da3f4010029",
nonce: 0, nonce: 0,
r: 0, r: 0,
s: 0, s: 0,
@ -639,6 +630,96 @@ defmodule Explorer.Chain.ImportTest do
to_address_hash: to_address_hash, to_address_hash: to_address_hash,
gas: 4_677_320, gas: 4_677_320,
gas_used: 27770, gas_used: 27770,
input:
"0x6060604052341561000f57600080fd5b7fb94ae47ec9f4248692e2ecf9740b67ab493f3dcc8452bedc7d9cd911c28d1ca5426040518082815260200191505060405180910390a1609e806100546000396000f300606060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063557ed1ba146044575b600080fd5b3415604e57600080fd5b6054606a565b6040518082815260200191505060405180910390f35b6000429050905600a165627a7a7230582053883c0c39da080adc15a91094921659c200b3bb60aed9e49b79b0274da3f4010029",
output: "0x",
value: 0
}
],
with: :blockless_changeset
}
}
assert {:ok, _} = Import.all(options)
assert [block_hash] = Explorer.Repo.all(PendingBlockOperation.block_hashes(:fetch_internal_transactions))
assert {:ok, _} = Import.all(internal_txs_options)
assert [] == Explorer.Repo.all(PendingBlockOperation.block_hashes(:fetch_internal_transactions))
end
test "blocks with simple coin transfers updates PendingBlockOperation status" do
block_hash = "0xe69314b702f403e00ec89cd63d5870182ed334d9d461bd042cdd6609fd6b7c17"
block_number = 13_255_416
miner_hash = from_address_hash = "0xe2ac1c6843A33f81aE4935E5EF1277a392990381"
to_address_hash = "0xDC1772b72d828ea9b7D4ded22dbef0f082578B8B"
transaction_hash = "0x8f20a5b3b79199db857323af7a5077d2dae7867368fef6f4e8cd8b14b88a9c6a"
options = %{
addresses: %{
params: [
%{hash: from_address_hash},
%{hash: to_address_hash}
]
},
blocks: %{
params: [
%{
consensus: true,
difficulty: 340_282_366_920_938_463_463_374_607_400_000_000_000,
gas_limit: 9_999_991,
gas_used: 21_000,
hash: block_hash,
miner_hash: miner_hash,
nonce: 0,
number: block_number,
parent_hash: "0x4c4505527d99e07dbcd6274ffaac629099ae6d4e1f2bc2bd3cc48d3f5a511d6f",
size: 703,
timestamp: Timex.parse!("2020-02-12 10:48:21Z", "{ISO:Extended:Z}"),
total_difficulty: 4_510_584_331_001_678_443_607_831_185_000_000_000_000_000_000
}
]
},
transactions: %{
params: [
%{
block_hash: block_hash,
block_number: block_number,
cumulative_gas_used: 21_000,
from_address_hash: from_address_hash,
gas: 21_000,
gas_price: 1,
gas_used: 21_000,
hash: transaction_hash,
index: 0,
input: "0x",
nonce: 0,
r: 0,
s: 0,
status: :ok,
v: 0,
value: 0
}
]
}
}
internal_txs_options = %{
internal_transactions: %{
params: [
%{
block_number: block_number,
transaction_index: 0,
transaction_hash: transaction_hash,
index: 0,
trace_address: [],
type: "call",
call_type: "call",
from_address_hash: from_address_hash,
to_address_hash: to_address_hash,
gas: 21_000,
gas_used: 21000,
input: "0x", input: "0x",
output: "0x", output: "0x",
value: 0 value: 0
@ -1709,7 +1790,7 @@ defmodule Explorer.Chain.ImportTest do
end end
# https://github.com/poanetwork/blockscout/issues/868 regression test # https://github.com/poanetwork/blockscout/issues/868 regression test
test "errored transactions can be forked" do test "errored simple coin transfer can be forked" do
block_number = 0 block_number = 0
miner_hash_before = address_hash() miner_hash_before = address_hash()
@ -1771,6 +1852,125 @@ defmodule Explorer.Chain.ImportTest do
status: :error status: :error
} }
] ]
}
})
%Block{consensus: true, number: ^block_number} = Repo.get(Block, block_hash_before)
transaction_before = Repo.get!(Transaction, transaction_hash)
refute transaction_before.block_hash == nil
refute transaction_before.block_number == nil
refute transaction_before.gas_used == nil
refute transaction_before.cumulative_gas_used == nil
refute transaction_before.index == nil
refute transaction_before.status == nil
miner_hash_after = address_hash()
from_address_hash_after = address_hash()
block_hash_after = block_hash()
assert {:ok, _} =
Import.all(%{
addresses: %{
params: [
%{hash: miner_hash_after},
%{hash: from_address_hash_after}
]
},
blocks: %{
params: [
%{
consensus: true,
difficulty: 1,
gas_limit: 1,
gas_used: 1,
hash: block_hash_after,
miner_hash: miner_hash_after,
nonce: 1,
number: block_number,
parent_hash: block_hash(),
size: 1,
timestamp: Timex.parse!("2019-01-01T02:00:00Z", "{ISO:Extended:Z}"),
total_difficulty: 1
}
]
}
})
transaction_after = Repo.get!(Transaction, transaction_hash)
assert transaction_after.block_hash == nil
assert transaction_after.block_number == nil
assert transaction_after.gas_used == nil
assert transaction_after.cumulative_gas_used == nil
assert transaction_after.index == nil
assert transaction_after.error == nil
assert transaction_after.status == nil
end
# https://github.com/poanetwork/blockscout/issues/868 regression test
test "errored other transactions can be forked" do
block_number = 0
miner_hash_before = address_hash()
from_address_hash_before = address_hash()
to_address_hash_before = address_hash()
block_hash_before = block_hash()
index_before = 0
error = "Reverted"
transaction_hash = transaction_hash()
assert {:ok, _} =
Import.all(%{
addresses: %{
params: [
%{hash: miner_hash_before},
%{hash: from_address_hash_before},
%{hash: to_address_hash_before}
]
},
blocks: %{
params: [
%{
consensus: true,
difficulty: 0,
gas_limit: 0,
gas_used: 0,
hash: block_hash_before,
miner_hash: miner_hash_before,
nonce: 0,
number: block_number,
parent_hash: block_hash(),
size: 0,
timestamp: Timex.parse!("2019-01-01T01:00:00Z", "{ISO:Extended:Z}"),
total_difficulty: 0
}
]
},
transactions: %{
params: [
%{
block_hash: block_hash_before,
block_number: block_number,
error: error,
from_address_hash: from_address_hash_before,
to_address_hash: to_address_hash_before,
gas: 666_000,
gas_price: 1,
gas_used: 555_000,
cumulative_gas_used: 555_000,
hash: transaction_hash,
index: index_before,
input: "0x0102",
nonce: 0,
r: 0,
s: 0,
v: 0,
value: 0,
status: :error
}
]
}, },
internal_transactions: %{ internal_transactions: %{
params: [ params: [
@ -1784,7 +1984,7 @@ defmodule Explorer.Chain.ImportTest do
to_address_hash: to_address_hash_before, to_address_hash: to_address_hash_before,
trace_address: [], trace_address: [],
value: 0, value: 0,
input: "0x", input: "0x0102",
error: error, error: error,
block_number: block_number, block_number: block_number,
transaction_index: 0 transaction_index: 0

@ -1397,7 +1397,7 @@ defmodule Explorer.ChainTest do
to_address_hash: "0x8bf38d4764929064f2d4d3a56520a76ab3df415b", to_address_hash: "0x8bf38d4764929064f2d4d3a56520a76ab3df415b",
gas: 4_677_320, gas: 4_677_320,
gas_used: 27770, gas_used: 27770,
input: "0x", input: "0x10855269000000000000000000000000862d67cb0773ee3f8ce7ea89b328ffea861ab3ef",
output: "0x", output: "0x",
value: 0 value: 0
} }
@ -1566,17 +1566,7 @@ defmodule Explorer.ChainTest do
updated_at: %{} updated_at: %{}
} }
], ],
internal_transactions: [ internal_transactions: [],
%{
index: 0,
transaction_hash: %Hash{
byte_count: 32,
bytes:
<<83, 189, 136, 72, 114, 222, 62, 72, 134, 146, 136, 27, 174, 236, 38, 46, 123, 149, 35, 77, 57,
101, 36, 140, 57, 254, 153, 47, 255, 212, 51, 229>>
}
}
],
logs: [ logs: [
%Log{ %Log{
address_hash: %Hash{ address_hash: %Hash{

@ -20,3 +20,17 @@ config :logger, :addresses_without_code,
level: :debug, level: :debug,
path: Path.absname("logs/test/indexer/addresses_without_code.log"), path: Path.absname("logs/test/indexer/addresses_without_code.log"),
metadata_filter: [fetcher: :addresses_without_code] metadata_filter: [fetcher: :addresses_without_code]
variant =
if is_nil(System.get_env("ETHEREUM_JSONRPC_VARIANT")) do
"parity"
else
System.get_env("ETHEREUM_JSONRPC_VARIANT")
|> String.split(".")
|> List.last()
|> String.downcase()
end
# Import variant specific config. This must remain at the bottom
# of this file so it overrides the configuration defined above.
import_config "test/#{variant}.exs"

@ -0,0 +1,8 @@
use Mix.Config
config :indexer,
json_rpc_named_arguments: [
transport: EthereumJSONRPC.Mox,
transport_options: [],
variant: EthereumJSONRPC.Ganache
]

@ -0,0 +1,8 @@
use Mix.Config
config :indexer,
json_rpc_named_arguments: [
transport: EthereumJSONRPC.Mox,
transport_options: [],
variant: EthereumJSONRPC.Geth
]

@ -0,0 +1,8 @@
use Mix.Config
config :indexer,
json_rpc_named_arguments: [
transport: EthereumJSONRPC.Mox,
transport_options: [],
variant: EthereumJSONRPC.Parity
]

@ -0,0 +1,8 @@
use Mix.Config
config :indexer,
json_rpc_named_arguments: [
transport: EthereumJSONRPC.Mox,
transport_options: [],
variant: EthereumJSONRPC.RSK
]

@ -210,9 +210,26 @@ defmodule Indexer.Fetcher.InternalTransactionTest do
"value" => "0x174876e800" "value" => "0x174876e800"
}, },
"result" => %{"gasUsed" => "0x7d37", "output" => "0x"}, "result" => %{"gasUsed" => "0x7d37", "output" => "0x"},
"subtraces" => 0, "subtraces" => 1,
"traceAddress" => [], "traceAddress" => [],
"type" => "call" "type" => "call"
},
%{
"action" => %{
"callType" => "call",
"from" => "0xb37b428a7ddee91f39b26d79d23dc1c89e3e12a7",
"gas" => "0x32dcf",
"input" => "0x42dad49e",
"to" => "0xee4019030fb5c2b68c42105552c6268d56c6cbfe",
"value" => "0x0"
},
"result" => %{
"gasUsed" => "0xb08",
"output" => "0x"
},
"subtraces" => 0,
"traceAddress" => [0],
"type" => "call"
} }
], ],
"transactionHash" => transaction.hash, "transactionHash" => transaction.hash,

Loading…
Cancel
Save