From c52fc31a0aeca875643c8c43156f7f6e4ee76286 Mon Sep 17 00:00:00 2001 From: CristhianRodriguezMolina <50219561+CristhianRodriguezMolina@users.noreply.github.com> Date: Thu, 20 Apr 2023 11:55:34 -0500 Subject: [PATCH] Created SCNonceKe, SCBytes and SCString and updated SCSymbol --- lib/xdr/contract/sc_bytes.ex | 47 +++++++++++++++ lib/xdr/contract/sc_nonce_key.ex | 55 ++++++++++++++++++ lib/xdr/contract/sc_string.ex | 48 ++++++++++++++++ lib/xdr/contract/sc_symbol.ex | 2 +- test/xdr/contract/sc_bytes_test.exs | 51 +++++++++++++++++ test/xdr/contract/sc_nonce_key_test.exs | 65 +++++++++++++++++++++ test/xdr/contract/sc_string_test.exs | 76 +++++++++++++++++++++++++ test/xdr/contract/sc_symbol_test.exs | 2 +- 8 files changed, 344 insertions(+), 2 deletions(-) create mode 100644 lib/xdr/contract/sc_bytes.ex create mode 100644 lib/xdr/contract/sc_nonce_key.ex create mode 100644 lib/xdr/contract/sc_string.ex create mode 100644 test/xdr/contract/sc_bytes_test.exs create mode 100644 test/xdr/contract/sc_nonce_key_test.exs create mode 100644 test/xdr/contract/sc_string_test.exs diff --git a/lib/xdr/contract/sc_bytes.ex b/lib/xdr/contract/sc_bytes.ex new file mode 100644 index 00000000..3765f5b8 --- /dev/null +++ b/lib/xdr/contract/sc_bytes.ex @@ -0,0 +1,47 @@ +defmodule StellarBase.XDR.SCBytes do + @moduledoc """ + Representation of Stellar `SCBytes` type. + """ + alias StellarBase.XDR.VariableOpaque256000 + + @behaviour XDR.Declaration + + @type t :: %__MODULE__{value: binary()} + + defstruct [:value] + + @spec new(value :: binary()) :: t() + def new(value), do: %__MODULE__{value: value} + + @impl true + def encode_xdr(%__MODULE__{value: value}) do + value + |> VariableOpaque256000.new() + |> VariableOpaque256000.encode_xdr() + end + + @impl true + def encode_xdr!(%__MODULE__{value: value}) do + value + |> VariableOpaque256000.new() + |> VariableOpaque256000.encode_xdr!() + end + + @impl true + def decode_xdr(bytes, term \\ nil) + + def decode_xdr(bytes, _term) do + case VariableOpaque256000.decode_xdr(bytes) do + {:ok, {%VariableOpaque256000{opaque: value}, rest}} -> {:ok, {new(value), rest}} + error -> error + end + end + + @impl true + def decode_xdr!(bytes, term \\ nil) + + def decode_xdr!(bytes, _term) do + {%VariableOpaque256000{opaque: value}, rest} = VariableOpaque256000.decode_xdr!(bytes) + {new(value), rest} + end +end diff --git a/lib/xdr/contract/sc_nonce_key.ex b/lib/xdr/contract/sc_nonce_key.ex new file mode 100644 index 00000000..0374d78e --- /dev/null +++ b/lib/xdr/contract/sc_nonce_key.ex @@ -0,0 +1,55 @@ +defmodule StellarBase.XDR.SCNonceKey do + @moduledoc """ + Representation of Stellar `SCNonceKey` type. + """ + alias StellarBase.XDR.SCAddress + + @behaviour XDR.Declaration + + @struct_spec XDR.Struct.new(nonce_address: SCAddress) + + @type t :: %__MODULE__{nonce_address: SCAddress.t()} + + defstruct [:nonce_address] + + @spec new(nonce_address :: SCAddress.t()) :: t() + def new(%SCAddress{} = nonce_address), + do: %__MODULE__{nonce_address: nonce_address} + + @impl true + def encode_xdr(%__MODULE__{nonce_address: nonce_address}) do + [nonce_address: nonce_address] + |> XDR.Struct.new() + |> XDR.Struct.encode_xdr() + end + + @impl true + def encode_xdr!(%__MODULE__{nonce_address: nonce_address}) do + [nonce_address: nonce_address] + |> XDR.Struct.new() + |> XDR.Struct.encode_xdr!() + end + + @impl true + def decode_xdr(bytes, struct \\ @struct_spec) + + def decode_xdr(bytes, struct) do + case XDR.Struct.decode_xdr(bytes, struct) do + {:ok, {%XDR.Struct{components: [nonce_address: nonce_address]}, rest}} -> + {:ok, {new(nonce_address), rest}} + + error -> + error + end + end + + @impl true + def decode_xdr!(bytes, struct \\ @struct_spec) + + def decode_xdr!(bytes, struct) do + {%XDR.Struct{components: [nonce_address: nonce_address]}, rest} = + XDR.Struct.decode_xdr!(bytes, struct) + + {new(nonce_address), rest} + end +end diff --git a/lib/xdr/contract/sc_string.ex b/lib/xdr/contract/sc_string.ex new file mode 100644 index 00000000..4aad8a1f --- /dev/null +++ b/lib/xdr/contract/sc_string.ex @@ -0,0 +1,48 @@ +defmodule StellarBase.XDR.SCString do + @moduledoc """ + Representation of Stellar `SCString` type. + """ + + @behaviour XDR.Declaration + + @type t :: %__MODULE__{value: String.t()} + + defstruct [:value] + + @max_length 256_000 + + @spec new(value :: String.t()) :: t() + def new(value), do: %__MODULE__{value: value} + + @impl true + def encode_xdr(%__MODULE__{value: value}) do + value + |> XDR.String.new(@max_length) + |> XDR.String.encode_xdr() + end + + @impl true + def encode_xdr!(%__MODULE__{value: value}) do + value + |> XDR.String.new(@max_length) + |> XDR.String.encode_xdr!() + end + + @impl true + def decode_xdr(bytes, term \\ nil) + + def decode_xdr(bytes, _term) do + case XDR.String.decode_xdr(bytes) do + {:ok, {%XDR.String{string: value}, rest}} -> {:ok, {new(value), rest}} + error -> error + end + end + + @impl true + def decode_xdr!(bytes, term \\ nil) + + def decode_xdr!(bytes, _term) do + {%XDR.String{string: value}, rest} = XDR.String.decode_xdr!(bytes) + {new(value), rest} + end +end diff --git a/lib/xdr/contract/sc_symbol.ex b/lib/xdr/contract/sc_symbol.ex index b1c28236..f05552b1 100644 --- a/lib/xdr/contract/sc_symbol.ex +++ b/lib/xdr/contract/sc_symbol.ex @@ -9,7 +9,7 @@ defmodule StellarBase.XDR.SCSymbol do defstruct [:value] - @max_length 10 + @max_length 32 @spec new(value :: String.t()) :: t() def new(value), do: %__MODULE__{value: value} diff --git a/test/xdr/contract/sc_bytes_test.exs b/test/xdr/contract/sc_bytes_test.exs new file mode 100644 index 00000000..fa10ff30 --- /dev/null +++ b/test/xdr/contract/sc_bytes_test.exs @@ -0,0 +1,51 @@ +defmodule StellarBase.XDR.SCBytesTest do + use ExUnit.Case + + alias StellarBase.XDR.SCBytes + + describe "SCBytes" do + setup do + %{ + sc_bytes: SCBytes.new("GCIZ3GSM5"), + binary: <<0, 0, 0, 9, 71, 67, 73, 90, 51, 71, 83, 77, 53, 0, 0, 0>> + } + end + + test "new/1" do + %SCBytes{value: sc_bytes} = + SCBytes.new(<<0, 0, 0, 9, 71, 67, 73, 90, 51, 71, 83, 77, 53, 0, 0, 0>>) + + 16 = String.length(sc_bytes) + end + + test "encode_xdr/1", %{sc_bytes: sc_bytes, binary: binary} do + {:ok, ^binary} = SCBytes.encode_xdr(sc_bytes) + end + + test "encode_xdr!/1", %{sc_bytes: sc_bytes, binary: binary} do + ^binary = SCBytes.encode_xdr!(sc_bytes) + end + + test "decode_xdr/2", %{sc_bytes: sc_bytes, binary: binary} do + {:ok, {^sc_bytes, ""}} = SCBytes.decode_xdr(binary) + end + + test "decode_xdr/2 with an invalid binary" do + {:error, :not_binary} = SCBytes.decode_xdr(123) + end + + test "decode_xdr!/2", %{sc_bytes: sc_bytes, binary: binary} do + {^sc_bytes, ""} = SCBytes.decode_xdr!(binary) + end + + test "invalid length" do + bits = 256_001 * 8 + binary = <<0::size(bits)>> + + {:error, :invalid_length} = + SCBytes.encode_xdr(%SCBytes{ + value: binary + }) + end + end +end diff --git a/test/xdr/contract/sc_nonce_key_test.exs b/test/xdr/contract/sc_nonce_key_test.exs new file mode 100644 index 00000000..7da60652 --- /dev/null +++ b/test/xdr/contract/sc_nonce_key_test.exs @@ -0,0 +1,65 @@ +defmodule StellarBase.XDR.SCNonceKeyTest do + use ExUnit.Case + + alias StellarBase.StrKey + + alias StellarBase.XDR.{ + AccountID, + SCNonceKey, + PublicKeyType, + PublicKey, + SCAddressType, + SCAddress, + UInt256 + } + + describe "SCNonceKey" do + setup do + pk_type = PublicKeyType.new(:PUBLIC_KEY_TYPE_ED25519) + + account_id = + "GBZNLMUQMIN3VGUJISKZU7GNY3O3XLMYEHJCKCSMDHKLGSMKALRXOEZD" + |> StrKey.decode!(:ed25519_public_key) + |> UInt256.new() + |> PublicKey.new(pk_type) + |> AccountID.new() + + sc_address_type = SCAddressType.new(:SC_ADDRESS_TYPE_ACCOUNT) + + sc_address = SCAddress.new(account_id, sc_address_type) + + %{ + sc_address: sc_address, + sc_nonce_key: SCNonceKey.new(sc_address), + binary: + <<0, 0, 0, 0, 0, 0, 0, 0, 114, 213, 178, 144, 98, 27, 186, 154, 137, 68, 149, 154, 124, + 205, 198, 221, 187, 173, 152, 33, 210, 37, 10, 76, 25, 212, 179, 73, 138, 2, 227, + 119>> + } + end + + test "new/1", %{sc_address: sc_address} do + %SCNonceKey{nonce_address: ^sc_address} = SCNonceKey.new(sc_address) + end + + test "encode_xdr/1", %{sc_nonce_key: sc_nonce_key, binary: binary} do + {:ok, ^binary} = SCNonceKey.encode_xdr(sc_nonce_key) + end + + test "encode_xdr!/1", %{sc_nonce_key: sc_nonce_key, binary: binary} do + ^binary = SCNonceKey.encode_xdr!(sc_nonce_key) + end + + test "decode_xdr/2", %{sc_nonce_key: sc_nonce_key, binary: binary} do + {:ok, {^sc_nonce_key, ""}} = SCNonceKey.decode_xdr(binary) + end + + test "decode_xdr/2 with an invalid binary" do + {:error, :not_binary} = SCNonceKey.decode_xdr(123) + end + + test "decode_xdr!/2", %{sc_nonce_key: sc_nonce_key, binary: binary} do + {^sc_nonce_key, ^binary} = SCNonceKey.decode_xdr!(binary <> binary) + end + end +end diff --git a/test/xdr/contract/sc_string_test.exs b/test/xdr/contract/sc_string_test.exs new file mode 100644 index 00000000..73edb3d4 --- /dev/null +++ b/test/xdr/contract/sc_string_test.exs @@ -0,0 +1,76 @@ +defmodule StellarBase.XDR.SCStringTest do + use ExUnit.Case + + alias StellarBase.XDR.SCString + + describe "SCString" do + setup do + %{ + sc_symbol: SCString.new("Hello"), + binary: <<0, 0, 0, 5, 72, 101, 108, 108, 111, 0, 0, 0>> + } + end + + test "new/1" do + %SCString{value: "Hello"} = SCString.new("Hello") + end + + test "encode_xdr/1", %{sc_symbol: sc_symbol, binary: binary} do + {:ok, ^binary} = SCString.encode_xdr(sc_symbol) + end + + test "encode_xdr/1 a non-string value" do + {:error, :not_bitstring} = + 123 + |> SCString.new() + |> SCString.encode_xdr() + end + + test "encode_xdr/1 an invalid string lenght" do + bits = 256_001 * 8 + large_string = <<64::size(bits)>> + + {:error, :invalid_length} = + large_string + |> SCString.new() + |> SCString.encode_xdr() + end + + test "encode_xdr!/1", %{sc_symbol: sc_symbol, binary: binary} do + ^binary = SCString.encode_xdr!(sc_symbol) + end + + test "encode_xdr!/1 a string longer than 256000-bytes" do + bits = 256_001 * 8 + large_string = <<64::size(bits)>> + + assert_raise XDR.StringError, + "The length of the string exceeds the max length allowed", + fn -> + large_string + |> SCString.new() + |> SCString.encode_xdr!() + end + end + + test "decode_xdr/2", %{sc_symbol: sc_symbol, binary: binary} do + {:ok, {^sc_symbol, ""}} = SCString.decode_xdr(binary) + end + + test "decode_xdr/2 with an invalid binary" do + {:error, :not_binary} = SCString.decode_xdr(123) + end + + test "decode_xdr/2 an invalid binary" do + assert_raise XDR.VariableOpaqueError, + "The XDR has an invalid length, it must be less than byte-size of the rest", + fn -> + SCString.decode_xdr(<<0, 0, 4, 210>>) + end + end + + test "decode_xdr!/2", %{sc_symbol: sc_symbol, binary: binary} do + {^sc_symbol, ^binary} = SCString.decode_xdr!(binary <> binary) + end + end +end diff --git a/test/xdr/contract/sc_symbol_test.exs b/test/xdr/contract/sc_symbol_test.exs index 7ea92a0b..aabb3b4a 100644 --- a/test/xdr/contract/sc_symbol_test.exs +++ b/test/xdr/contract/sc_symbol_test.exs @@ -28,7 +28,7 @@ defmodule StellarBase.XDR.SCSymbolTest do test "encode_xdr/1 an invalid string lenght" do {:error, :invalid_length} = - "Hello There" + "The length of the string exceeds the max length allowed" |> SCSymbol.new() |> SCSymbol.encode_xdr() end