diff --git a/.dialyzer.ignore-warnings b/.dialyzer.ignore-warnings index 0eefb9f..bdf3301 100644 --- a/.dialyzer.ignore-warnings +++ b/.dialyzer.ignore-warnings @@ -1,19 +1,10 @@ # protocol warnings -:0: Unknown function 'Elixir.ExRLP.Decoder.Atom':'__impl__'/1 -:0: Unknown function 'Elixir.ExRLP.Decoder.Float':'__impl__'/1 -:0: Unknown function 'Elixir.ExRLP.Decoder.Function':'__impl__'/1 -:0: Unknown function 'Elixir.ExRLP.Decoder.Integer':'__impl__'/1 -:0: Unknown function 'Elixir.ExRLP.Decoder.List':'__impl__'/1 -:0: Unknown function 'Elixir.ExRLP.Decoder.Map':'__impl__'/1 -:0: Unknown function 'Elixir.ExRLP.Decoder.PID':'__impl__'/1 -:0: Unknown function 'Elixir.ExRLP.Decoder.Port':'__impl__'/1 -:0: Unknown function 'Elixir.ExRLP.Decoder.Reference':'__impl__'/1 -:0: Unknown function 'Elixir.ExRLP.Decoder.Tuple':'__impl__'/1 -:0: Unknown function 'Elixir.ExRLP.Encoder.Atom':'__impl__'/1 -:0: Unknown function 'Elixir.ExRLP.Encoder.Float':'__impl__'/1 -:0: Unknown function 'Elixir.ExRLP.Encoder.Function':'__impl__'/1 -:0: Unknown function 'Elixir.ExRLP.Encoder.PID':'__impl__'/1 -:0: Unknown function 'Elixir.ExRLP.Encoder.Port':'__impl__'/1 -:0: Unknown function 'Elixir.ExRLP.Encoder.Reference':'__impl__'/1 -:0: Unknown function 'Elixir.ExRLP.Encoder.Tuple':'__impl__'/1 +:0: Unknown function 'Elixir.ExRLP.Encode.Atom':'__impl__'/1 +:0: Unknown function 'Elixir.ExRLP.Encode.Float':'__impl__'/1 +:0: Unknown function 'Elixir.ExRLP.Encode.Function':'__impl__'/1 +:0: Unknown function 'Elixir.ExRLP.Encode.Map':'__impl__'/1 +:0: Unknown function 'Elixir.ExRLP.Encode.PID':'__impl__'/1 +:0: Unknown function 'Elixir.ExRLP.Encode.Port':'__impl__'/1 +:0: Unknown function 'Elixir.ExRLP.Encode.Reference':'__impl__'/1 +:0: Unknown function 'Elixir.ExRLP.Encode.Tuple':'__impl__'/1 diff --git a/CHANGELOG.md b/CHANGELOG.md index 5de7e0c..050a8c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ +# 0.3.0 +* Remove protocols for Map because it overrides custom struct protocols. # 0.2.1 * Improve typespecs to allow for integers as a valid value to encode in RLP. # 0.2.0 diff --git a/README.md b/README.md index 7a9168b..8df948e 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Add `:ex_rlp` as a dependency to your project's `mix.exs`: ```elixir defp deps do [ - {:ex_rlp, "~> 0.2.1"} + {:ex_rlp, "~> 0.3.0"} ] end ``` @@ -53,13 +53,13 @@ Use ExRLP.decode/1 method to decode a rlp encoded data. All items except lists a ## Examples - iex(1)> "83646f67" |> ExRLP.decode(:binary, encoding: :hex) + iex(1)> "83646f67" |> ExRLP.decode(encoding: :hex) "dog" - iex(2)> "8203e8" |> ExRLP.decode(:binary, encoding: :hex) |> :binary.decode_unsigned + iex(2)> "8203e8" |> ExRLP.decode(encoding: :hex) |> :binary.decode_unsigned 1000 - iex(3)> "c4c2c0c0c0" |> ExRLP.decode(:binary, encoding: :hex) + iex(3)> "c4c2c0c0c0" |> ExRLP.decode(encoding: :hex) [[[], []], []] ``` @@ -69,49 +69,41 @@ More examples can be found in test files. You can define protocols for encoding/decoding custom data types. -Custom protocols for Map have already been implemented in ExRLP: - ```elixir +defmodule ExRLP.LogEntry do + defstruct address: nil, topics: [], data: nil + + @type t :: %__MODULE__{ + address: EVM.address(), + topics: [integer()], + data: binary() + } + + @spec new(binary, [integer()], binary()) :: t() + def new(address, topics, data) do + %__MODULE__{ + address: address, + topics: topics, + data: data + } + end -defimpl ExRLP.Encoder, for: Map do - alias ExRLP.Encode - - def encode(map, _) do - map - |> Map.values - |> Encode.encode + def to_list(log) do + [log.address, log.topics, log.data] end end -defimpl ExRLP.Decoder, for: BitString do - alias ExRLP.Decode - - def decode(value, :map, options) do - keys = - options - |> Keyword.fetch!(:keys) - |> Enum.sort +defimpl ExRLP.Encode, for: ExRLP.LogEntry do + alias ExRLP.{Encode, LogEntry} - value - |> Decode.decode - |> Enum.with_index - |> Enum.reduce(%{}, fn({value, index}, acc) -> - key = keys |> Enum.at(index) - - acc |> Map.put(key, value) - end) - - ... + @spec encode(LogEntry.t(), keyword()) :: binary() + def encode(log, options \\ []) do + log + |> LogEntry.to_list() + |> Encode.encode(options) end end -``` -So now it's possible to encode/decode maps: -```elixir -iex(1)> %{name: "Vitalik", surname: "Buterin"} |> ExRLP.encode(encoding: :hex) -"d087566974616c696b874275746572696e" -iex(2)> "d087566974616c696b874275746572696e" |> ExRLP.decode(:map, keys: [:surname, :name], encoding: :hex) -%{name: "Vitalik", surname: "Buterin"} ``` ## Contributing diff --git a/lib/ex_rlp.ex b/lib/ex_rlp.ex index aaecd4f..5e78a97 100644 --- a/lib/ex_rlp.ex +++ b/lib/ex_rlp.ex @@ -1,9 +1,9 @@ defmodule ExRLP do - alias ExRLP.{Encoder, Decoder} + alias ExRLP.{Encode, Decode} @moduledoc File.read!("#{__DIR__}/../README.md") - @type t :: nil | binary() | integer() | [t] + @type t :: any() @doc """ Given an RLP structure, returns the encoding as a string. @@ -51,8 +51,8 @@ defmodule ExRLP do """ @spec encode(t) :: binary() @spec encode(t, keyword()) :: binary() - def encode(item, options \\ []) do - item |> Encoder.encode(options) + def encode(item, options \\ [encoding: :binary]) do + item |> Encode.encode(options) end @doc """ @@ -66,7 +66,7 @@ defmodule ExRLP do iex> ExRLP.decode(<<0x83, ?d, ?o, ?g>>) "dog" - iex> ExRLP.decode("83646f67", :binary, encoding: :hex) + iex> ExRLP.decode("83646f67", encoding: :hex) "dog" iex> ExRLP.decode(<<184, 60, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65>>) @@ -100,9 +100,8 @@ defmodule ExRLP do 15_000_000_000_000_000_000_000_000_000_000_000 """ @spec decode(binary()) :: t - @spec decode(binary(), atom()) :: t - @spec decode(binary(), atom(), keyword()) :: t - def decode(item, type \\ :binary, options \\ []) do - item |> Decoder.decode(type, options) + @spec decode(binary(), keyword()) :: t + def decode(item, options \\ [encoding: :binary]) do + item |> Decode.decode(options) end end diff --git a/lib/ex_rlp/decoder.ex b/lib/ex_rlp/decode.ex similarity index 78% rename from lib/ex_rlp/decoder.ex rename to lib/ex_rlp/decode.ex index 069de70..dc225b0 100644 --- a/lib/ex_rlp/decoder.ex +++ b/lib/ex_rlp/decode.ex @@ -1,10 +1,10 @@ defmodule ExRLP.Decode do @moduledoc false - @spec decode(binary(), :binary | :hex) :: ExRLP.t() - def decode(item, encoding) when is_binary(item) do + @spec decode(binary(), keyword()) :: ExRLP.t() + def decode(item, options \\ []) when is_binary(item) do item - |> maybe_decode_hex(encoding) + |> maybe_decode_hex(Keyword.get(options, :encoding, :binary)) |> decode_item end @@ -113,34 +113,3 @@ defmodule ExRLP.Decode do decoded_binary end end - -defprotocol ExRLP.Decoder do - def decode(value, type \\ :binary, options \\ nil) -end - -defimpl ExRLP.Decoder, for: BitString do - alias ExRLP.Decode - - @spec decode(binary(), atom(), keyword()) :: ExRLP.t() - def decode(value, type \\ :binary, options \\ []) - - def decode(value, :map, options) do - keys = - options - |> Keyword.get(:keys, []) - |> Enum.sort() - - value - |> Decode.decode(Keyword.get(options, :encoding, :binary)) - |> Enum.with_index() - |> Enum.reduce(%{}, fn {value, index}, acc -> - key = keys |> Enum.at(index) - - acc |> Map.put(key, value) - end) - end - - def decode(value, :binary, options) do - value |> Decode.decode(Keyword.get(options, :encoding, :binary)) - end -end diff --git a/lib/ex_rlp/encode.ex b/lib/ex_rlp/encode.ex new file mode 100644 index 0000000..e320a30 --- /dev/null +++ b/lib/ex_rlp/encode.ex @@ -0,0 +1,89 @@ +defprotocol ExRLP.Encode do + def encode(value, options \\ []) +end + +defimpl ExRLP.Encode, for: BitString do + alias ExRLP.Utils + + @spec encode(ExRLP.t(), keyword()) :: binary() + def encode(value, options \\ []) do + value + |> encode_item + |> Utils.maybe_encode_hex(Keyword.get(options, :encoding, :binary)) + end + + @spec encode_item(binary()) :: binary() + defp encode_item(<> = item) when byte_size(item) == 1 and byte < 128 do + item + end + + defp encode_item(item) when is_binary(item) and byte_size(item) < 56 do + prefix = 128 + byte_size(item) + + <> <> item + end + + defp encode_item(item) when is_binary(item) do + be_size = item |> Utils.big_endian_size() + byte_size = be_size |> byte_size + + <<183 + byte_size>> <> be_size <> item + end +end + +defimpl ExRLP.Encode, for: Integer do + alias ExRLP.{Utils, Encode} + + @spec encode(ExRLP.t(), keyword()) :: binary() + def encode(value, options \\ []) when value >= 0 do + value + |> to_binary() + |> Encode.encode() + |> Utils.maybe_encode_hex(Keyword.get(options, :encoding, :binary)) + end + + @spec to_binary(integer()) :: binary() + defp to_binary(object) when is_integer(object) and object == 0 do + "" + end + + defp to_binary(object) when is_integer(object) and object > 0 do + object |> :binary.encode_unsigned() + end +end + +defimpl ExRLP.Encode, for: List do + alias ExRLP.{Utils, Encode} + + @spec encode([ExRLP.t()], keyword()) :: binary() + def encode(values, options \\ []) do + values + |> encode_items("") + |> Utils.maybe_encode_hex(Keyword.get(options, :encoding, :binary)) + end + + @spec encode_items([ExRLP.t()], binary()) :: binary() + defp encode_items([], acc) do + acc |> prefix_list + end + + defp encode_items([item | tail], acc) do + encoded_item = item |> Encode.encode() + + tail |> encode_items(acc <> encoded_item) + end + + @spec prefix_list(binary()) :: binary() + defp prefix_list(encoded_concat) when byte_size(encoded_concat) < 56 do + size = encoded_concat |> byte_size + + <<192 + size>> <> encoded_concat + end + + defp prefix_list(encoded_concat) do + be_size = encoded_concat |> Utils.big_endian_size() + byte_size = be_size |> byte_size + + <<247 + byte_size>> <> be_size <> encoded_concat + end +end diff --git a/lib/ex_rlp/encoder.ex b/lib/ex_rlp/encoder.ex deleted file mode 100644 index a61da3c..0000000 --- a/lib/ex_rlp/encoder.ex +++ /dev/null @@ -1,129 +0,0 @@ -defmodule ExRLP.Encode do - @moduledoc false - - @spec encode(ExRLP.t(), :binary | :hex) :: binary() - def encode(item, encoding) do - item - |> encode_item - |> maybe_encode_hex(encoding) - end - - @spec maybe_encode_hex(binary(), atom()) :: binary() - def maybe_encode_hex(value, :binary), do: value - def maybe_encode_hex(value, :hex), do: encode_hex(value) - - @spec encode_item(binary()) :: binary() - defp encode_item(<> = item) when byte_size(item) == 1 and byte < 128 do - item - end - - defp encode_item(item) when is_binary(item) and byte_size(item) < 56 do - prefix = 128 + byte_size(item) - - <> <> item - end - - defp encode_item(item) when is_binary(item) do - be_size = item |> big_endian_size - byte_size = be_size |> byte_size - - <<183 + byte_size>> <> be_size <> item - end - - defp encode_item(items) when is_list(items) do - encoded_concat = - items - |> Enum.reduce("", fn item, acc -> - encoded_item = item |> encode_item - - acc <> encoded_item - end) - - encoded_concat |> prefix_list - end - - defp encode_item(item) do - item - |> encode_binary - |> encode_item - end - - @spec prefix_list(binary()) :: binary() - defp prefix_list(encoded_concat) when byte_size(encoded_concat) < 56 do - size = encoded_concat |> byte_size - - <<192 + size>> <> encoded_concat - end - - defp prefix_list(encoded_concat) do - be_size = encoded_concat |> big_endian_size - byte_size = be_size |> byte_size - - <<247 + byte_size>> <> be_size <> encoded_concat - end - - @spec big_endian_size(binary()) :: bitstring() - defp big_endian_size(binary) do - binary - |> byte_size - |> :binary.encode_unsigned() - end - - @spec encode_hex(binary()) :: binary() - defp encode_hex(binary) do - binary |> Base.encode16(case: :lower) - end - - @spec encode_binary(integer()) :: binary() - defp encode_binary(object) when is_integer(object) and object == 0 do - "" - end - - defp encode_binary(object) when is_integer(object) and object > 0 do - object |> :binary.encode_unsigned() - end -end - -defprotocol ExRLP.Encoder do - def encode(value, options \\ nil) -end - -defimpl ExRLP.Encoder, for: BitString do - alias ExRLP.Encode - - @spec encode(ExRLP.t(), keyword()) :: binary() - def encode(value, options) do - value |> Encode.encode(Keyword.get(options, :encoding, :binary)) - end -end - -defimpl ExRLP.Encoder, for: Integer do - alias ExRLP.Encode - - @spec encode(ExRLP.t(), keyword()) :: binary() - def encode(value, options) when value >= 0 do - value |> Encode.encode(Keyword.get(options, :encoding, :binary)) - end -end - -defimpl ExRLP.Encoder, for: List do - alias ExRLP.Encode - - @spec encode(ExRLP.t(), keyword()) :: binary() - def encode(value, options) do - value |> Encode.encode(Keyword.get(options, :encoding, :binary)) - end -end - -defimpl ExRLP.Encoder, for: Map do - alias ExRLP.Encode - - @dialyzer {:nowarn_function, encode: 2} - - @spec encode(%{key: ExRLP.t()}, keyword()) :: binary() - def encode(map, options) do - map - |> Map.values() - |> Encode.encode(Keyword.get(options, :encoding, :binary)) - end -end diff --git a/lib/ex_rlp/utils.ex b/lib/ex_rlp/utils.ex new file mode 100644 index 0000000..3335d2e --- /dev/null +++ b/lib/ex_rlp/utils.ex @@ -0,0 +1,19 @@ +defmodule ExRLP.Utils do + @moduledoc false + + @spec maybe_encode_hex(binary(), atom()) :: binary() + def maybe_encode_hex(value, :hex), do: encode_hex(value) + def maybe_encode_hex(value, _encoding), do: value + + @spec encode_hex(binary()) :: binary() + def encode_hex(binary) do + binary |> Base.encode16(case: :lower) + end + + @spec big_endian_size(binary()) :: bitstring() + def big_endian_size(binary) do + binary + |> byte_size + |> :binary.encode_unsigned() + end +end diff --git a/mix.exs b/mix.exs index 4e20662..1637fbc 100644 --- a/mix.exs +++ b/mix.exs @@ -4,7 +4,7 @@ defmodule ExRLP.Mixfile do def project do [ app: :ex_rlp, - version: "0.2.1", + version: "0.3.0", elixir: "~> 1.6", description: "Ethereum's Recursive Length Prefix (RLP) encoding", package: [ @@ -15,7 +15,8 @@ defmodule ExRLP.Mixfile do build_embedded: Mix.env() == :prod, start_permanent: Mix.env() == :prod, deps: deps(), - dialyzer: [ignore_warnings: ".dialyzer.ignore-warnings"] + dialyzer: [ignore_warnings: ".dialyzer.ignore-warnings"], + elixirc_paths: elixirc_paths(Mix.env()) ] end @@ -30,4 +31,7 @@ defmodule ExRLP.Mixfile do {:dialyxir, "~> 0.5", only: [:dev], runtime: false} ] end + + defp elixirc_paths(:test), do: ["lib", "test/support"] + defp elixirc_paths(_), do: ["lib"] end diff --git a/test/ex_rlp/decoder_test.exs b/test/ex_rlp/decode_test.exs similarity index 86% rename from test/ex_rlp/decoder_test.exs rename to test/ex_rlp/decode_test.exs index ba6c897..41ded2c 100644 --- a/test/ex_rlp/decoder_test.exs +++ b/test/ex_rlp/decode_test.exs @@ -1,12 +1,12 @@ -defmodule ExRLP.DecoderTest do +defmodule ExRLP.DecodeTest do use ExUnit.Case - alias ExRLP.Decoder + alias ExRLP.Decode test "decodes empty string" do rlp_binary = "80" expected_result = "" - result = rlp_binary |> Decoder.decode(:binary, encoding: :hex) + result = rlp_binary |> Decode.decode(encoding: :hex) assert result == expected_result end @@ -15,7 +15,7 @@ defmodule ExRLP.DecoderTest do rlp_binary = "00" expected_result = "\u0000" - result = rlp_binary |> Decoder.decode(:binary, encoding: :hex) + result = rlp_binary |> Decode.decode(encoding: :hex) assert result == expected_result end @@ -24,7 +24,7 @@ defmodule ExRLP.DecoderTest do rlp_binary = "01" expected_result = "\u0001" - result = rlp_binary |> Decoder.decode(:binary, encoding: :hex) + result = rlp_binary |> Decode.decode(encoding: :hex) assert result == expected_result end @@ -33,7 +33,7 @@ defmodule ExRLP.DecoderTest do rlp_binary = "7f" expected_result = "\u007F" - result = rlp_binary |> Decoder.decode(:binary, encoding: :hex) + result = rlp_binary |> Decode.decode(encoding: :hex) assert result == expected_result end @@ -42,7 +42,7 @@ defmodule ExRLP.DecoderTest do rlp_binary = "83646f67" expected_result = "dog" - result = rlp_binary |> Decoder.decode(:binary, encoding: :hex) + result = rlp_binary |> Decode.decode(encoding: :hex) assert result == expected_result end @@ -54,7 +54,7 @@ defmodule ExRLP.DecoderTest do expected_result = "Lorem ipsum dolor sit amet, consectetur adipisicing eli" - result = rlp_binary |> Decoder.decode(:binary, encoding: :hex) + result = rlp_binary |> Decode.decode(encoding: :hex) assert result == expected_result end @@ -66,7 +66,7 @@ defmodule ExRLP.DecoderTest do expected_result = "Lorem ipsum dolor sit amet, consectetur adipisicing elit" - result = rlp_binary |> Decoder.decode(:binary, encoding: :hex) + result = rlp_binary |> Decode.decode(encoding: :hex) assert result == expected_result end @@ -115,7 +115,7 @@ defmodule ExRLP.DecoderTest do "lorem libero aliquet arcu, non interdum tellus lectus sit amet eros. Cras rhoncus, " <> "metus ac ornare cursus, dolor justo ultrices metus, at ullamcorper volutpat" - result = rlp_binary |> Decoder.decode(:binary, encoding: :hex) + result = rlp_binary |> Decode.decode(encoding: :hex) assert result == expected_result end @@ -124,7 +124,7 @@ defmodule ExRLP.DecoderTest do rlp_binary = "cc83646f6783676f6483636174" expected_result = ["dog", "god", "cat"] - result = rlp_binary |> Decoder.decode(:binary, encoding: :hex) + result = rlp_binary |> Decode.decode(encoding: :hex) assert result == expected_result end @@ -148,7 +148,7 @@ defmodule ExRLP.DecoderTest do "qwer" ] - result = rlp_binary |> Decoder.decode(:binary, encoding: :hex) + result = rlp_binary |> Decode.decode(encoding: :hex) assert result == expected_result end @@ -210,7 +210,7 @@ defmodule ExRLP.DecoderTest do ["asdf", "qwer", "zxcv"] ] - result = rlp_binary |> Decoder.decode(:binary, encoding: :hex) + result = rlp_binary |> Decode.decode(encoding: :hex) assert result == expected_result end @@ -219,7 +219,7 @@ defmodule ExRLP.DecoderTest do rlp_binary = "c4c2c0c0c0" expected_result = [[[], []], []] - result = rlp_binary |> Decoder.decode(:binary, encoding: :hex) + result = rlp_binary |> Decode.decode(encoding: :hex) assert result == expected_result end @@ -228,7 +228,7 @@ defmodule ExRLP.DecoderTest do rlp_binary = "c7c0c1c0c3c0c1c0" expected_result = [[], [[]], [[], [[]]]] - result = rlp_binary |> Decoder.decode(:binary, encoding: :hex) + result = rlp_binary |> Decode.decode(encoding: :hex) assert result == expected_result end @@ -245,16 +245,7 @@ defmodule ExRLP.DecoderTest do ["key4", "val4"] ] - result = rlp_binary |> Decoder.decode(:binary, encoding: :hex) - - assert result == expected_result - end - - test "decoders Map" do - rlp_binary = "da8b526f636b276e27526f6c6c85417972617487426164796b6f76" - expected_result = %{name: "Ayrat", surname: "Badykov", music: "Rock'n'Roll"} - - result = rlp_binary |> Decoder.decode(:map, keys: [:name, :surname, :music], encoding: :hex) + result = rlp_binary |> Decode.decode(encoding: :hex) assert result == expected_result end diff --git a/test/ex_rlp/encoder_test.exs b/test/ex_rlp/encode_test.exs similarity index 86% rename from test/ex_rlp/encoder_test.exs rename to test/ex_rlp/encode_test.exs index d150d92..f4b5e3c 100644 --- a/test/ex_rlp/encoder_test.exs +++ b/test/ex_rlp/encode_test.exs @@ -1,12 +1,12 @@ -defmodule ExRLP.EncoderTest do +defmodule ExRLP.EncodeTest do use ExUnit.Case - alias ExRLP.Encoder + alias ExRLP.Encode test "encodes empty string" do string = "" expected_result = "80" - result = string |> Encoder.encode(encoding: :hex) + result = string |> Encode.encode(encoding: :hex) assert result == expected_result end @@ -15,7 +15,7 @@ defmodule ExRLP.EncoderTest do string = "\u0000" expected_result = "00" - result = string |> Encoder.encode(encoding: :hex) + result = string |> Encode.encode(encoding: :hex) assert result == expected_result end @@ -24,7 +24,7 @@ defmodule ExRLP.EncoderTest do string = "\u0001" expected_result = "01" - result = string |> Encoder.encode(encoding: :hex) + result = string |> Encode.encode(encoding: :hex) assert result == expected_result end @@ -33,7 +33,7 @@ defmodule ExRLP.EncoderTest do string = "\u007F" expected_result = "7f" - result = string |> Encoder.encode(encoding: :hex) + result = string |> Encode.encode(encoding: :hex) assert result == expected_result end @@ -42,7 +42,7 @@ defmodule ExRLP.EncoderTest do string = "dog" expected_result = "83646f67" - result = string |> Encoder.encode(encoding: :hex) + result = string |> Encode.encode(encoding: :hex) assert result == expected_result end @@ -54,7 +54,7 @@ defmodule ExRLP.EncoderTest do "b74c6f72656d20697073756d20646f6c6f722073697" <> "420616d65742c20636f6e7365637465747572206164697069736963696e6720656c69" - result = string |> Encoder.encode(encoding: :hex) + result = string |> Encode.encode(encoding: :hex) assert result == expected_result end @@ -66,7 +66,7 @@ defmodule ExRLP.EncoderTest do "b8384c6f72656d20697073756d20646f6c6f722073697" <> "420616d65742c20636f6e7365637465747572206164697069736963696e6720656c6974" - result = string |> Encoder.encode(encoding: :hex) + result = string |> Encode.encode(encoding: :hex) assert result == expected_result end @@ -115,7 +115,7 @@ defmodule ExRLP.EncoderTest do "e6375732c206d65747573206163206f726e617265206375727375732c20646f6c6f72206a7573746f20" <> "756c747269636573206d657475732c20617420756c6c616d636f7270657220766f6c7574706174" - result = string |> Encoder.encode(encoding: :hex) + result = string |> Encode.encode(encoding: :hex) assert result == expected_result end @@ -124,7 +124,7 @@ defmodule ExRLP.EncoderTest do string = 0 expected_result = "80" - result = string |> Encoder.encode(encoding: :hex) + result = string |> Encode.encode(encoding: :hex) assert result == expected_result end @@ -133,7 +133,7 @@ defmodule ExRLP.EncoderTest do string = 1 expected_result = "01" - result = string |> Encoder.encode(encoding: :hex) + result = string |> Encode.encode(encoding: :hex) assert result == expected_result end @@ -142,7 +142,7 @@ defmodule ExRLP.EncoderTest do string = 16 expected_result = "10" - result = string |> Encoder.encode(encoding: :hex) + result = string |> Encode.encode(encoding: :hex) assert result == expected_result end @@ -151,7 +151,7 @@ defmodule ExRLP.EncoderTest do string = 79 expected_result = "4f" - result = string |> Encoder.encode(encoding: :hex) + result = string |> Encode.encode(encoding: :hex) assert result == expected_result end @@ -160,7 +160,7 @@ defmodule ExRLP.EncoderTest do string = 127 expected_result = "7f" - result = string |> Encoder.encode(encoding: :hex) + result = string |> Encode.encode(encoding: :hex) assert result == expected_result end @@ -169,7 +169,7 @@ defmodule ExRLP.EncoderTest do string = 128 expected_result = "8180" - result = string |> Encoder.encode(encoding: :hex) + result = string |> Encode.encode(encoding: :hex) assert result == expected_result end @@ -178,7 +178,7 @@ defmodule ExRLP.EncoderTest do string = 1000 expected_result = "8203e8" - result = string |> Encoder.encode(encoding: :hex) + result = string |> Encode.encode(encoding: :hex) assert result == expected_result end @@ -187,7 +187,7 @@ defmodule ExRLP.EncoderTest do string = 100_000 expected_result = "830186a0" - result = string |> Encoder.encode(encoding: :hex) + result = string |> Encode.encode(encoding: :hex) assert result == expected_result end @@ -196,7 +196,7 @@ defmodule ExRLP.EncoderTest do string = 83_729_609_699_884_896_815_286_331_701_780_722 expected_result = "8f102030405060708090a0b0c0d0e0f2" - result = string |> Encoder.encode(encoding: :hex) + result = string |> Encode.encode(encoding: :hex) assert result == expected_result end @@ -207,7 +207,7 @@ defmodule ExRLP.EncoderTest do expected_result = "9c0100020003000400050006000700080009000a000b000c000d000e01" - result = string |> Encoder.encode(encoding: :hex) + result = string |> Encode.encode(encoding: :hex) assert result == expected_result end @@ -216,7 +216,7 @@ defmodule ExRLP.EncoderTest do list = ["dog", "god", "cat"] expected_result = "cc83646f6783676f6483636174" - result = list |> Encoder.encode(encoding: :hex) + result = list |> Encode.encode(encoding: :hex) assert result == expected_result end @@ -225,7 +225,7 @@ defmodule ExRLP.EncoderTest do list = ["zw", [4], 1] expected_result = "c6827a77c10401" - result = list |> Encoder.encode(encoding: :hex) + result = list |> Encode.encode(encoding: :hex) assert result == expected_result end @@ -249,7 +249,7 @@ defmodule ExRLP.EncoderTest do "f784617364668471776572847a7863768461736466847" <> "1776572847a78637684617364668471776572847a78637684617364668471776572" - result = list |> Encoder.encode(encoding: :hex) + result = list |> Encode.encode(encoding: :hex) assert result == expected_result end @@ -266,7 +266,7 @@ defmodule ExRLP.EncoderTest do "f840cf84617364668471776572847a786376cf84617364668" <> "471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376" - result = list |> Encoder.encode(encoding: :hex) + result = list |> Encode.encode(encoding: :hex) assert result == expected_result end @@ -328,7 +328,7 @@ defmodule ExRLP.EncoderTest do "84617364668471776572847a786376cf84617364668471776572847a" <> "786376cf84617364668471776572847a786376" - result = list |> Encoder.encode(encoding: :hex) + result = list |> Encode.encode(encoding: :hex) assert result == expected_result end @@ -337,7 +337,7 @@ defmodule ExRLP.EncoderTest do list = [[[], []], []] expected_result = "c4c2c0c0c0" - result = list |> Encoder.encode(encoding: :hex) + result = list |> Encode.encode(encoding: :hex) assert result == expected_result end @@ -346,7 +346,7 @@ defmodule ExRLP.EncoderTest do list = [[], [[]], [[], [[]]]] expected_result = "c7c0c1c0c3c0c1c0" - result = list |> Encoder.encode(encoding: :hex) + result = list |> Encode.encode(encoding: :hex) assert result == expected_result end @@ -363,7 +363,7 @@ defmodule ExRLP.EncoderTest do "ecca846b6579318476616c31ca846b65" <> "79328476616c32ca846b6579338476616c33ca846b6579348476616c34" - result = list |> Encoder.encode(encoding: :hex) + result = list |> Encode.encode(encoding: :hex) assert result == expected_result end @@ -374,16 +374,7 @@ defmodule ExRLP.EncoderTest do expected_result = "a1010000000000000000000000000000000000000000000000000000000000000000" - result = big_integer |> Encoder.encode(encoding: :hex) - - assert result == expected_result - end - - test "encodes Map" do - map = %{name: "Ayrat", surname: "Badykov", music: "Rock'n'Roll"} - expected_result = "da8b526f636b276e27526f6c6c85417972617487426164796b6f76" - - result = map |> Encoder.encode(encoding: :hex) + result = big_integer |> Encode.encode(encoding: :hex) assert result == expected_result end diff --git a/test/ex_rlp/protocols_test.exs b/test/ex_rlp/protocols_test.exs new file mode 100644 index 0000000..106c766 --- /dev/null +++ b/test/ex_rlp/protocols_test.exs @@ -0,0 +1,34 @@ +defmodule ExRLP.ProtocolsTest do + use ExUnit.Case + alias ExRLP.LogEntry + + @log_entry LogEntry.new( + <<15, 87, 46, 82, 149, 197, 127, 21, 136, 111, 155, 38, 62, 47, 109, 45, 108, 123, + 94, 198>>, + [0, 0, 0], + <<255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255>> + ) + + describe "encode/2" do + test "encodes custom struct" do + expected_result = + <<248, 58, 148, 15, 87, 46, 82, 149, 197, 127, 21, 136, 111, 155, 38, 62, 47, 109, 45, + 108, 123, 94, 198, 195, 128, 128, 128, 160, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255>> + + assert ExRLP.encode(@log_entry) == expected_result + end + + test "encodes custom struct in list" do + expected_result = + <<248, 60, 248, 58, 148, 15, 87, 46, 82, 149, 197, 127, 21, 136, 111, 155, 38, 62, 47, + 109, 45, 108, 123, 94, 198, 195, 128, 128, 128, 160, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255>> + + assert ExRLP.encode([@log_entry]) == expected_result + end + end +end diff --git a/test/support/log_entry.ex b/test/support/log_entry.ex new file mode 100644 index 0000000..669a841 --- /dev/null +++ b/test/support/log_entry.ex @@ -0,0 +1,35 @@ +defmodule ExRLP.LogEntry do + @moduledoc false + + defstruct address: nil, topics: [], data: nil + + @type t :: %__MODULE__{ + address: EVM.address(), + topics: [integer()], + data: binary() + } + + @spec new(binary, [integer()], binary()) :: t() + def new(address, topics, data) do + %__MODULE__{ + address: address, + topics: topics, + data: data + } + end + + def to_list(log) do + [log.address, log.topics, log.data] + end +end + +defimpl ExRLP.Encode, for: ExRLP.LogEntry do + alias ExRLP.{Encode, LogEntry} + + @spec encode(LogEntry.t(), keyword()) :: binary() + def encode(log, options \\ []) do + log + |> LogEntry.to_list() + |> Encode.encode(options) + end +end