From 21381914aa3d7ec15c7e799c2c7dd66cd35a6e40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9D=D0=B8=D0=BA=D0=B8=D1=82=D0=B0=20=D0=9F=D0=BE=D0=B7?= =?UTF-8?q?=D0=B4=D0=BD=D1=8F=D0=BA=D0=BE=D0=B2?= Date: Mon, 5 Dec 2022 13:23:56 +0300 Subject: [PATCH] Fix bug with proxy for twins --- CHANGELOG.md | 2 +- apps/explorer/lib/explorer/chain.ex | 17 ++++-- .../lib/explorer/chain/smart_contract.ex | 54 ++++++++++++------- 3 files changed, 48 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 49f87e0e87..290d23f844 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ### Features - [#6544](https://github.com/blockscout/blockscout/pull/6544) - API improvements -- [#5561](https://github.com/blockscout/blockscout/pull/5561), [#6523](https://github.com/blockscout/blockscout/pull/6523) - Improve working with contracts implementations +- [#5561](https://github.com/blockscout/blockscout/pull/5561), [#6523](https://github.com/blockscout/blockscout/pull/6523), [#6549](https://github.com/blockscout/blockscout/pull/6549) - Improve working with contracts implementations - [#6401](https://github.com/blockscout/blockscout/pull/6401) - Add Sol2Uml contract visualization - [#6481](https://github.com/blockscout/blockscout/pull/6481) - Smart contract verification improvements - [#6444](https://github.com/blockscout/blockscout/pull/6444) - Add support for yul verification via rust microservice diff --git a/apps/explorer/lib/explorer/chain.ex b/apps/explorer/lib/explorer/chain.ex index 3d2b93bc36..9e8c46c6a5 100644 --- a/apps/explorer/lib/explorer/chain.ex +++ b/apps/explorer/lib/explorer/chain.ex @@ -1384,7 +1384,10 @@ defmodule Explorer.Chain do address_verified_twin_contract_updated = address_verified_twin_contract |> Map.put(:address_hash, hash) - |> Map.put_new(:metadata_from_verified_twin, true) + |> Map.put(:metadata_from_verified_twin, true) + |> Map.put(:implementation_address_hash, nil) + |> Map.put(:implementation_name, nil) + |> Map.put(:implementation_fetched_at, nil) address_result |> Map.put(:smart_contract, address_verified_twin_contract_updated) @@ -1902,7 +1905,10 @@ defmodule Explorer.Chain do address_verified_twin_contract_updated = address_verified_twin_contract |> Map.put(:address_hash, hash) - |> Map.put_new(:metadata_from_verified_twin, true) + |> Map.put(:metadata_from_verified_twin, true) + |> Map.put(:implementation_address_hash, nil) + |> Map.put(:implementation_name, nil) + |> Map.put(:implementation_fetched_at, nil) address_result |> Map.put(:smart_contract, address_verified_twin_contract_updated) @@ -4349,9 +4355,10 @@ defmodule Explorer.Chain do if address_verified_twin_contract do address_verified_twin_contract |> Map.put(:address_hash, address_hash) - |> Map.put(:implementation_address_hash, current_smart_contract.implementation_address_hash) - |> Map.put(:implementation_name, current_smart_contract.implementation_name) - |> Map.put(:implementation_fetched_at, current_smart_contract.implementation_fetched_at) + |> Map.put(:metadata_from_verified_twin, true) + |> Map.put(:implementation_address_hash, nil) + |> Map.put(:implementation_name, nil) + |> Map.put(:implementation_fetched_at, nil) else current_smart_contract end diff --git a/apps/explorer/lib/explorer/chain/smart_contract.ex b/apps/explorer/lib/explorer/chain/smart_contract.ex index bd72f3ad2b..043077c195 100644 --- a/apps/explorer/lib/explorer/chain/smart_contract.ex +++ b/apps/explorer/lib/explorer/chain/smart_contract.ex @@ -261,6 +261,7 @@ defmodule Explorer.Chain.SmartContract do field(:implementation_address_hash, Hash.Address, default: nil) field(:autodetect_constructor_args, :boolean, virtual: true) field(:is_yul, :boolean, virtual: true) + field(:metadata_from_verified_twin, :boolean, virtual: true) has_many( :decompiled_smart_contracts, @@ -529,7 +530,11 @@ defmodule Explorer.Chain.SmartContract do def proxy_contract?(_), do: false - def get_implementation_address_hash(%__MODULE__{abi: nil}), do: false + def get_implementation_address_hash(%__MODULE__{abi: nil}), do: {nil, nil} + + def get_implementation_address_hash(%__MODULE__{metadata_from_verified_twin: true} = smart_contract) do + get_implementation_address_hash({:updated, smart_contract}) + end def get_implementation_address_hash( %__MODULE__{ @@ -540,7 +545,7 @@ defmodule Explorer.Chain.SmartContract do updated_smart_contract = if Application.get_env(:explorer, :enable_caching_implementation_data_of_proxy) && check_implementation_refetch_neccessity(implementation_fetched_at) do - Chain.address_hash_to_smart_contract(address_hash) + Chain.address_hash_to_smart_contract_without_twin(address_hash) else smart_contract end @@ -555,11 +560,13 @@ defmodule Explorer.Chain.SmartContract do abi: abi, implementation_address_hash: implementation_address_hash_from_db, implementation_name: implementation_name_from_db, - implementation_fetched_at: implementation_fetched_at + implementation_fetched_at: implementation_fetched_at, + metadata_from_verified_twin: metadata_from_verified_twin }} ) do if check_implementation_refetch_neccessity(implementation_fetched_at) do - get_implementation_address_hash_task = Task.async(fn -> get_implementation_address_hash(address_hash, abi) end) + get_implementation_address_hash_task = + Task.async(fn -> get_implementation_address_hash(address_hash, abi, metadata_from_verified_twin) end) timeout = Application.get_env(:explorer, :implementation_data_fetching_timeout) @@ -624,8 +631,9 @@ defmodule Explorer.Chain.SmartContract do end end - @spec get_implementation_address_hash(Hash.Address.t(), list()) :: {String.t() | nil, String.t() | nil} - defp get_implementation_address_hash(proxy_address_hash, abi) + @spec get_implementation_address_hash(Hash.Address.t(), list(), boolean() | nil) :: + {String.t() | nil, String.t() | nil} + defp get_implementation_address_hash(proxy_address_hash, abi, metadata_from_verified_twin) when not is_nil(proxy_address_hash) and not is_nil(abi) do implementation_method_abi = abi @@ -651,10 +659,10 @@ defmodule Explorer.Chain.SmartContract do get_implementation_address_hash_eip_1967(proxy_address_hash) end - save_implementation_data(implementation_address, proxy_address_hash) + save_implementation_data(implementation_address, proxy_address_hash, metadata_from_verified_twin) end - defp get_implementation_address_hash(proxy_address_hash, abi) when is_nil(proxy_address_hash) or is_nil(abi) do + defp get_implementation_address_hash(_proxy_address_hash, _abi, _) do {nil, nil} end @@ -794,28 +802,30 @@ defmodule Explorer.Chain.SmartContract do abi_decode_address_output(implementation_address) end - defp save_implementation_data(nil, _), do: {nil, nil} + defp save_implementation_data(nil, _, _), do: {nil, nil} - defp save_implementation_data(empty_address_hash_string, proxy_address_hash) + defp save_implementation_data(empty_address_hash_string, proxy_address_hash, metadata_from_verified_twin) when empty_address_hash_string in [ "0x", "0x0", "0x0000000000000000000000000000000000000000000000000000000000000000", @burn_address_hash_str ] do - proxy_address_hash - |> Chain.address_hash_to_smart_contract_without_twin() - |> changeset(%{ - implementation_name: nil, - implementation_address_hash: nil, - implementation_fetched_at: DateTime.utc_now() - }) - |> Repo.update() + if is_nil(metadata_from_verified_twin) or !metadata_from_verified_twin do + proxy_address_hash + |> Chain.address_hash_to_smart_contract_without_twin() + |> changeset(%{ + implementation_name: nil, + implementation_address_hash: nil, + implementation_fetched_at: DateTime.utc_now() + }) + |> Repo.update() + end {:empty, :empty} end - defp save_implementation_data(implementation_address_hash_string, proxy_address_hash) + defp save_implementation_data(implementation_address_hash_string, proxy_address_hash, _) when is_binary(implementation_address_hash_string) do with {:ok, address_hash} <- Chain.string_to_address_hash(implementation_address_hash_string), proxy_contract <- Chain.address_hash_to_smart_contract_without_twin(proxy_address_hash), @@ -845,6 +855,12 @@ defmodule Explorer.Chain.SmartContract do {implementation_address_hash_string, nil} + true -> + {:ok, address_hash} = Chain.string_to_address_hash(implementation_address_hash_string) + smart_contract = Chain.address_hash_to_smart_contract(address_hash) + + {implementation_address_hash_string, smart_contract && smart_contract.name} + _ -> {implementation_address_hash_string, nil} end