diff --git a/apps/block_scout_web/lib/block_scout_web/paging_helper.ex b/apps/block_scout_web/lib/block_scout_web/paging_helper.ex index 11b9552bf2..483e4150f1 100644 --- a/apps/block_scout_web/lib/block_scout_web/paging_helper.ex +++ b/apps/block_scout_web/lib/block_scout_web/paging_helper.ex @@ -287,6 +287,8 @@ defmodule BlockScoutWeb.PagingHelper do def address_transactions_sorting(_), do: [] + defp do_address_transaction_sorting("block_number", "asc"), do: [asc: :block_number, asc: :index] + defp do_address_transaction_sorting("block_number", "desc"), do: [desc: :block_number, desc: :index] defp do_address_transaction_sorting("value", "asc"), do: [asc: :value] defp do_address_transaction_sorting("value", "desc"), do: [desc: :value] defp do_address_transaction_sorting("fee", "asc"), do: [{:dynamic, :fee, :asc_nulls_first, Transaction.dynamic_fee()}] diff --git a/apps/block_scout_web/test/block_scout_web/controllers/api/v2/address_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/api/v2/address_controller_test.exs index ba804e55c6..ea3318f7cc 100644 --- a/apps/block_scout_web/test/block_scout_web/controllers/api/v2/address_controller_test.exs +++ b/apps/block_scout_web/test/block_scout_web/controllers/api/v2/address_controller_test.exs @@ -6,7 +6,6 @@ defmodule BlockScoutWeb.API.V2.AddressControllerTest do alias ABI.{TypeDecoder, TypeEncoder} alias Explorer.{Chain, Repo, TestHelper} alias Explorer.Chain.Address.Counters - alias Explorer.Chain.Events.Subscriber alias Explorer.Chain.{ Address, @@ -823,6 +822,82 @@ defmodule BlockScoutWeb.API.V2.AddressControllerTest do check_paginated_response(response, response_2nd_page, transactions |> Enum.reverse()) end + + test "can order and paginate by block number ascending", %{conn: conn} do + address = insert(:address) + + transactions_from = + for _ <- 0..24, do: insert(:transaction, from_address: address) |> with_block() + + transactions_to = for _ <- 0..25, do: insert(:transaction, to_address: address) |> with_block() + + transactions = + (transactions_from ++ transactions_to) + |> Enum.sort_by(& &1.block.number) + + request = + get(conn, "/api/v2/addresses/#{address.hash}/transactions", %{"sort" => "block_number", "order" => "asc"}) + + assert response = json_response(request, 200) + + request_2nd_page = + get( + conn, + "/api/v2/addresses/#{address.hash}/transactions", + %{"sort" => "block_number", "order" => "asc"} |> Map.merge(response["next_page_params"]) + ) + + assert response_2nd_page = json_response(request_2nd_page, 200) + + assert Enum.count(response["items"]) == 50 + assert response["next_page_params"] != nil + compare_item(Enum.at(transactions, 0), Enum.at(response["items"], 0)) + compare_item(Enum.at(transactions, 49), Enum.at(response["items"], 49)) + + assert Enum.count(response_2nd_page["items"]) == 1 + assert response_2nd_page["next_page_params"] == nil + compare_item(Enum.at(transactions, 50), Enum.at(response_2nd_page["items"], 0)) + + check_paginated_response(response, response_2nd_page, transactions |> Enum.reverse()) + end + + test "can order and paginate by block number descending", %{conn: conn} do + address = insert(:address) + + transactions_from = + for _ <- 0..24, do: insert(:transaction, from_address: address) |> with_block() + + transactions_to = for _ <- 0..25, do: insert(:transaction, to_address: address) |> with_block() + + transactions = + (transactions_from ++ transactions_to) + |> Enum.sort_by(& &1.block.number, :desc) + + request = + get(conn, "/api/v2/addresses/#{address.hash}/transactions", %{"sort" => "block_number", "order" => "desc"}) + + assert response = json_response(request, 200) + + request_2nd_page = + get( + conn, + "/api/v2/addresses/#{address.hash}/transactions", + %{"sort" => "block_number", "order" => "desc"} |> Map.merge(response["next_page_params"]) + ) + + assert response_2nd_page = json_response(request_2nd_page, 200) + + assert Enum.count(response["items"]) == 50 + assert response["next_page_params"] != nil + compare_item(Enum.at(transactions, 0), Enum.at(response["items"], 0)) + compare_item(Enum.at(transactions, 49), Enum.at(response["items"], 49)) + + assert Enum.count(response_2nd_page["items"]) == 1 + assert response_2nd_page["next_page_params"] == nil + compare_item(Enum.at(transactions, 50), Enum.at(response_2nd_page["items"], 0)) + + check_paginated_response(response, response_2nd_page, transactions |> Enum.reverse()) + end end describe "/addresses/{address_hash}/token-transfers" do diff --git a/apps/explorer/lib/explorer/chain/transaction.ex b/apps/explorer/lib/explorer/chain/transaction.ex index 4bcd5df3e6..93d2a62df6 100644 --- a/apps/explorer/lib/explorer/chain/transaction.ex +++ b/apps/explorer/lib/explorer/chain/transaction.ex @@ -1581,6 +1581,18 @@ defmodule Explorer.Chain.Transaction do end end + defp compare_custom_sorting([{block_order, :block_number}, {index_order, :index}]) do + fn a, b -> + case {Helper.compare(a.block_number, b.block_number), Helper.compare(a.index, b.index)} do + {:eq, :eq} -> compare_default_sorting(a, b) + {:eq, :gt} -> index_order == :desc + {:eq, :lt} -> index_order == :asc + {:gt, _} -> block_order == :desc + {:lt, _} -> block_order == :asc + end + end + end + defp compare_custom_sorting([{:dynamic, :fee, order, _dynamic_fee}]) do fn a, b -> nil_case =