Manage proxy implementation ttl via avg block time

pull/9155/head
Viktor Baranov 10 months ago
parent 502dec051c
commit e6b39be251
  1. 1
      CHANGELOG.md
  2. 10
      apps/explorer/config/test.exs
  3. 14
      apps/explorer/lib/explorer/chain/smart_contract.ex
  4. 89
      apps/explorer/test/explorer/chain/smart_contract_test.exs
  5. 11
      config/runtime.exs

@ -4,6 +4,7 @@
### Features ### Features
- [#9155](https://github.com/blockscout/blockscout/pull/9155) - Allow bypassing avg block time in proxy implementation re-fetch ttl calculation
- [#9072](https://github.com/blockscout/blockscout/pull/9072) - Add tracing by block logic for geth - [#9072](https://github.com/blockscout/blockscout/pull/9072) - Add tracing by block logic for geth
- [#9056](https://github.com/blockscout/blockscout/pull/9056) - Noves.fi API proxy - [#9056](https://github.com/blockscout/blockscout/pull/9056) - Noves.fi API proxy

@ -24,12 +24,14 @@ config :explorer, Explorer.Repo.Replica1,
ownership_timeout: :timer.minutes(1), ownership_timeout: :timer.minutes(1),
timeout: :timer.seconds(60), timeout: :timer.seconds(60),
queue_target: 1000, queue_target: 1000,
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),
log: false log: false
config :explorer, :proxy,
caching_implementation_data_enabled: true,
implementation_data_ttl_via_avg_block_time: false,
fallback_cached_implementation_data_ttl: :timer.seconds(20),
implementation_data_fetching_timeout: :timer.seconds(20)
# Configure API database # Configure API database
config :explorer, Explorer.Repo.Account, config :explorer, Explorer.Repo.Account,
database: "explorer_test_account", database: "explorer_test_account",

@ -516,7 +516,7 @@ defmodule Explorer.Chain.SmartContract do
options options
) do ) do
updated_smart_contract = updated_smart_contract =
if Application.get_env(:explorer, :enable_caching_implementation_data_of_proxy) && if Application.get_env(:explorer, :proxy)[:caching_implementation_data_enabled] &&
check_implementation_refetch_necessity(implementation_fetched_at) do check_implementation_refetch_necessity(implementation_fetched_at) do
address_hash_to_smart_contract_without_twin(address_hash, options) address_hash_to_smart_contract_without_twin(address_hash, options)
else else
@ -544,7 +544,7 @@ defmodule Explorer.Chain.SmartContract do
Proxy.fetch_implementation_address_hash(address_hash, abi, metadata_from_verified_twin, options) Proxy.fetch_implementation_address_hash(address_hash, abi, metadata_from_verified_twin, options)
end) end)
timeout = Application.get_env(:explorer, :implementation_data_fetching_timeout) timeout = Application.get_env(:explorer, :proxy)[:implementation_data_fetching_timeout]
case Task.yield(get_implementation_address_hash_task, timeout) || case Task.yield(get_implementation_address_hash_task, timeout) ||
Task.ignore(get_implementation_address_hash_task) do Task.ignore(get_implementation_address_hash_task) do
@ -1182,15 +1182,15 @@ defmodule Explorer.Chain.SmartContract do
defp check_implementation_refetch_necessity(nil), do: true defp check_implementation_refetch_necessity(nil), do: true
defp check_implementation_refetch_necessity(timestamp) do defp check_implementation_refetch_necessity(timestamp) do
if Application.get_env(:explorer, :enable_caching_implementation_data_of_proxy) do if Application.get_env(:explorer, :proxy)[:caching_implementation_data_enabled] do
now = DateTime.utc_now() now = DateTime.utc_now()
average_block_time = get_average_block_time() average_block_time = get_average_block_time_for_implementation_refetch()
fresh_time_distance = fresh_time_distance =
case average_block_time do case average_block_time do
0 -> 0 ->
Application.get_env(:explorer, :fallback_ttl_cached_implementation_data_of_proxy) Application.get_env(:explorer, :proxy)[:fallback_cached_implementation_data_ttl]
time -> time ->
round(time) round(time)
@ -1204,8 +1204,8 @@ defmodule Explorer.Chain.SmartContract do
end end
end end
defp get_average_block_time do defp get_average_block_time_for_implementation_refetch do
if Application.get_env(:explorer, :avg_block_time_as_ttl_cached_implementation_data_of_proxy) do if Application.get_env(:explorer, :proxy)[:implementation_data_ttl_via_avg_block_time] do
case AverageBlockTime.average_block_time() do case AverageBlockTime.average_block_time() do
{:error, :disabled} -> {:error, :disabled} ->
0 0

@ -15,8 +15,13 @@ defmodule Explorer.Chain.SmartContractTest do
test "check proxy_contract/1 function" do test "check proxy_contract/1 function" do
smart_contract = insert(:smart_contract) smart_contract = insert(:smart_contract)
Application.put_env(:explorer, :fallback_ttl_cached_implementation_data_of_proxy, :timer.seconds(20)) proxy =
Application.put_env(:explorer, :implementation_data_fetching_timeout, :timer.seconds(20)) :explorer
|> Application.get_env(:proxy)
|> Keyword.replace(:fallback_cached_implementation_data_ttl, :timer.seconds(20))
|> Keyword.replace(:implementation_data_fetching_timeout, :timer.seconds(20))
Application.put_env(:explorer, :proxy, proxy)
refute smart_contract.implementation_fetched_at refute smart_contract.implementation_fetched_at
@ -26,7 +31,12 @@ defmodule Explorer.Chain.SmartContractTest do
verify!(EthereumJSONRPC.Mox) verify!(EthereumJSONRPC.Mox)
assert_implementation_never_fetched(smart_contract.address_hash) assert_implementation_never_fetched(smart_contract.address_hash)
Application.put_env(:explorer, :fallback_ttl_cached_implementation_data_of_proxy, 0) proxy =
:explorer
|> Application.get_env(:proxy)
|> Keyword.replace(:fallback_cached_implementation_data_ttl, 0)
Application.put_env(:explorer, :proxy, proxy)
get_eip1967_implementation_error_response() get_eip1967_implementation_error_response()
refute Proxy.proxy_contract?(smart_contract) refute Proxy.proxy_contract?(smart_contract)
@ -42,10 +52,22 @@ defmodule Explorer.Chain.SmartContractTest do
verify!(EthereumJSONRPC.Mox) verify!(EthereumJSONRPC.Mox)
assert_implementation_address(smart_contract.address_hash) assert_implementation_address(smart_contract.address_hash)
Application.put_env(:explorer, :fallback_ttl_cached_implementation_data_of_proxy, :timer.seconds(20)) proxy =
:explorer
|> Application.get_env(:proxy)
|> Keyword.replace(:fallback_cached_implementation_data_ttl, :timer.seconds(20))
Application.put_env(:explorer, :proxy, proxy)
assert Proxy.proxy_contract?(smart_contract) assert Proxy.proxy_contract?(smart_contract)
Application.put_env(:explorer, :fallback_ttl_cached_implementation_data_of_proxy, 0) proxy =
:explorer
|> Application.get_env(:proxy)
|> Keyword.replace(:fallback_cached_implementation_data_ttl, 0)
Application.put_env(:explorer, :proxy, proxy)
get_eip1967_implementation_non_zero_address() get_eip1967_implementation_non_zero_address()
assert Proxy.proxy_contract?(smart_contract) assert Proxy.proxy_contract?(smart_contract)
verify!(EthereumJSONRPC.Mox) verify!(EthereumJSONRPC.Mox)
@ -59,8 +81,13 @@ defmodule Explorer.Chain.SmartContractTest do
smart_contract = insert(:smart_contract) smart_contract = insert(:smart_contract)
implementation_smart_contract = insert(:smart_contract, name: "proxy") implementation_smart_contract = insert(:smart_contract, name: "proxy")
Application.put_env(:explorer, :fallback_ttl_cached_implementation_data_of_proxy, :timer.seconds(20)) proxy =
Application.put_env(:explorer, :implementation_data_fetching_timeout, :timer.seconds(20)) :explorer
|> Application.get_env(:proxy)
|> Keyword.replace(:fallback_cached_implementation_data_ttl, :timer.seconds(20))
|> Keyword.replace(:implementation_data_fetching_timeout, :timer.seconds(20))
Application.put_env(:explorer, :proxy, proxy)
refute smart_contract.implementation_fetched_at refute smart_contract.implementation_fetched_at
@ -71,7 +98,12 @@ defmodule Explorer.Chain.SmartContractTest do
assert_implementation_never_fetched(smart_contract.address_hash) assert_implementation_never_fetched(smart_contract.address_hash)
# extract proxy info from db # extract proxy info from db
Application.put_env(:explorer, :fallback_ttl_cached_implementation_data_of_proxy, 0) proxy =
:explorer
|> Application.get_env(:proxy)
|> Keyword.replace(:fallback_cached_implementation_data_ttl, 0)
Application.put_env(:explorer, :proxy, proxy)
string_implementation_address_hash = to_string(implementation_smart_contract.address_hash) string_implementation_address_hash = to_string(implementation_smart_contract.address_hash)
@ -116,7 +148,12 @@ defmodule Explorer.Chain.SmartContractTest do
contract_1 = SmartContract.address_hash_to_smart_contract(smart_contract.address_hash) contract_1 = SmartContract.address_hash_to_smart_contract(smart_contract.address_hash)
Application.put_env(:explorer, :fallback_ttl_cached_implementation_data_of_proxy, :timer.seconds(20)) proxy =
:explorer
|> Application.get_env(:proxy)
|> Keyword.replace(:fallback_cached_implementation_data_ttl, :timer.seconds(20))
Application.put_env(:explorer, :proxy, proxy)
assert {^string_implementation_address_hash, "proxy"} = assert {^string_implementation_address_hash, "proxy"} =
SmartContract.get_implementation_address_hash(smart_contract) SmartContract.get_implementation_address_hash(smart_contract)
@ -126,7 +163,12 @@ defmodule Explorer.Chain.SmartContractTest do
assert contract_1.implementation_fetched_at == contract_2.implementation_fetched_at && assert contract_1.implementation_fetched_at == contract_2.implementation_fetched_at &&
contract_1.updated_at == contract_2.updated_at contract_1.updated_at == contract_2.updated_at
Application.put_env(:explorer, :fallback_ttl_cached_implementation_data_of_proxy, 0) proxy =
:explorer
|> Application.get_env(:proxy)
|> Keyword.replace(:fallback_cached_implementation_data_ttl, 0)
Application.put_env(:explorer, :proxy, proxy)
get_eip1967_implementation_zero_addresses() get_eip1967_implementation_zero_addresses()
assert {^string_implementation_address_hash, "proxy"} = assert {^string_implementation_address_hash, "proxy"} =
@ -147,8 +189,13 @@ defmodule Explorer.Chain.SmartContractTest do
twin = SmartContract.address_hash_to_smart_contract(another_address.hash) twin = SmartContract.address_hash_to_smart_contract(another_address.hash)
implementation_smart_contract = insert(:smart_contract, name: "proxy") implementation_smart_contract = insert(:smart_contract, name: "proxy")
Application.put_env(:explorer, :fallback_ttl_cached_implementation_data_of_proxy, :timer.seconds(20)) proxy =
Application.put_env(:explorer, :implementation_data_fetching_timeout, :timer.seconds(20)) :explorer
|> Application.get_env(:proxy)
|> Keyword.replace(:fallback_cached_implementation_data_ttl, :timer.seconds(20))
|> Keyword.replace(:implementation_data_fetching_timeout, :timer.seconds(20))
Application.put_env(:explorer, :proxy, proxy)
# fetch nil implementation # fetch nil implementation
get_eip1967_implementation_zero_addresses() get_eip1967_implementation_zero_addresses()
@ -184,8 +231,13 @@ defmodule Explorer.Chain.SmartContractTest do
implementation_smart_contract = insert(:smart_contract, name: "proxy") implementation_smart_contract = insert(:smart_contract, name: "proxy")
Application.put_env(:explorer, :fallback_ttl_cached_implementation_data_of_proxy, :timer.seconds(20)) proxy =
Application.put_env(:explorer, :implementation_data_fetching_timeout, :timer.seconds(20)) :explorer
|> Application.get_env(:proxy)
|> Keyword.replace(:fallback_cached_implementation_data_ttl, :timer.seconds(20))
|> Keyword.replace(:implementation_data_fetching_timeout, :timer.seconds(20))
Application.put_env(:explorer, :proxy, proxy)
# fetch nil implementation # fetch nil implementation
get_eip1967_implementation_zero_addresses() get_eip1967_implementation_zero_addresses()
@ -231,8 +283,13 @@ defmodule Explorer.Chain.SmartContractTest do
implementation_smart_contract = insert(:smart_contract, name: "proxy") implementation_smart_contract = insert(:smart_contract, name: "proxy")
Application.put_env(:explorer, :fallback_ttl_cached_implementation_data_of_proxy, :timer.seconds(20)) proxy =
Application.put_env(:explorer, :implementation_data_fetching_timeout, :timer.seconds(20)) :explorer
|> Application.get_env(:proxy)
|> Keyword.replace(:fallback_cached_implementation_data_ttl, :timer.seconds(20))
|> Keyword.replace(:implementation_data_fetching_timeout, :timer.seconds(20))
Application.put_env(:explorer, :proxy, proxy)
# fetch nil implementation # fetch nil implementation
get_eip1967_implementation_zero_addresses() get_eip1967_implementation_zero_addresses()

@ -203,15 +203,18 @@ config :explorer,
do: Explorer.Chain.Events.DBSender, do: Explorer.Chain.Events.DBSender,
else: Explorer.Chain.Events.SimpleSender else: Explorer.Chain.Events.SimpleSender
), ),
enable_caching_implementation_data_of_proxy: true,
avg_block_time_as_ttl_cached_implementation_data_of_proxy: true,
fallback_ttl_cached_implementation_data_of_proxy: :timer.seconds(4),
implementation_data_fetching_timeout: :timer.seconds(2),
restricted_list: System.get_env("RESTRICTED_LIST"), restricted_list: System.get_env("RESTRICTED_LIST"),
restricted_list_key: System.get_env("RESTRICTED_LIST_KEY"), restricted_list_key: System.get_env("RESTRICTED_LIST_KEY"),
checksum_function: checksum_function && String.to_atom(checksum_function), checksum_function: checksum_function && String.to_atom(checksum_function),
elasticity_multiplier: ConfigHelper.parse_integer_env_var("EIP_1559_ELASTICITY_MULTIPLIER", 2) elasticity_multiplier: ConfigHelper.parse_integer_env_var("EIP_1559_ELASTICITY_MULTIPLIER", 2)
config :explorer, :proxy,
caching_implementation_data_enabled: true,
implementation_data_ttl_via_avg_block_time:
ConfigHelper.parse_bool_env_var("CONTRACT_PROXY_IMPLEMENTATION_TTL_VIA_AVG_BLOCK_TIME", "true"),
fallback_cached_implementation_data_ttl: :timer.seconds(4),
implementation_data_fetching_timeout: :timer.seconds(2)
config :explorer, Explorer.Chain.Events.Listener, config :explorer, Explorer.Chain.Events.Listener,
enabled: enabled:
if(disable_webapp? && disable_indexer?, if(disable_webapp? && disable_indexer?,

Loading…
Cancel
Save