add endpoint to search address logs by topic

pull/2056/head
Ayrat Badykov 6 years ago
parent d63e5b02aa
commit e0468fffdd
No known key found for this signature in database
GPG Key ID: B44668E265E9396F
  1. 43
      apps/block_scout_web/lib/block_scout_web/controllers/address_logs_controller.ex
  2. 2
      apps/block_scout_web/lib/block_scout_web/router.ex
  3. 14
      apps/explorer/lib/explorer/chain.ex
  4. 44
      apps/explorer/test/explorer/chain_test.exs

@ -6,9 +6,11 @@ defmodule BlockScoutWeb.AddressLogsController do
import BlockScoutWeb.AddressController, only: [transaction_count: 1, validation_count: 1] import BlockScoutWeb.AddressController, only: [transaction_count: 1, validation_count: 1]
import BlockScoutWeb.Chain, only: [paging_options: 1, next_page_params: 3, split_list_by_page: 1] import BlockScoutWeb.Chain, only: [paging_options: 1, next_page_params: 3, split_list_by_page: 1]
alias BlockScoutWeb.AddressLogsView
alias Explorer.{Chain, Market} alias Explorer.{Chain, Market}
alias Explorer.ExchangeRates.Token alias Explorer.ExchangeRates.Token
alias Indexer.Fetcher.CoinBalanceOnDemand alias Indexer.Fetcher.CoinBalanceOnDemand
alias Phoenix.View
use BlockScoutWeb, :controller use BlockScoutWeb, :controller
@ -43,4 +45,45 @@ defmodule BlockScoutWeb.AddressLogsController do
not_found(conn) not_found(conn)
end end
end end
def search_logs(conn, %{"topic" => topic, "address_id" => address_hash_string} = params) do
with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string),
{:ok, address} <- Chain.hash_to_address(address_hash) do
topic = String.trim(topic)
logs_plus_one = Chain.address_to_logs(address, topic: topic)
{results, next_page} = split_list_by_page(logs_plus_one)
next_page_url =
case next_page_params(next_page, results, params) do
nil ->
nil
next_page_params ->
address_logs_path(conn, :index, address, Map.delete(next_page_params, "type"))
end
items =
results
|> Enum.map(fn log ->
View.render_to_string(
AddressLogsView,
"_logs.html",
log: log,
conn: conn
)
end)
json(
conn,
%{
items: items,
next_page_path: next_page_url
}
)
else
_ ->
not_found(conn)
end
end
end end

@ -238,6 +238,8 @@ defmodule BlockScoutWeb.Router do
get("/search", ChainController, :search) get("/search", ChainController, :search)
get("/search_logs", AddressLogsController, :search_logs)
get("/token_autocomplete", ChainController, :token_autocomplete) get("/token_autocomplete", ChainController, :token_autocomplete)
get("/chain_blocks", ChainController, :chain_blocks, as: :chain_blocks) get("/chain_blocks", ChainController, :chain_blocks, as: :chain_blocks)

@ -291,8 +291,9 @@ defmodule Explorer.Chain do
paging_options = Keyword.get(options, :paging_options) || %PagingOptions{page_size: 50} paging_options = Keyword.get(options, :paging_options) || %PagingOptions{page_size: 50}
{block_number, transaction_index, log_index} = paging_options.key || {BlockNumberCache.max_number(), 0, 0} {block_number, transaction_index, log_index} = paging_options.key || {BlockNumberCache.max_number(), 0, 0}
topic = Keyword.get(options, :topic)
query = base_query =
from(log in Log, from(log in Log,
inner_join: transaction in assoc(log, :transaction), inner_join: transaction in assoc(log, :transaction),
order_by: [desc: transaction.block_number, desc: transaction.index], order_by: [desc: transaction.block_number, desc: transaction.index],
@ -307,6 +308,17 @@ defmodule Explorer.Chain do
select: log select: log
) )
query =
if topic do
from(log in base_query,
where:
log.first_topic == ^topic or log.second_topic == ^topic or log.third_topic == ^topic or
log.fourth_topic == ^topic
)
else
base_query
end
query query
|> Repo.all() |> Repo.all()
|> Enum.take(paging_options.page_size) |> Enum.take(paging_options.page_size)

@ -93,6 +93,50 @@ defmodule Explorer.ChainTest do
assert Enum.count(Chain.address_to_logs(address, paging_options: paging_options2)) == 50 assert Enum.count(Chain.address_to_logs(address, paging_options: paging_options2)) == 50
end end
test "searches logs by topic when the first topic matches" do
address = insert(:address)
transaction1 =
:transaction
|> insert(to_address: address)
|> with_block()
insert(:log, transaction: transaction1, index: 1, address: address)
transaction2 =
:transaction
|> insert(from_address: address)
|> with_block()
insert(:log, transaction: transaction2, index: 2, address: address, first_topic: "test")
[found_log] = Chain.address_to_logs(address, topic: "test")
assert found_log.transaction.hash == transaction2.hash
end
test "searches logs by topic when the fourth topic matches" do
address = insert(:address)
transaction1 =
:transaction
|> insert(to_address: address)
|> with_block()
insert(:log, transaction: transaction1, index: 1, address: address, fourth_topic: "test")
transaction2 =
:transaction
|> insert(from_address: address)
|> with_block()
insert(:log, transaction: transaction2, index: 2, address: address)
[found_log] = Chain.address_to_logs(address, topic: "test")
assert found_log.transaction.hash == transaction1.hash
end
end end
describe "address_to_transactions_with_rewards/2" do describe "address_to_transactions_with_rewards/2" do

Loading…
Cancel
Save