diff --git a/CHANGELOG.md b/CHANGELOG.md index 0eed85aec8..02a2349bf0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ - [#1920](https://github.com/poanetwork/blockscout/pull/1920) - fix: remove source code fields from list endpoint - [#1876](https://github.com/poanetwork/blockscout/pull/1876) - async calculate a count of blocks - [#1941](https://github.com/poanetwork/blockscout/pull/1941) - feat: add on demand fetching and stale attr to rpc +- [#1952](https://github.com/poanetwork/blockscout/pull/1952) - feat: exclude empty contracts by default ### Fixes diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/contract_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/contract_controller.ex index 886bbcd575..23dacd45da 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/contract_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/contract_controller.ex @@ -103,6 +103,9 @@ defmodule BlockScoutWeb.API.RPC.ContractController do :not_decompiled -> Chain.list_not_decompiled_contracts(page_size, offset) + :empty -> + Chain.list_empty_contracts(page_size, offset) + _ -> Chain.list_contracts(page_size, offset) end @@ -140,10 +143,12 @@ defmodule BlockScoutWeb.API.RPC.ContractController do defp contracts_filter(2), do: {:ok, :decompiled} defp contracts_filter(3), do: {:ok, :unverified} defp contracts_filter(4), do: {:ok, :not_decompiled} + defp contracts_filter(5), do: {:ok, :empty} defp contracts_filter("verified"), do: {:ok, :verified} defp contracts_filter("decompiled"), do: {:ok, :decompiled} defp contracts_filter("unverified"), do: {:ok, :unverified} defp contracts_filter("not_decompiled"), do: {:ok, :not_decompiled} + defp contracts_filter("empty"), do: {:ok, :empty} defp contracts_filter(filter) when is_bitstring(filter) do case Integer.parse(filter) do diff --git a/apps/block_scout_web/lib/block_scout_web/etherscan.ex b/apps/block_scout_web/lib/block_scout_web/etherscan.ex index 3621a12d10..a657ff8fd2 100644 --- a/apps/block_scout_web/lib/block_scout_web/etherscan.ex +++ b/apps/block_scout_web/lib/block_scout_web/etherscan.ex @@ -1795,7 +1795,7 @@ defmodule BlockScoutWeb.Etherscan do key: "filter", type: "string", description: - "verified|decompiled|unverified|not_decompiled, or 1|2|3|4 respectively. This requests only contracts with that status." + "verified|decompiled|unverified|not_decompiled|empty, or 1|2|3|4|5 respectively. This requests only contracts with that status." }, %{ key: "not_decompiled_with_version", diff --git a/apps/block_scout_web/test/block_scout_web/controllers/api/rpc/contract_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/api/rpc/contract_controller_test.exs index 43169a65d2..399e49bfff 100644 --- a/apps/block_scout_web/test/block_scout_web/controllers/api/rpc/contract_controller_test.exs +++ b/apps/block_scout_web/test/block_scout_web/controllers/api/rpc/contract_controller_test.exs @@ -100,6 +100,34 @@ defmodule BlockScoutWeb.API.RPC.ContractControllerTest do ] end + test "filtering for only unverified contracts does not show self destructed contracts", %{ + params: params, + conn: conn + } do + address = insert(:contract_address) + insert(:smart_contract) + insert(:contract_address, contract_code: "0x") + + response = + conn + |> get("/api", Map.put(params, "filter", "unverified")) + |> json_response(200) + + assert response["message"] == "OK" + assert response["status"] == "1" + + assert response["result"] == [ + %{ + "ABI" => "Contract source code not verified", + "Address" => to_string(address.hash), + "CompilerVersion" => "", + "ContractName" => "", + "DecompilerVersion" => "", + "OptimizationUsed" => "" + } + ] + end + test "filtering for only verified contracts shows only verified contracts", %{params: params, conn: conn} do insert(:contract_address) contract = insert(:smart_contract) @@ -222,6 +250,35 @@ defmodule BlockScoutWeb.API.RPC.ContractControllerTest do } ] end + + test "filtering for only not_decompiled (and by extension not verified contracts) does not show empty contracts", %{ + params: params, + conn: conn + } do + insert(:decompiled_smart_contract) + insert(:smart_contract) + insert(:contract_address, contract_code: "0x") + contract_address = insert(:contract_address) + + response = + conn + |> get("/api", Map.put(params, "filter", "not_decompiled")) + |> json_response(200) + + assert response["message"] == "OK" + assert response["status"] == "1" + + assert response["result"] == [ + %{ + "ABI" => "Contract source code not verified", + "Address" => to_string(contract_address.hash), + "CompilerVersion" => "", + "ContractName" => "", + "DecompilerVersion" => "", + "OptimizationUsed" => "" + } + ] + end end describe "getabi" do diff --git a/apps/explorer/lib/explorer/chain.ex b/apps/explorer/lib/explorer/chain.ex index 713d449d72..adb9759638 100644 --- a/apps/explorer/lib/explorer/chain.ex +++ b/apps/explorer/lib/explorer/chain.ex @@ -2802,6 +2802,7 @@ defmodule Explorer.Chain do on: smart_contract.address_hash == address.hash, where: not is_nil(address.contract_code), where: is_nil(smart_contract.address_hash), + where: address.contract_code != <<>>, preload: [{:smart_contract, smart_contract}, :decompiled_smart_contracts], order_by: [asc: address.inserted_at], limit: ^limit, @@ -2811,6 +2812,19 @@ defmodule Explorer.Chain do Repo.all(query) end + def list_empty_contracts(limit, offset) do + query = + from(address in Address, + where: address.contract_code == <<>>, + preload: [:smart_contract, :decompiled_smart_contracts], + order_by: [asc: address.inserted_at], + limit: ^limit, + offset: ^offset + ) + + Repo.all(query) + end + def list_not_decompiled_contracts(limit, offset) do query = from( @@ -2820,6 +2834,7 @@ defmodule Explorer.Chain do "NOT EXISTS (SELECT 1 FROM decompiled_smart_contracts WHERE decompiled_smart_contracts.address_hash = ?)", address.hash ), + where: address.contract_code != <<>>, left_join: smart_contract in SmartContract, on: smart_contract.address_hash == address.hash, left_join: decompiled_smart_contract in DecompiledSmartContract,