Skip to content

Commit 3a8f3fb

Browse files
vbaranovjagdeep sidhu
authored andcommitted
Merge pull request blockscout#5697 from blockscout/vb-ignore-gas-price-round-for-small-values
Gas price oracle: ignore gas price rounding for values less than 0.01
1 parent a05e38f commit 3a8f3fb

File tree

4 files changed

+85
-284
lines changed

4 files changed

+85
-284
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
### Features
44

55
### Fixes
6+
- [#5697](https://github.com/blockscout/blockscout/pull/5697) - Gas price oracle: ignore gas price rounding for values less than 0.01
67
- [#5690](https://github.com/blockscout/blockscout/pull/5690) - Allow special characters for password in DB URL parser
78

89
### Chore

apps/explorer/lib/explorer/chain.ex

Lines changed: 0 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -2954,73 +2954,6 @@ defmodule Explorer.Chain do
29542954
end
29552955
end
29562956

2957-
def get_average_gas_price(num_of_blocks, safelow_percentile, average_percentile, fast_percentile) do
2958-
lates_gas_price_query =
2959-
from(
2960-
block in Block,
2961-
left_join: transaction in assoc(block, :transactions),
2962-
where: block.consensus == true,
2963-
where: transaction.status == ^1,
2964-
where: transaction.gas_price > ^0,
2965-
group_by: block.number,
2966-
order_by: [desc: block.number],
2967-
select: min(transaction.gas_price),
2968-
limit: ^num_of_blocks
2969-
)
2970-
2971-
latest_gas_prices =
2972-
lates_gas_price_query
2973-
|> Repo.all(timeout: :infinity)
2974-
2975-
latest_ordered_gas_prices =
2976-
latest_gas_prices
2977-
|> Enum.map(fn %Explorer.Chain.Wei{value: gas_price} -> Decimal.to_integer(gas_price) end)
2978-
2979-
safelow_gas_price = gas_price_percentile_to_gwei(latest_ordered_gas_prices, safelow_percentile)
2980-
average_gas_price = gas_price_percentile_to_gwei(latest_ordered_gas_prices, average_percentile)
2981-
fast_gas_price = gas_price_percentile_to_gwei(latest_ordered_gas_prices, fast_percentile)
2982-
2983-
gas_prices = %{
2984-
"slow" => safelow_gas_price,
2985-
"average" => average_gas_price,
2986-
"fast" => fast_gas_price
2987-
}
2988-
2989-
{:ok, gas_prices}
2990-
catch
2991-
error ->
2992-
{:error, error}
2993-
end
2994-
2995-
defp gas_price_percentile_to_gwei(gas_prices, percentile) do
2996-
safelow_gas_price_wei = percentile(gas_prices, percentile)
2997-
2998-
if safelow_gas_price_wei do
2999-
safelow_gas_price_gwei = Wei.to(%Explorer.Chain.Wei{value: Decimal.from_float(safelow_gas_price_wei)}, :gwei)
3000-
3001-
safelow_gas_price_gwei
3002-
|> Decimal.to_float()
3003-
|> Float.ceil(2)
3004-
else
3005-
nil
3006-
end
3007-
end
3008-
3009-
@spec percentile(list, number) :: number | nil
3010-
defp percentile([], _), do: nil
3011-
defp percentile([x], _), do: x
3012-
defp percentile(list, 0), do: Enum.min(list)
3013-
defp percentile(list, 100), do: Enum.max(list)
3014-
3015-
defp percentile(list, n) when is_list(list) and is_number(n) do
3016-
s = Enum.sort(list)
3017-
r = n / 100.0 * (length(list) - 1)
3018-
f = :erlang.trunc(r)
3019-
lower = Enum.at(s, f)
3020-
upper = Enum.at(s, f + 1)
3021-
lower + (upper - lower) * (r - f)
3022-
end
3023-
30242957
@spec upsert_last_fetched_counter(map()) :: {:ok, LastFetchedCounter.t()} | {:error, Ecto.Changeset.t()}
30252958
def upsert_last_fetched_counter(params) do
30262959
changeset = LastFetchedCounter.changeset(%LastFetchedCounter{}, params)

apps/explorer/lib/explorer/chain/cache/gas_price_oracle.ex

Lines changed: 84 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,18 @@ defmodule Explorer.Chain.Cache.GasPriceOracle do
55

66
require Logger
77

8+
import Ecto.Query,
9+
only: [
10+
from: 2
11+
]
12+
13+
alias Explorer.Chain.{
14+
Block,
15+
Wei
16+
}
17+
18+
alias Explorer.Repo
19+
820
@default_cache_period :timer.seconds(30)
921

1022
@num_of_blocks (case Integer.parse(System.get_env("GAS_PRICE_ORACLE_NUM_OF_BLOCKS", "200")) do
@@ -35,7 +47,43 @@ defmodule Explorer.Chain.Cache.GasPriceOracle do
3547
ttl_check_interval: :timer.minutes(5),
3648
callback: &async_task_on_deletion(&1)
3749

38-
alias Explorer.Chain
50+
def get_average_gas_price(num_of_blocks, safelow_percentile, average_percentile, fast_percentile) do
51+
lates_gas_price_query =
52+
from(
53+
block in Block,
54+
left_join: transaction in assoc(block, :transactions),
55+
where: block.consensus == true,
56+
where: transaction.status == ^1,
57+
where: transaction.gas_price > ^0,
58+
group_by: block.number,
59+
order_by: [desc: block.number],
60+
select: min(transaction.gas_price),
61+
limit: ^num_of_blocks
62+
)
63+
64+
latest_gas_prices =
65+
lates_gas_price_query
66+
|> Repo.all(timeout: :infinity)
67+
68+
latest_ordered_gas_prices =
69+
latest_gas_prices
70+
|> Enum.map(fn %Wei{value: gas_price} -> Decimal.to_integer(gas_price) end)
71+
72+
safelow_gas_price = gas_price_percentile_to_gwei(latest_ordered_gas_prices, safelow_percentile)
73+
average_gas_price = gas_price_percentile_to_gwei(latest_ordered_gas_prices, average_percentile)
74+
fast_gas_price = gas_price_percentile_to_gwei(latest_ordered_gas_prices, fast_percentile)
75+
76+
gas_prices = %{
77+
"slow" => safelow_gas_price,
78+
"average" => average_gas_price,
79+
"fast" => fast_gas_price
80+
}
81+
82+
{:ok, gas_prices}
83+
catch
84+
error ->
85+
{:error, error}
86+
end
3987

4088
defp handle_fallback(:gas_prices) do
4189
# This will get the task PID if one exists and launch a new task if not
@@ -51,7 +99,7 @@ defmodule Explorer.Chain.Cache.GasPriceOracle do
5199
{:ok, task} =
52100
Task.start(fn ->
53101
try do
54-
result = Chain.get_average_gas_price(@num_of_blocks, @safelow, @average, @fast)
102+
result = get_average_gas_price(@num_of_blocks, @safelow, @average, @fast)
55103

56104
set_all(result)
57105
rescue
@@ -67,6 +115,40 @@ defmodule Explorer.Chain.Cache.GasPriceOracle do
67115
{:update, task}
68116
end
69117

118+
defp gas_price_percentile_to_gwei(gas_prices, percentile) do
119+
gas_price_wei = percentile(gas_prices, percentile)
120+
121+
if gas_price_wei do
122+
gas_price_gwei = Wei.to(%Wei{value: Decimal.from_float(gas_price_wei)}, :gwei)
123+
124+
gas_price_gwei_float = gas_price_gwei |> Decimal.to_float()
125+
126+
if gas_price_gwei_float > 0.01 do
127+
gas_price_gwei_float
128+
|> Float.ceil(2)
129+
else
130+
gas_price_gwei_float
131+
end
132+
else
133+
nil
134+
end
135+
end
136+
137+
@spec percentile(list, number) :: number | nil
138+
defp percentile([], _), do: nil
139+
defp percentile([x], _), do: x
140+
defp percentile(list, 0), do: Enum.min(list)
141+
defp percentile(list, 100), do: Enum.max(list)
142+
143+
defp percentile(list, n) when is_list(list) and is_number(n) do
144+
s = Enum.sort(list)
145+
r = n / 100.0 * (length(list) - 1)
146+
f = :erlang.trunc(r)
147+
lower = Enum.at(s, f)
148+
upper = Enum.at(s, f + 1)
149+
lower + (upper - lower) * (r - f)
150+
end
151+
70152
# By setting this as a `callback` an async task will be started each time the
71153
# `gas_prices` expires (unless there is one already running)
72154
defp async_task_on_deletion({:delete, _, :gas_prices}), do: get_async_task()

0 commit comments

Comments
 (0)