Null round handling (#9403)
* Null round handling * Add repo for filecoin chain type * Add repo for filecoin chain type * Modify gas price constraint for Filecoin as it for PolygonEdge * Fix null round heights db type * Add filecoin to chain-type matrix --------- Co-authored-by: Viktor Baranov <baranov.viktor.27@gmail.com>dependabot/hex/briefly-a533393
parent
15f708e1fd
commit
42425edef8
@ -0,0 +1,25 @@ |
||||
# credo:disable-for-this-file |
||||
defmodule Explorer.Chain.BlockNumberHelper do |
||||
@moduledoc """ |
||||
Functions to operate with block numbers based on null round heights (applicable for CHAIN_TYPE=filecoin) |
||||
""" |
||||
|
||||
def previous_block_number(number), do: neighbor_block_number(number, :previous) |
||||
|
||||
def next_block_number(number), do: neighbor_block_number(number, :next) |
||||
|
||||
case Application.compile_env(:explorer, :chain_type) do |
||||
"filecoin" -> |
||||
def null_rounds_count, do: Explorer.Chain.NullRoundHeight.total() |
||||
|
||||
defp neighbor_block_number(number, direction), |
||||
do: Explorer.Chain.NullRoundHeight.neighbor_block_number(number, direction) |
||||
|
||||
_ -> |
||||
def null_rounds_count, do: 0 |
||||
defp neighbor_block_number(number, direction), do: move_by_one(number, direction) |
||||
end |
||||
|
||||
def move_by_one(number, :previous), do: number - 1 |
||||
def move_by_one(number, :next), do: number + 1 |
||||
end |
@ -0,0 +1,81 @@ |
||||
defmodule Explorer.Chain.NullRoundHeight do |
||||
@moduledoc """ |
||||
A null round is formed when a block at height N links to a block at height N-2 instead of N-1 |
||||
""" |
||||
|
||||
use Explorer.Schema |
||||
|
||||
alias Explorer.Repo |
||||
|
||||
@primary_key false |
||||
schema "null_round_heights" do |
||||
field(:height, :integer, primary_key: true) |
||||
end |
||||
|
||||
def changeset(null_round_height \\ %__MODULE__{}, params) do |
||||
null_round_height |
||||
|> cast(params, [:height]) |
||||
|> validate_required([:height]) |
||||
|> unique_constraint(:height) |
||||
end |
||||
|
||||
def total do |
||||
Repo.aggregate(__MODULE__, :count) |
||||
end |
||||
|
||||
def insert_heights(heights) do |
||||
params = |
||||
heights |
||||
|> Enum.uniq() |
||||
|> Enum.map(&%{height: &1}) |
||||
|
||||
Repo.insert_all(__MODULE__, params, on_conflict: :nothing) |
||||
end |
||||
|
||||
defp find_neighbor_from_previous(previous_null_rounds, number, direction) do |
||||
previous_null_rounds |
||||
|> Enum.reduce_while({number, nil}, fn height, {current, _result} -> |
||||
if height == move_by_one(current, direction) do |
||||
{:cont, {height, nil}} |
||||
else |
||||
{:halt, {nil, move_by_one(current, direction)}} |
||||
end |
||||
end) |
||||
|> elem(1) |
||||
|> case do |
||||
nil -> |
||||
previous_null_rounds |
||||
|> List.last() |
||||
|> neighbor_block_number(direction) |
||||
|
||||
number -> |
||||
number |
||||
end |
||||
end |
||||
|
||||
def neighbor_block_number(number, direction) do |
||||
number |
||||
|> neighbors_query(direction) |
||||
|> select([nrh], nrh.height) |
||||
|> Repo.all() |
||||
|> case do |
||||
[] -> |
||||
move_by_one(number, direction) |
||||
|
||||
previous_null_rounds -> |
||||
find_neighbor_from_previous(previous_null_rounds, number, direction) |
||||
end |
||||
end |
||||
|
||||
defp move_by_one(number, :previous), do: number - 1 |
||||
defp move_by_one(number, :next), do: number + 1 |
||||
|
||||
@batch_size 5 |
||||
defp neighbors_query(number, :previous) do |
||||
from(nrh in __MODULE__, where: nrh.height < ^number, order_by: [desc: :height], limit: @batch_size) |
||||
end |
||||
|
||||
defp neighbors_query(number, :next) do |
||||
from(nrh in __MODULE__, where: nrh.height > ^number, order_by: [asc: :height], limit: @batch_size) |
||||
end |
||||
end |
@ -0,0 +1,15 @@ |
||||
defmodule Explorer.Repo.Filecoin.Migrations.ModifyCollatedGasPriceConstraint do |
||||
use Ecto.Migration |
||||
|
||||
def change do |
||||
execute("ALTER TABLE transactions DROP CONSTRAINT collated_gas_price") |
||||
|
||||
create( |
||||
constraint( |
||||
:transactions, |
||||
:collated_gas_price, |
||||
check: "block_hash IS NULL OR gas_price IS NOT NULL OR max_fee_per_gas IS NOT NULL" |
||||
) |
||||
) |
||||
end |
||||
end |
@ -0,0 +1,9 @@ |
||||
defmodule Explorer.Repo.Filecoin.Migrations.CreateNullRoundHeights do |
||||
use Ecto.Migration |
||||
|
||||
def change do |
||||
create table(:null_round_heights, primary_key: false) do |
||||
add(:height, :integer, primary_key: true) |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,9 @@ |
||||
defmodule Explorer.Repo.Filecoin.Migrations.ChangeNullRoundHeightsHeightType do |
||||
use Ecto.Migration |
||||
|
||||
def change do |
||||
alter table(:null_round_heights) do |
||||
modify(:height, :bigint) |
||||
end |
||||
end |
||||
end |
Loading…
Reference in new issue