Blockchain explorer for Ethereum based network and a tool for inspecting and analyzing EVM based blockchains.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
blockscout/apps/explorer/test/explorer/etherscan/logs_test.exs

670 lines
18 KiB

defmodule Explorer.Etherscan.LogsTest do
use Explorer.DataCase
import Explorer.Factory
alias Explorer.Etherscan.Logs
alias Explorer.Chain.Transaction
describe "list_logs/1" do
test "with empty db" do
contract_address = build(:contract_address)
filter = %{
from_block: 0,
to_block: 9999,
address_hash: contract_address.hash
}
assert Logs.list_logs(filter) == []
end
test "with address with zero logs" do
contract_address = insert(:contract_address)
%Transaction{block: block} =
:transaction
|> insert(to_address: contract_address)
|> with_block()
filter = %{
from_block: block.number,
to_block: block.number,
address_hash: contract_address.hash
}
assert Logs.list_logs(filter) == []
end
test "with address with one log response includes all required information" do
contract_address = insert(:contract_address)
transaction =
%Transaction{block: block} =
:transaction
|> insert(to_address: contract_address)
|> with_block()
log = insert(:log, address: contract_address, transaction: transaction)
filter = %{
from_block: block.number,
to_block: block.number,
address_hash: contract_address.hash
}
[found_log] = Logs.list_logs(filter)
assert found_log.data == log.data
assert found_log.first_topic == log.first_topic
assert found_log.second_topic == log.second_topic
assert found_log.third_topic == log.third_topic
assert found_log.fourth_topic == log.fourth_topic
assert found_log.index == log.index
assert found_log.address_hash == log.address_hash
assert found_log.transaction_hash == log.transaction_hash
assert found_log.gas_price == transaction.gas_price
assert found_log.gas_used == transaction.gas_used
assert found_log.transaction_index == transaction.index
assert found_log.block_number == block.number
assert found_log.block_timestamp == block.timestamp
end
test "with address with two logs" do
contract_address = insert(:contract_address)
transaction =
%Transaction{block: block} =
:transaction
|> insert(to_address: contract_address)
|> with_block()
insert_list(2, :log, address: contract_address, transaction: transaction)
filter = %{
from_block: block.number,
to_block: block.number,
address_hash: contract_address.hash
}
found_logs = Logs.list_logs(filter)
assert length(found_logs) == 2
end
test "ignores logs with block below fromBlock" do
first_block = insert(:block)
second_block = insert(:block)
contract_address = insert(:contract_address)
transaction_block1 =
%Transaction{} =
:transaction
|> insert(to_address: contract_address)
|> with_block(first_block)
transaction_block2 =
%Transaction{} =
:transaction
|> insert(to_address: contract_address)
|> with_block(second_block)
insert(:log, address: contract_address, transaction: transaction_block1)
insert(:log, address: contract_address, transaction: transaction_block2)
filter = %{
from_block: second_block.number,
to_block: second_block.number,
address_hash: contract_address.hash
}
[found_log] = Logs.list_logs(filter)
assert found_log.block_number == second_block.number
assert found_log.transaction_hash == transaction_block2.hash
end
test "ignores logs with block above toBlock" do
first_block = insert(:block)
second_block = insert(:block)
contract_address = insert(:contract_address)
transaction_block1 =
%Transaction{} =
:transaction
|> insert(to_address: contract_address)
|> with_block(first_block)
transaction_block2 =
%Transaction{} =
:transaction
|> insert(to_address: contract_address)
|> with_block(second_block)
insert(:log, address: contract_address, transaction: transaction_block1)
insert(:log, address: contract_address, transaction: transaction_block2)
filter = %{
from_block: first_block.number,
to_block: first_block.number,
address_hash: contract_address.hash
}
[found_log] = Logs.list_logs(filter)
assert found_log.block_number == first_block.number
assert found_log.transaction_hash == transaction_block1.hash
end
test "paginates logs" do
contract_address = insert(:contract_address)
transaction =
%Transaction{block: block} =
:transaction
|> insert(to_address: contract_address)
|> with_block()
inserted_records = insert_list(2000, :log, address: contract_address, transaction: transaction)
filter = %{
from_block: block.number,
to_block: block.number,
address_hash: contract_address.hash
}
first_found_logs = Logs.list_logs(filter)
assert Enum.count(first_found_logs) == 1_000
last_record = List.last(first_found_logs)
next_page_params = %{
log_index: last_record.index,
transaction_index: last_record.transaction_index,
block_number: transaction.block_number
}
second_found_logs = Logs.list_logs(filter, next_page_params)
assert Enum.count(second_found_logs) == 1_000
all_found_logs = first_found_logs ++ second_found_logs
assert Enum.all?(inserted_records, fn record ->
Enum.any?(all_found_logs, fn found_log -> found_log.index == record.index end)
end)
end
test "with a valid topic{x}" do
contract_address = insert(:contract_address)
transaction =
%Transaction{block: block} =
:transaction
|> insert(to_address: contract_address)
|> with_block()
log1_details = [
address: contract_address,
transaction: transaction,
first_topic: "some topic"
]
log2_details = [
address: contract_address,
transaction: transaction,
first_topic: "some other topic"
]
log1 = insert(:log, log1_details)
_log2 = insert(:log, log2_details)
filter = %{
from_block: block.number,
to_block: block.number,
first_topic: log1.first_topic
}
[found_log] = Logs.list_logs(filter)
assert found_log.first_topic == log1.first_topic
assert found_log.index == log1.index
end
test "with a valid topic{x} AND another" do
contract_address = insert(:contract_address)
transaction =
%Transaction{block: block} =
:transaction
|> insert(to_address: contract_address)
|> with_block()
log1_details = [
address: contract_address,
transaction: transaction,
first_topic: "some first topic",
second_topic: "some second topic"
]
log2_details = [
address: contract_address,
transaction: transaction,
first_topic: "some first topic",
second_topic: "some OTHER second topic"
]
_log1 = insert(:log, log1_details)
log2 = insert(:log, log2_details)
filter = %{
from_block: block.number,
to_block: block.number,
first_topic: log2.first_topic,
second_topic: log2.second_topic,
topic0_1_opr: "and"
}
[found_log] = Logs.list_logs(filter)
assert found_log.second_topic == log2.second_topic
assert found_log.first_topic == log2.first_topic
assert found_log.index == log2.index
end
test "with a valid topic{x} OR another" do
contract_address = insert(:contract_address)
transaction =
%Transaction{block: block} =
:transaction
|> insert(to_address: contract_address)
|> with_block()
log1_details = [
address: contract_address,
transaction: transaction,
first_topic: "some first topic",
second_topic: "some second topic"
]
log2_details = [
address: contract_address,
transaction: transaction,
first_topic: "some OTHER first topic",
second_topic: "some OTHER second topic"
]
log1 = insert(:log, log1_details)
log2 = insert(:log, log2_details)
filter = %{
from_block: block.number,
to_block: block.number,
first_topic: log1.first_topic,
second_topic: log2.second_topic,
topic0_1_opr: "or"
}
found_logs = Logs.list_logs(filter)
assert length(found_logs) == 2
end
test "with address and topic{x}" do
contract_address = insert(:contract_address)
transaction =
%Transaction{block: block} =
:transaction
|> insert(to_address: contract_address)
|> with_block()
log1_details = [
address: contract_address,
transaction: transaction,
first_topic: "some first topic"
]
log2_details = [
address: contract_address,
transaction: transaction,
first_topic: "some OTHER first topic"
]
_log1 = insert(:log, log1_details)
log2 = insert(:log, log2_details)
filter = %{
from_block: block.number,
to_block: block.number,
address_hash: contract_address.hash,
first_topic: log2.first_topic
}
[found_log] = Logs.list_logs(filter)
assert found_log.index == log2.index
assert found_log.first_topic == log2.first_topic
end
test "with address and two topic{x}s" do
contract_address = insert(:contract_address)
transaction =
%Transaction{block: block} =
:transaction
|> insert(to_address: contract_address)
|> with_block()
log1_details = [
address: contract_address,
transaction: transaction,
first_topic: "some first topic",
second_topic: "some second topic"
]
log2_details = [
address: contract_address,
transaction: transaction,
first_topic: "some OTHER first topic",
second_topic: "some OTHER second topic"
]
_log1 = insert(:log, log1_details)
log2 = insert(:log, log2_details)
filter = %{
from_block: block.number,
to_block: block.number,
address_hash: contract_address.hash,
first_topic: log2.first_topic,
second_topic: log2.second_topic,
topic0_1_opr: "and"
}
[found_log] = Logs.list_logs(filter)
assert found_log.index == log2.index
assert found_log.first_topic == log2.first_topic
end
test "with address and three topic{x}s with AND operator" do
contract_address = insert(:contract_address)
transaction =
%Transaction{block: block} =
:transaction
|> insert(to_address: contract_address)
|> with_block()
log1_details = [
address: contract_address,
transaction: transaction,
first_topic: "some first topic",
second_topic: "some second topic",
third_topic: "some third topic"
]
log2_details = [
address: contract_address,
transaction: transaction,
first_topic: "some OTHER first topic",
second_topic: "some OTHER second topic",
third_topic: "some OTHER third topic"
]
log3_details = [
address: contract_address,
transaction: transaction,
first_topic: "some ALT first topic",
second_topic: "some ALT second topic",
third_topic: "some ALT third topic"
]
_log1 = insert(:log, log1_details)
log2 = insert(:log, log2_details)
_log3 = insert(:log, log3_details)
filter = %{
from_block: block.number,
to_block: block.number,
address_hash: contract_address.hash,
first_topic: log2.first_topic,
second_topic: log2.second_topic,
third_topic: log2.third_topic,
topic0_1_opr: "and",
topic0_2_opr: "and",
topic1_2_opr: "and"
}
[found_log] = Logs.list_logs(filter)
assert found_log.index == log2.index
assert found_log.first_topic == log2.first_topic
assert found_log.second_topic == log2.second_topic
assert found_log.third_topic == log2.third_topic
end
test "with address and three topic{x}s with OR operator" do
contract_address = insert(:contract_address)
transaction =
%Transaction{block: block} =
:transaction
|> insert(to_address: contract_address)
|> with_block()
log1_details = [
address: contract_address,
transaction: transaction,
first_topic: "some first topic",
second_topic: "some second topic",
third_topic: "some third topic"
]
log2_details = [
address: contract_address,
transaction: transaction,
first_topic: "some OTHER first topic",
second_topic: "some OTHER second topic",
third_topic: "some OTHER third topic"
]
log3_details = [
address: contract_address,
transaction: transaction,
first_topic: "some ALT first topic",
second_topic: "some ALT second topic",
third_topic: "some ALT third topic"
]
log1 = insert(:log, log1_details)
log2 = insert(:log, log2_details)
_log3 = insert(:log, log3_details)
filter = %{
from_block: block.number,
to_block: block.number,
address_hash: contract_address.hash,
first_topic: log1.first_topic,
second_topic: log2.second_topic,
third_topic: log2.third_topic,
topic0_1_opr: "or",
topic0_2_opr: "or",
topic1_2_opr: "or"
}
[found_log] = Logs.list_logs(filter)
assert found_log.index == log2.index
assert found_log.first_topic == log2.first_topic
assert found_log.second_topic == log2.second_topic
assert found_log.third_topic == log2.third_topic
end
test "three topic{x}s with OR and AND operator" do
contract_address = insert(:contract_address)
transaction =
%Transaction{block: block} =
:transaction
|> insert(to_address: contract_address)
|> with_block()
log1_details = [
address: contract_address,
transaction: transaction,
first_topic: "some topic",
second_topic: "some second topic",
third_topic: "some third topic"
]
log2_details = [
address: contract_address,
transaction: transaction,
first_topic: "some topic",
second_topic: "some OTHER second topic",
third_topic: "some third topic"
]
log3_details = [
address: contract_address,
transaction: transaction,
first_topic: "some topic",
second_topic: "some second topic",
third_topic: "some third topic"
]
log1 = insert(:log, log1_details)
log2 = insert(:log, log2_details)
_log3 = insert(:log, log3_details)
filter = %{
from_block: block.number,
to_block: block.number,
address_hash: contract_address.hash,
first_topic: log1.first_topic,
second_topic: log2.second_topic,
third_topic: log2.third_topic,
topic0_1_opr: "or",
topic0_2_opr: "or",
topic1_2_opr: "and"
}
[found_log] = Logs.list_logs(filter)
assert found_log.index == log2.index
assert found_log.first_topic == log2.first_topic
assert found_log.second_topic == log2.second_topic
assert found_log.third_topic == log2.third_topic
end
test "four topic{x}s with all possible operators" do
contract_address = insert(:contract_address)
transaction =
%Transaction{block: block} =
:transaction
|> insert(to_address: contract_address)
|> with_block()
log1_details = [
address: contract_address,
transaction: transaction,
first_topic: "some topic",
second_topic: "some second topic"
]
log2_details = [
address: contract_address,
transaction: transaction,
first_topic: "some OTHER topic",
second_topic: "some OTHER second topic",
third_topic: "some OTHER third topic",
fourth_topic: "some fourth topic"
]
log3_details = [
address: contract_address,
transaction: transaction,
first_topic: "some topic",
second_topic: "some second topic",
third_topic: "some third topic",
fourth_topic: "some fourth topic"
]
log1 = insert(:log, log1_details)
log2 = insert(:log, log2_details)
_log3 = insert(:log, log3_details)
filter = %{
from_block: block.number,
to_block: block.number,
address_hash: contract_address.hash,
first_topic: log1.first_topic,
second_topic: log2.second_topic,
third_topic: log2.third_topic,
fourth_topic: log2.fourth_topic,
topic0_1_opr: "or",
topic0_2_opr: "or",
topic0_3_opr: "or",
topic1_2_opr: "and",
topic1_3_opr: "and",
topic2_3_opr: "and"
}
[found_log] = Logs.list_logs(filter)
assert found_log.index == log2.index
assert found_log.first_topic == log2.first_topic
assert found_log.second_topic == log2.second_topic
assert found_log.third_topic == log2.third_topic
end
test "returned logs are sorted by block" do
first_block = insert(:block)
second_block = insert(:block)
third_block = insert(:block)
contract_address = insert(:contract_address)
transaction_block1 =
%Transaction{} =
:transaction
|> insert(to_address: contract_address)
|> with_block(first_block)
transaction_block2 =
%Transaction{} =
:transaction
|> insert(to_address: contract_address)
|> with_block(second_block)
transaction_block3 =
%Transaction{} =
:transaction
|> insert(to_address: contract_address)
|> with_block(third_block)
insert(:log, address: contract_address, transaction: transaction_block3)
insert(:log, address: contract_address, transaction: transaction_block1)
insert(:log, address: contract_address, transaction: transaction_block2)
filter = %{
from_block: first_block.number,
to_block: third_block.number,
address_hash: contract_address.hash
}
found_logs = Logs.list_logs(filter)
block_number_order = Enum.map(found_logs, & &1.block_number)
assert block_number_order == Enum.sort(block_number_order)
end
end
end