Skip to content

Commit

Permalink
Merge branch 'main' into libp2p_configurable_ports
Browse files Browse the repository at this point in the history
  • Loading branch information
Arkenan authored Apr 22, 2024
2 parents 20e1d1e + 54e5c45 commit ab5b574
Show file tree
Hide file tree
Showing 7 changed files with 226 additions and 110 deletions.
70 changes: 35 additions & 35 deletions lib/lambda_ethereum_consensus/beacon/pending_blocks.ex
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ defmodule LambdaEthereumConsensus.Beacon.PendingBlocks do
@impl true
def handle_cast({:block_processed, block_root, true}, state) do
# Block is valid. We immediately check if we can process another block.
state |> Map.delete(block_root) |> then(&handle_info(:process_blocks, &1))
new_state = state |> Map.delete(block_root) |> process_blocks()
{:noreply, new_state}
end

@impl true
Expand All @@ -80,45 +81,14 @@ defmodule LambdaEthereumConsensus.Beacon.PendingBlocks do
{:noreply, state |> Map.put(block_root, {nil, :invalid})}
end

@spec handle_info(any(), state()) :: {:noreply, state()}

@doc """
Iterates through the pending blocks and adds them to the fork choice if their parent is already in the fork choice.
"""
@impl true
@spec handle_info(atom(), state()) :: {:noreply, state()}
def handle_info(:process_blocks, state) do
state
|> Enum.filter(fn {_, {_, s}} -> s == :pending end)
|> Enum.map(fn {root, {block, _}} -> {root, block} end)
|> Enum.sort_by(fn {_, signed_block} -> signed_block.message.slot end)
|> Enum.reduce(state, fn {block_root, signed_block}, state ->
parent_root = signed_block.message.parent_root
parent_status = get_block_status(state, parent_root)

cond do
# If parent is invalid, block is invalid
parent_status == :invalid ->
state |> Map.put(block_root, {nil, :invalid})

# If parent isn't processed, block is pending
parent_status in [:processing, :pending, :download, :download_blobs] ->
state

# If parent is not in fork choice, download parent
not Blocks.has_block?(parent_root) ->
state |> Map.put(parent_root, {nil, :download})

# If all the other conditions are false, add block to fork choice
true ->
ForkChoice.on_block(signed_block, block_root)
state |> Map.put(block_root, {signed_block, :processing})
end
end)
|> then(fn state ->
schedule_blocks_processing()
{:noreply, state}
end)
schedule_blocks_processing()
{:noreply, process_blocks(state)}
end

@impl true
Expand Down Expand Up @@ -191,6 +161,36 @@ defmodule LambdaEthereumConsensus.Beacon.PendingBlocks do
### Private Functions
##########################

defp process_blocks(state) do
state
|> Enum.filter(fn {_, {_, s}} -> s == :pending end)
|> Enum.map(fn {root, {block, _}} -> {root, block} end)
|> Enum.sort_by(fn {_, signed_block} -> signed_block.message.slot end)
|> Enum.reduce(state, fn {block_root, signed_block}, state ->
parent_root = signed_block.message.parent_root
parent_status = get_block_status(state, parent_root)

cond do
# If parent is invalid, block is invalid
parent_status == :invalid ->
state |> Map.put(block_root, {nil, :invalid})

# If parent isn't processed, block is pending
parent_status in [:processing, :pending, :download, :download_blobs] ->
state

# If parent is not in fork choice, download parent
not Blocks.has_block?(parent_root) ->
state |> Map.put(parent_root, {nil, :download})

# If all the other conditions are false, add block to fork choice
true ->
ForkChoice.on_block(signed_block, block_root)
state |> Map.put(block_root, {signed_block, :processing})
end
end)
end

@spec get_block_status(state(), Types.root()) :: block_status()
defp get_block_status(state, block_root) do
state |> Map.get(block_root, {nil, :unknown}) |> elem(1)
Expand All @@ -216,7 +216,7 @@ defmodule LambdaEthereumConsensus.Beacon.PendingBlocks do
end

def schedule_blocks_processing do
Process.send_after(__MODULE__, :process_blocks, 3000)
Process.send_after(__MODULE__, :process_blocks, 500)
end

def schedule_blobs_download do
Expand Down
99 changes: 79 additions & 20 deletions lib/ssz_ex/decode.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@ defmodule SszEx.Decode do

alias LambdaEthereumConsensus.Utils.BitList
alias LambdaEthereumConsensus.Utils.BitVector
alias SszEx.Error
alias SszEx.Utils

@bytes_per_length_offset 4
@offset_bits 32

@spec decode(binary(), SszEx.schema()) ::
{:ok, any()} | {:error, String.t()}
{:ok, any()} | {:error, Error.t()}
def decode(binary, :bool), do: decode_bool(binary)
def decode(binary, {:int, size}), do: decode_uint(binary, size)
def decode(value, {:byte_list, _}), do: {:ok, value}
Expand Down Expand Up @@ -52,7 +53,10 @@ defmodule SszEx.Decode do
defp decode_uint(binary, size) when bit_size(binary) != size,
do:
{:error,
"Invalid binary length while decoding uint.\nExpected size: #{size}.\nFound:#{bit_size(binary)}\n"}
%Error{
message:
"Invalid binary length while decoding uint.\nExpected size: #{size}.\nFound:#{bit_size(binary)}\n"
}}

defp decode_uint(binary, size) do
<<element::integer-size(size)-little, _rest::bitstring>> = binary
Expand All @@ -62,18 +66,28 @@ defmodule SszEx.Decode do
defp decode_bool(binary) when byte_size(binary) != 1,
do:
{:error,
"Invalid binary length while decoding bool.\nExpected size: 1.\nFound:#{byte_size(binary)}\n"}
%Error{
message:
"Invalid binary length while decoding bool.\nExpected size: 1.\nFound:#{byte_size(binary)}\n"
}}

defp decode_bool("\x01"), do: {:ok, true}
defp decode_bool("\x00"), do: {:ok, false}

defp decode_bool(binary),
do:
{:error,
"Invalid binary value while decoding bool.\nExpected value: x01/x00.\nFound: x#{Base.encode16(binary)}."}
%Error{
message:
"Invalid binary value while decoding bool.\nExpected value: x01/x00.\nFound: x#{Base.encode16(binary)}."
}}

defp decode_bitlist("", _max_size),
do: {:error, "Invalid binary value while decoding BitList.\nEmpty binary found.\n"}
do:
{:error,
%Error{
message: "Invalid binary value while decoding BitList.\nEmpty binary found.\n"
}}

defp decode_bitlist(bit_list, max_size) do
num_bytes = byte_size(bit_list)
Expand All @@ -82,11 +96,17 @@ defmodule SszEx.Decode do

cond do
match?(<<_::binary-size(num_bytes - 1), 0>>, bit_list) ->
{:error, "Invalid binary value while decoding BitList.\nMissing sentinel bit.\n"}
{:error,
%Error{
message: "Invalid binary value while decoding BitList.\nMissing sentinel bit.\n"
}}

len > max_size ->
{:error,
"Invalid binary length while decoding BitList. \nExpected max_size: #{max_size}. Found: #{len}.\n"}
%Error{
message:
"Invalid binary length while decoding BitList. \nExpected max_size: #{max_size}. Found: #{len}.\n"
}}

true ->
{:ok, decoded}
Expand All @@ -103,7 +123,10 @@ defmodule SszEx.Decode do
{:ok, BitVector.new(bit_vector, size)}

_ ->
{:error, "Invalid binary length while decoding BitVector. \nExpected size: #{size}.\n"}
{:error,
%Error{
message: "Invalid binary length while decoding BitVector. \nExpected size: #{size}.\n"
}}
end
end

Expand Down Expand Up @@ -137,7 +160,10 @@ defmodule SszEx.Decode do
when byte_length > inner_type_size * max_size,
do:
{:error,
"Invalid binary length while decoding list of #{inspect(inner_type)}.\nExpected max_size: #{max_size}.\nFound: #{byte_length}\n"}
%Error{
message:
"Invalid binary length while decoding list of #{inspect(inner_type)}.\nExpected max_size: #{max_size}.\nFound: #{byte_length}\n"
}}

defp check_valid_fixed_list_size(_byte_length, _inner_type, _inner_type_size, _max_size),
do: :ok
Expand All @@ -146,7 +172,10 @@ defmodule SszEx.Decode do
when byte_length != inner_type_size * size,
do:
{:error,
"Invalid binary length while decoding vector of #{inspect(inner_type)}.\nExpected size #{inner_type_size * size} bytes.\nFound: #{byte_length}.\n"}
%Error{
message:
"Invalid binary length while decoding vector of #{inspect(inner_type)}.\nExpected size #{inner_type_size * size} bytes.\nFound: #{byte_length}.\n"
}}

defp check_valid_vector_size(_byte_length, _inner_type, _inner_type_size, _size),
do: :ok
Expand All @@ -158,7 +187,10 @@ defmodule SszEx.Decode do
defp check_valid_vector_size_after_decode(size, decoded_size),
do:
{:error,
"Invalid vector decoded size.\nExpected size: #{size}. Decoded vector size: #{decoded_size} "}
%Error{
message:
"Invalid vector decoded size.\nExpected size: #{size}. Decoded vector size: #{decoded_size} "
}}

defp decode_variable_list("", _, _) do
{:ok, []}
Expand All @@ -172,7 +204,10 @@ defmodule SszEx.Decode do
when div(first_offset, @bytes_per_length_offset) > size,
do:
{:error,
"Invalid binary while decoding list of #{inspect(inner_type)}.\nExpected max_size: #{size}.\n First offset points to: #{first_offset}."}
%Error{
message:
"Invalid binary while decoding list of #{inspect(inner_type)}.\nExpected max_size: #{size}.\n First offset points to: #{first_offset}."
}}

defp decode_variable_list(binary, inner_type, _size) do
<<first_offset::integer-32-little, rest_bytes::bitstring>> = binary
Expand All @@ -181,7 +216,10 @@ defmodule SszEx.Decode do
if Integer.mod(first_offset, @bytes_per_length_offset) != 0 ||
first_offset < @bytes_per_length_offset do
{:error,
"Invalid binary while decoding list of #{inspect(inner_type)}.\nFirst offset points to: #{first_offset}."}
%Error{
message:
"Invalid binary while decoding list of #{inspect(inner_type)}.\nFirst offset points to: #{first_offset}."
}}
else
with :ok <-
sanitize_offset(first_offset, nil, byte_size(binary), first_offset) do
Expand Down Expand Up @@ -270,7 +308,10 @@ defmodule SszEx.Decode do
when expected_length != size,
do:
{:error,
"Invalid binary length while decoding #{module}. \nExpected #{expected_length}. \nFound #{size}.\n"}
%Error{
message:
"Invalid binary length while decoding #{module}. \nExpected #{expected_length}. \nFound #{size}.\n"
}}

defp check_fixed_container_size(_module, _expected_length, _size),
do: :ok
Expand All @@ -279,7 +320,10 @@ defmodule SszEx.Decode do
when offset != items_index,
do:
{:error,
"First offset does not point to the first variable byte.\nExpected index: #{items_index}.\nOffset: #{offset}. "}
%Error{
message:
"First offset does not point to the first variable byte.\nExpected index: #{items_index}.\nOffset: #{offset}. "
}}

defp check_first_offset(_offsets, _items_index, _binary_size),
do: :ok
Expand Down Expand Up @@ -345,11 +389,17 @@ defmodule SszEx.Decode do
cond do
offset > num_bytes ->
{:error,
"Offset points outside the binary. \nBinary length: #{num_bytes}.\nOffset: #{offset}"}
%Error{
message:
"Offset points outside the binary. \nBinary length: #{num_bytes}.\nOffset: #{offset}"
}}

previous_offset != nil && previous_offset > offset ->
{:error,
"Offset points to bytes prior to the previous offset.\nPrevious offset: #{previous_offset}.\nOffset: #{offset}"}
%Error{
message:
"Offset points to bytes prior to the previous offset.\nPrevious offset: #{previous_offset}.\nOffset: #{offset}"
}}

true ->
:ok
Expand All @@ -360,11 +410,17 @@ defmodule SszEx.Decode do
cond do
offset < num_fixed_bytes ->
{:error,
"Offset points “backwards” into the fixed-bytes portion. \nFirst variable byte index: #{num_fixed_bytes}.\nOffset: #{offset}."}
%Error{
message:
"Offset points “backwards” into the fixed-bytes portion. \nFirst variable byte index: #{num_fixed_bytes}.\nOffset: #{offset}."
}}

previous_offset == nil && offset != num_fixed_bytes ->
{:error,
"Offset does not point to the first variable byte.\nExpected index: #{num_fixed_bytes}.\nOffset: #{offset}."}
%Error{
message:
"Offset does not point to the first variable byte.\nExpected index: #{num_fixed_bytes}.\nOffset: #{offset}."
}}

true ->
:ok
Expand All @@ -383,7 +439,10 @@ defmodule SszEx.Decode do
when byte_size(binary) < chunk_size,
do: [
{:error,
"Invalid binary length while decoding collection. \nInner type size: #{chunk_size} bytes. Binary length: #{byte_size(binary)} bytes.\n"}
%Error{
message:
"Invalid binary length while decoding collection. \nInner type size: #{chunk_size} bytes. Binary length: #{byte_size(binary)} bytes.\n"
}}
| results
]

Expand Down
Loading

0 comments on commit ab5b574

Please sign in to comment.