feat: gas prices with base fee if no transactions (#11132)

* feat: gas prices with base fee if no transactions

* Replace wildcard with exact error

Co-authored-by: Victor Baranov <baranov.viktor.27@gmail.com>

---------

Co-authored-by: Victor Baranov <baranov.viktor.27@gmail.com>
Claire
Maxim Filonov 2 weeks ago committed by GitHub
parent b9115d9945
commit b87b06bf86
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 65
      apps/explorer/lib/explorer/chain/cache/gas_price_oracle.ex
  2. 47
      apps/explorer/test/explorer/chain/cache/gas_price_oracle_test.exs

@ -92,11 +92,7 @@ defmodule Explorer.Chain.Cache.GasPriceOracle do
from_block_query = max(from_block_acc, from_block_actual)
average_block_time =
case AverageBlockTime.average_block_time() do
{:error, _} -> nil
average_block_time -> average_block_time |> Duration.to_milliseconds()
end
average_block_time = get_average_block_time()
fee_query =
from(
@ -186,11 +182,26 @@ defmodule Explorer.Chain.Cache.GasPriceOracle do
defp merge_gas_prices(new, acc, from_block), do: Enum.take_while(new ++ acc, &(&1.block_number > from_block))
defp process_fee_data_from_db([]) do
%{
slow: nil,
average: nil,
fast: nil
}
case Block.next_block_base_fee_per_gas() do
%Decimal{} = base_fee ->
base_fee_wei = base_fee |> Wei.from(:wei)
exchange_rate = Market.get_coin_exchange_rate()
average_block_time = get_average_block_time()
%{
slow: compose_gas_price(base_fee_wei, average_block_time, exchange_rate, base_fee_wei, 0),
average: compose_gas_price(base_fee_wei, average_block_time, exchange_rate, base_fee_wei, 0),
fast: compose_gas_price(base_fee_wei, average_block_time, exchange_rate, base_fee_wei, 0)
}
_ ->
%{
slow: nil,
average: nil,
fast: nil
}
end
end
defp process_fee_data_from_db(fees) do
@ -223,13 +234,12 @@ defmodule Explorer.Chain.Cache.GasPriceOracle do
{gas_price(slow_gas_price), gas_price(average_gas_price), gas_price(fast_gas_price), nil}
end
exchange_rate_from_db = Market.get_coin_exchange_rate()
exchange_rate = Market.get_coin_exchange_rate()
%{
slow: compose_gas_price(slow_fee, slow_time, exchange_rate_from_db, base_fee_wei, slow_priority_fee_per_gas),
average:
compose_gas_price(average_fee, average_time, exchange_rate_from_db, base_fee_wei, average_priority_fee_per_gas),
fast: compose_gas_price(fast_fee, fast_time, exchange_rate_from_db, base_fee_wei, fast_priority_fee_per_gas)
slow: compose_gas_price(slow_fee, slow_time, exchange_rate, base_fee_wei, slow_priority_fee_per_gas),
average: compose_gas_price(average_fee, average_time, exchange_rate, base_fee_wei, average_priority_fee_per_gas),
fast: compose_gas_price(fast_fee, fast_time, exchange_rate, base_fee_wei, fast_priority_fee_per_gas)
}
end
@ -251,15 +261,27 @@ defmodule Explorer.Chain.Cache.GasPriceOracle do
{key, value} ->
value = if is_list(value), do: value, else: [value]
count = Enum.count(value)
{key, value |> Enum.reduce(Decimal.new(0), &Decimal.add/2) |> Decimal.div(count)}
value =
value
|> Enum.reduce(Decimal.new(0), fn
fee, sum when is_float(fee) ->
fee |> Decimal.from_float() |> Decimal.add(sum)
fee, sum ->
Decimal.add(sum, fee)
end)
|> Decimal.div(count)
{key, value}
end)
end
defp compose_gas_price(fee, time, exchange_rate_from_db, base_fee, priority_fee) do
defp compose_gas_price(fee, time, exchange_rate, base_fee, priority_fee) do
%{
price: fee |> format_wei(),
time: time && time |> Decimal.to_float(),
fiat_price: fiat_fee(fee, exchange_rate_from_db),
fiat_price: fiat_fee(fee, exchange_rate),
base_fee: base_fee |> format_wei(),
priority_fee: base_fee && priority_fee && priority_fee |> Decimal.new() |> Wei.from(:wei) |> format_wei(),
priority_fee_wei: base_fee && priority_fee && priority_fee |> Decimal.new() |> Decimal.round(),
@ -358,4 +380,11 @@ defmodule Explorer.Chain.Cache.GasPriceOracle do
end
defp async_task_on_deletion(_data), do: nil
defp get_average_block_time do
case AverageBlockTime.average_block_time() do
{:error, :disabled} -> nil
average_block_time -> average_block_time |> Duration.to_milliseconds()
end
end
end

@ -90,6 +90,53 @@ defmodule Explorer.Chain.Cache.GasPriceOracleTest do
}}, []} = GasPriceOracle.get_average_gas_price(2, 35, 60, 90)
end
test "returns base fee only gas estimation if there is no recent transactions with non-zero gas price" do
block1 =
insert(:block,
number: 100,
hash: "0x3e51328bccedee581e8ba35190216a61a5d67fd91ca528f3553142c0c7d18391",
base_fee_per_gas: 100
)
block2 =
insert(:block,
number: 101,
hash: "0x76c3da57334fffdc66c0d954dce1a910fcff13ec889a13b2d8b0b6e9440ce729",
base_fee_per_gas: 100
)
:transaction
|> insert(
status: :ok,
block_hash: block1.hash,
block_number: block1.number,
cumulative_gas_used: 884_322,
gas_used: 106_025,
index: 0,
gas_price: 0,
hash: "0xac2a7dab94d965893199e7ee01649e2d66f0787a4c558b3118c09e80d4df8269"
)
:transaction
|> insert(
status: :ok,
block_hash: block2.hash,
block_number: block2.number,
cumulative_gas_used: 884_322,
gas_used: 106_025,
index: 0,
gas_price: 0,
hash: "0x5d5c2776f96704e7845f7d3c1fbba6685ab6efd6f82b6cd11d549f3b3a46bd03"
)
assert {{:ok,
%{
average: %{base_fee: 0.01, priority_fee: +0.0, price: 0.01},
fast: %{base_fee: 0.01, priority_fee: +0.0, price: 0.01},
slow: %{base_fee: 0.01, priority_fee: +0.0, price: 0.01}
}}, []} = GasPriceOracle.get_average_gas_price(2, 35, 60, 90)
end
test "returns the same percentile values if gas price is the same over transactions" do
block1 = insert(:block, number: 100, hash: "0x3e51328bccedee581e8ba35190216a61a5d67fd91ca528f3553142c0c7d18391")
block2 = insert(:block, number: 101, hash: "0x76c3da57334fffdc66c0d954dce1a910fcff13ec889a13b2d8b0b6e9440ce729")

Loading…
Cancel
Save