Skip to content

Commit f3d6067

Browse files
authored
fix: return to_string-capable ReqResp error (#846)
1 parent b02154b commit f3d6067

File tree

2 files changed

+41
-13
lines changed

2 files changed

+41
-13
lines changed

lib/lambda_ethereum_consensus/p2p/req_resp.ex

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,35 @@ defmodule LambdaEthereumConsensus.P2P.ReqResp do
77
alias LambdaEthereumConsensus.P2P
88
alias LambdaEthereumConsensus.SszEx
99

10+
defmodule Error do
11+
@moduledoc """
12+
Error messages for Req/Resp domain.
13+
"""
14+
defstruct [:code, :message]
15+
@type t :: %__MODULE__{code: 1..255, message: binary()}
16+
17+
defp parse_code(1), do: "InvalidRequest"
18+
defp parse_code(2), do: "ServerError"
19+
defp parse_code(3), do: "ResourceUnavailable"
20+
defp parse_code(n), do: "#{n}"
21+
22+
def format(%Error{code: code, message: message}) do
23+
"#{parse_code(code)}: #{message}"
24+
end
25+
26+
defimpl String.Chars, for: __MODULE__ do
27+
def to_string(error), do: Error.format(error)
28+
end
29+
end
30+
1031
## Encoding
1132

1233
@type context_bytes :: binary()
1334
@type encodable :: {any(), SszEx.schema()} | struct()
14-
@type error_code :: 1..255
15-
@type error_message :: binary()
1635

1736
@type response_payload ::
1837
{:ok, {encodable(), context_bytes()}}
19-
| {:error, {error_code(), error_message()}}
38+
| {:error, Error.t()}
2039

2140
@spec encode_response([response_payload()]) :: binary()
2241
def encode_response(responses) do
@@ -35,7 +54,10 @@ defmodule LambdaEthereumConsensus.P2P.ReqResp do
3554
def encode_ok({response, ssz_schema}, context_bytes),
3655
do: encode(<<0>>, context_bytes, {response, ssz_schema})
3756

38-
@spec encode_error(error_code(), error_message()) :: binary()
57+
@spec encode_error(Error.t()) :: binary()
58+
def encode_error(%Error{code: code, message: message}), do: encode_error(code, message)
59+
60+
@spec encode_error(1..255, binary()) :: binary()
3961
def encode_error(status_code, error_message),
4062
do: encode(<<status_code>>, <<>>, {error_message, TypeAliases.error_message()})
4163

@@ -52,7 +74,8 @@ defmodule LambdaEthereumConsensus.P2P.ReqResp do
5274

5375
## Decoding
5476

55-
@spec decode_response(binary(), SszEx.schema()) :: {:ok, [any()]} | {:error, String.t()}
77+
@spec decode_response(binary(), SszEx.schema()) ::
78+
{:ok, [any()]} | {:error, String.t()} | {:error, Error.t()}
5679
def decode_response(response_chunk, ssz_schema) do
5780
with {:ok, chunks} <- split_response(response_chunk) do
5881
# TODO: handle errors
@@ -69,7 +92,7 @@ defmodule LambdaEthereumConsensus.P2P.ReqResp do
6992
end
7093
end
7194

72-
@spec split_response(binary) :: {:ok, [binary()]} | {:error, String.t()}
95+
@spec split_response(binary) :: {:ok, [binary()]} | {:error, String.t()} | {:error, Error.t()}
7396
def split_response(response_chunk) do
7497
# TODO: the fork_context should be computed depending on the block's slot
7598
fork_context = BeaconChain.get_fork_digest()
@@ -86,8 +109,8 @@ defmodule LambdaEthereumConsensus.P2P.ReqResp do
86109
<<0, wrong_context::binary-size(4)>> <> _ ->
87110
{:error, "wrong context: #{Base.encode16(wrong_context)}"}
88111

89-
<<error_code>> <> error_message ->
90-
{:error, {error_code, decode_error_message(error_message)}}
112+
<<error_code>> <> message ->
113+
decode_error(error_code, message)
91114
end
92115
end
93116

@@ -114,10 +137,15 @@ defmodule LambdaEthereumConsensus.P2P.ReqResp do
114137
@spec decode_response_chunk(binary(), SszEx.schema()) ::
115138
{:ok, any()}
116139
| {:error, String.t()}
117-
| {:error, {error_code(), {:ok, error_message()}}}
118-
| {:error, {error_code(), {:error, String.t()}}}
140+
| {:error, Error.t()}
119141
def decode_response_chunk(<<0>> <> chunk, ssz_schema), do: decode_request(chunk, ssz_schema)
120142

121-
def decode_response_chunk(<<code>> <> message, _),
122-
do: {:error, {code, decode_error_message(message)}}
143+
def decode_response_chunk(<<code>> <> message, _), do: decode_error(code, message)
144+
145+
@spec decode_error(1..255, binary()) :: {:error, String.t()} | {:error, Error.t()}
146+
defp decode_error(code, encoded_message) do
147+
with {:ok, error_message} <- decode_error_message(encoded_message) do
148+
{:error, %Error{code: code, message: error_message}}
149+
end
150+
end
123151
end

test/unit/req_resp_test.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ defmodule Unit.ReqRespTest do
4747
"011CFF060000734E6150705900220000EF99F84B1C6C4661696C656420746F20756E636F6D7072657373206D657373616765"
4848
|> Base.decode16!()
4949

50-
expected_result = {:error, {1, {:ok, "Failed to uncompress message"}}}
50+
expected_result = {:error, %ReqResp.Error{code: 1, message: "Failed to uncompress message"}}
5151

5252
assert ReqResp.decode_response_chunk(msg, TypeAliases.uint64()) == expected_result
5353
end

0 commit comments

Comments
 (0)