diff --git a/CHANGELOG.md b/CHANGELOG.md index 109b2901d7..83089bc615 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### Features - [#8848](https://github.com/blockscout/blockscout/pull/8848) - Add MainPageRealtimeEventHandler +- [#8821](https://github.com/blockscout/blockscout/pull/8821) - Add new events to addresses channel: `eth_bytecode_db_lookup_started` and `smart_contract_was_not_verified` - [#8795](https://github.com/blockscout/blockscout/pull/8795) - Disable catchup indexer by env - [#8768](https://github.com/blockscout/blockscout/pull/8768) - Add possibility to search tokens by address hash - [#8750](https://github.com/blockscout/blockscout/pull/8750) - Support new eth-bytecode-db request metadata fields diff --git a/apps/block_scout_web/lib/block_scout_web/notifier.ex b/apps/block_scout_web/lib/block_scout_web/notifier.ex index cb1cdf70be..e340c4351d 100644 --- a/apps/block_scout_web/lib/block_scout_web/notifier.ex +++ b/apps/block_scout_web/lib/block_scout_web/notifier.ex @@ -232,9 +232,16 @@ defmodule BlockScoutWeb.Notifier do Endpoint.broadcast("addresses:#{to_string(address_hash)}", "changed_bytecode", %{}) end - def handle_event({:chain_event, :smart_contract_was_verified, :on_demand, [address_hash]}) do - log_broadcast_smart_contract_was_verified(address_hash) - Endpoint.broadcast("addresses:#{to_string(address_hash)}", "smart_contract_was_verified", %{}) + def handle_event({:chain_event, :smart_contract_was_verified = event, :on_demand, [address_hash]}) do + broadcast_automatic_verification_events(event, address_hash) + end + + def handle_event({:chain_event, :smart_contract_was_not_verified = event, :on_demand, [address_hash]}) do + broadcast_automatic_verification_events(event, address_hash) + end + + def handle_event({:chain_event, :eth_bytecode_db_lookup_started = event, :on_demand, [address_hash]}) do + broadcast_automatic_verification_events(event, address_hash) end def handle_event({:chain_event, :address_current_token_balances, :on_demand, address_current_token_balances}) do @@ -505,7 +512,12 @@ defmodule BlockScoutWeb.Notifier do Logger.info("Broadcast smart-contract #{address_hash} verification results") end - defp log_broadcast_smart_contract_was_verified(address_hash) do - Logger.info("Broadcast smart-contract #{address_hash} was verified") + defp log_broadcast_smart_contract_event(address_hash, event) do + Logger.info("Broadcast smart-contract #{address_hash}: #{event}") + end + + defp broadcast_automatic_verification_events(event, address_hash) do + log_broadcast_smart_contract_event(address_hash, event) + Endpoint.broadcast("addresses:#{to_string(address_hash)}", to_string(event), %{}) end end diff --git a/apps/block_scout_web/lib/block_scout_web/realtime_event_handler.ex b/apps/block_scout_web/lib/block_scout_web/realtime_event_handler.ex index 3f89f6762f..7d029f17f8 100644 --- a/apps/block_scout_web/lib/block_scout_web/realtime_event_handler.ex +++ b/apps/block_scout_web/lib/block_scout_web/realtime_event_handler.ex @@ -28,6 +28,8 @@ defmodule BlockScoutWeb.RealtimeEventHandler do Subscriber.to(:token_total_supply, :on_demand) Subscriber.to(:changed_bytecode, :on_demand) Subscriber.to(:smart_contract_was_verified, :on_demand) + Subscriber.to(:smart_contract_was_not_verified, :on_demand) + Subscriber.to(:eth_bytecode_db_lookup_started, :on_demand) Subscriber.to(:zkevm_confirmed_batches, :realtime) # Does not come from the indexer Subscriber.to(:exchange_rate) diff --git a/apps/block_scout_web/test/block_scout_web/controllers/api/v2/smart_contract_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/api/v2/smart_contract_controller_test.exs index 2164911f25..ad6eabf1f1 100644 --- a/apps/block_scout_web/test/block_scout_web/controllers/api/v2/smart_contract_controller_test.exs +++ b/apps/block_scout_web/test/block_scout_web/controllers/api/v2/smart_contract_controller_test.exs @@ -1,5 +1,5 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do - use BlockScoutWeb.ConnCase + use BlockScoutWeb.ConnCase, async: false use BlockScoutWeb.ChannelCase, async: false import Mox @@ -308,6 +308,16 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do end describe "/smart-contracts/{address_hash} <> eth_bytecode_db" do + setup do + old_interval_env = Application.get_env(:explorer, Explorer.Chain.Fetcher.LookUpSmartContractSourcesOnDemand) + + :ok + + on_exit(fn -> + Application.put_env(:explorer, Explorer.Chain.Fetcher.LookUpSmartContractSourcesOnDemand, old_interval_env) + end) + end + test "automatically verify contract", %{conn: conn} do {:ok, pid} = Explorer.Chain.Fetcher.LookUpSmartContractSourcesOnDemand.start_link([]) old_chain_id = Application.get_env(:block_scout_web, :chain_id) @@ -321,7 +331,9 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do Application.put_env(:explorer, Explorer.SmartContract.RustVerifierInterfaceBehaviour, service_url: "http://localhost:#{bypass.port}", - enabled: true + enabled: true, + type: "eth_bytecode_db", + eth_bytecode_db?: true ) address = insert(:contract_address) @@ -346,6 +358,13 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do request = get(conn, "/api/v2/smart-contracts/#{Address.checksum(address.hash)}") + assert_receive %Phoenix.Socket.Message{ + payload: %{}, + event: "eth_bytecode_db_lookup_started", + topic: ^topic + }, + :timer.seconds(1) + assert_receive %Phoenix.Socket.Message{ payload: %{}, event: "smart_contract_was_verified", @@ -391,7 +410,9 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do Application.put_env(:explorer, Explorer.SmartContract.RustVerifierInterfaceBehaviour, service_url: "http://localhost:#{bypass.port}", - enabled: true + enabled: true, + type: "eth_bytecode_db", + eth_bytecode_db?: true ) address = insert(:contract_address) @@ -416,6 +437,13 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do request = get(conn, "/api/v2/smart-contracts/#{Address.checksum(address.hash)}") + assert_receive %Phoenix.Socket.Message{ + payload: %{}, + event: "eth_bytecode_db_lookup_started", + topic: ^topic + }, + :timer.seconds(1) + assert_receive %Phoenix.Socket.Message{ payload: %{}, event: "smart_contract_was_verified", @@ -508,7 +536,9 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do Application.put_env(:explorer, Explorer.SmartContract.RustVerifierInterfaceBehaviour, service_url: "http://localhost:#{bypass.port}", - enabled: true + enabled: true, + type: "eth_bytecode_db", + eth_bytecode_db?: true ) address = insert(:contract_address) @@ -533,6 +563,13 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do request = get(conn, "/api/v2/smart-contracts/#{Address.checksum(address.hash)}") + assert_receive %Phoenix.Socket.Message{ + payload: %{}, + event: "eth_bytecode_db_lookup_started", + topic: ^topic + }, + :timer.seconds(1) + assert_receive %Phoenix.Socket.Message{ payload: %{}, event: "smart_contract_was_verified", @@ -582,7 +619,9 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do Application.put_env(:explorer, Explorer.SmartContract.RustVerifierInterfaceBehaviour, service_url: "http://localhost:#{bypass.port}", - enabled: true + enabled: true, + type: "eth_bytecode_db", + eth_bytecode_db?: true ) address = insert(:contract_address) @@ -607,6 +646,13 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do request = get(conn, "/api/v2/smart-contracts/#{Address.checksum(address.hash)}") + assert_receive %Phoenix.Socket.Message{ + payload: %{}, + event: "eth_bytecode_db_lookup_started", + topic: ^topic + }, + :timer.seconds(1) + assert_receive %Phoenix.Socket.Message{ payload: %{}, event: "smart_contract_was_verified", @@ -673,6 +719,12 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do bypass = Bypass.open() address = insert(:contract_address) + topic = "addresses:#{address.hash}" + + {:ok, _reply, _socket} = + BlockScoutWeb.UserSocketV2 + |> socket("no_id", %{}) + |> subscribe_and_join(topic) insert(:transaction, created_contract_address_hash: address.hash, @@ -685,7 +737,9 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do Application.put_env(:explorer, Explorer.SmartContract.RustVerifierInterfaceBehaviour, service_url: "http://localhost:#{bypass.port}", - enabled: true + enabled: true, + type: "eth_bytecode_db", + eth_bytecode_db?: true ) old_interval_env = Application.get_env(:explorer, Explorer.Chain.Fetcher.LookUpSmartContractSourcesOnDemand) @@ -698,6 +752,20 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do _request = get(conn, "/api/v2/smart-contracts/#{Address.checksum(address.hash)}") + assert_receive %Phoenix.Socket.Message{ + payload: %{}, + event: "eth_bytecode_db_lookup_started", + topic: ^topic + }, + :timer.seconds(1) + + assert_receive %Phoenix.Socket.Message{ + payload: %{}, + event: "smart_contract_was_not_verified", + topic: ^topic + }, + :timer.seconds(1) + :timer.sleep(10) Bypass.expect_once(bypass, "POST", "/api/v2/bytecodes/sources_search", fn conn -> @@ -706,6 +774,20 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do _request = get(conn, "/api/v2/smart-contracts/#{Address.checksum(address.hash)}") + assert_receive %Phoenix.Socket.Message{ + payload: %{}, + event: "eth_bytecode_db_lookup_started", + topic: ^topic + }, + :timer.seconds(1) + + assert_receive %Phoenix.Socket.Message{ + payload: %{}, + event: "smart_contract_was_not_verified", + topic: ^topic + }, + :timer.seconds(1) + :timer.sleep(10) Bypass.expect_once(bypass, "POST", "/api/v2/bytecodes/sources_search", fn conn -> @@ -714,12 +796,47 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do _request = get(conn, "/api/v2/smart-contracts/#{Address.checksum(address.hash)}") + assert_receive %Phoenix.Socket.Message{ + payload: %{}, + event: "eth_bytecode_db_lookup_started", + topic: ^topic + }, + :timer.seconds(1) + + assert_receive %Phoenix.Socket.Message{ + payload: %{}, + event: "smart_contract_was_not_verified", + topic: ^topic + }, + :timer.seconds(1) + :timer.sleep(10) Application.put_env(:explorer, Explorer.Chain.Fetcher.LookUpSmartContractSourcesOnDemand, fetch_interval: 10000) _request = get(conn, "/api/v2/smart-contracts/#{Address.checksum(address.hash)}") + refute_receive %Phoenix.Socket.Message{ + payload: %{}, + event: "eth_bytecode_db_lookup_started", + topic: ^topic + }, + :timer.seconds(1) + + refute_receive %Phoenix.Socket.Message{ + payload: %{}, + event: "smart_contract_was_not_verified", + topic: ^topic + }, + :timer.seconds(1) + + refute_receive %Phoenix.Socket.Message{ + payload: %{}, + event: "smart_contract_was_verified", + topic: ^topic + }, + :timer.seconds(1) + Application.put_env(:block_scout_web, :chain_id, old_chain_id) Application.put_env(:explorer, Explorer.Chain.Fetcher.LookUpSmartContractSourcesOnDemand, old_interval_env) Application.put_env(:explorer, Explorer.SmartContract.RustVerifierInterfaceBehaviour, old_env) diff --git a/apps/explorer/config/test.exs b/apps/explorer/config/test.exs index f47e241395..955f9df842 100644 --- a/apps/explorer/config/test.exs +++ b/apps/explorer/config/test.exs @@ -12,7 +12,8 @@ config :explorer, Explorer.Repo, ownership_timeout: :timer.minutes(7), timeout: :timer.seconds(60), queue_target: 1000, - migration_lock: nil + migration_lock: nil, + log: false # Configure API database config :explorer, Explorer.Repo.Replica1, @@ -26,7 +27,8 @@ config :explorer, Explorer.Repo.Replica1, enable_caching_implementation_data_of_proxy: true, avg_block_time_as_ttl_cached_implementation_data_of_proxy: false, fallback_ttl_cached_implementation_data_of_proxy: :timer.seconds(20), - implementation_data_fetching_timeout: :timer.seconds(20) + implementation_data_fetching_timeout: :timer.seconds(20), + log: false # Configure API database config :explorer, Explorer.Repo.Account, diff --git a/apps/explorer/lib/explorer/chain/events/publisher.ex b/apps/explorer/lib/explorer/chain/events/publisher.ex index 21b8d168af..3dca04f31f 100644 --- a/apps/explorer/lib/explorer/chain/events/publisher.ex +++ b/apps/explorer/lib/explorer/chain/events/publisher.ex @@ -3,7 +3,7 @@ defmodule Explorer.Chain.Events.Publisher do Publishes events related to the Chain context. """ - @allowed_events ~w(addresses address_coin_balances address_token_balances address_current_token_balances blocks block_rewards internal_transactions last_block_number polygon_edge_reorg_block token_transfers transactions contract_verification_result token_total_supply changed_bytecode smart_contract_was_verified zkevm_confirmed_batches)a + @allowed_events ~w(addresses address_coin_balances address_token_balances address_current_token_balances blocks block_rewards internal_transactions last_block_number polygon_edge_reorg_block token_transfers transactions contract_verification_result token_total_supply changed_bytecode smart_contract_was_verified zkevm_confirmed_batches eth_bytecode_db_lookup_started smart_contract_was_not_verified)a def broadcast(_data, false), do: :ok diff --git a/apps/explorer/lib/explorer/chain/events/subscriber.ex b/apps/explorer/lib/explorer/chain/events/subscriber.ex index 9d049758ec..f2aa49f61f 100644 --- a/apps/explorer/lib/explorer/chain/events/subscriber.ex +++ b/apps/explorer/lib/explorer/chain/events/subscriber.ex @@ -3,7 +3,7 @@ defmodule Explorer.Chain.Events.Subscriber do Subscribes to events related to the Chain context. """ - @allowed_broadcast_events ~w(addresses address_coin_balances address_token_balances address_current_token_balances blocks block_rewards internal_transactions last_block_number polygon_edge_reorg_block token_transfers transactions contract_verification_result token_total_supply changed_bytecode smart_contract_was_verified zkevm_confirmed_batches)a + @allowed_broadcast_events ~w(addresses address_coin_balances address_token_balances address_current_token_balances blocks block_rewards internal_transactions last_block_number polygon_edge_reorg_block token_transfers transactions contract_verification_result token_total_supply changed_bytecode smart_contract_was_verified zkevm_confirmed_batches eth_bytecode_db_lookup_started smart_contract_was_not_verified)a @allowed_broadcast_types ~w(catchup realtime on_demand contract_verification_result)a diff --git a/apps/explorer/lib/explorer/chain/fetcher/look_up_smart_contract_sources_on_demand.ex b/apps/explorer/lib/explorer/chain/fetcher/look_up_smart_contract_sources_on_demand.ex index 1e6bd9e6eb..145b77368a 100644 --- a/apps/explorer/lib/explorer/chain/fetcher/look_up_smart_contract_sources_on_demand.ex +++ b/apps/explorer/lib/explorer/chain/fetcher/look_up_smart_contract_sources_on_demand.ex @@ -34,6 +34,8 @@ defmodule Explorer.Chain.Fetcher.LookUpSmartContractSourcesOnDemand do end defp fetch_sources(address, only_full?) do + Publisher.broadcast(%{eth_bytecode_db_lookup_started: [address.hash]}, :on_demand) + creation_tx_input = contract_creation_input(address.hash) with {:ok, %{"sourceType" => type, "matchType" => match_type} = source} <- @@ -45,6 +47,7 @@ defmodule Explorer.Chain.Fetcher.LookUpSmartContractSourcesOnDemand do Publisher.broadcast(%{smart_contract_was_verified: [address.hash]}, :on_demand) else _ -> + Publisher.broadcast(%{smart_contract_was_not_verified: [address.hash]}, :on_demand) false end end