Skip to content

Commit

Permalink
Merge pull request #376 from kommitters/v0.22
Browse files Browse the repository at this point in the history
V0.22
  • Loading branch information
keliumJU authored Aug 16, 2024
2 parents 30270d6 + 042ffe5 commit 61ad061
Show file tree
Hide file tree
Showing 19 changed files with 320 additions and 22 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Changelog

## 0.22.0 (16.08.2024)

- Add hash to handle transaction timeout response. See [PR #374](https://github.com/kommitters/stellar_sdk/pull/374)
- Add new async transaction submission endpoint. See [PR #373](https://github.com/kommitters/stellar_sdk/pull/373)

## 0.21.2 (23.07.2024)

- Update stellar base dependency.
Expand Down
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ The **Stellar SDK** is composed of two complementary components: **`TxBuild`** +
```elixir
def deps do
[
{:stellar_sdk, "~> 0.21.2"}
{:stellar_sdk, "~> 0.22.0"}
]
end
```
Expand Down Expand Up @@ -583,6 +583,9 @@ See [**Stellar.Horizon.Accounts**](https://hexdocs.pm/stellar_sdk/Stellar.Horizo
# submit a transaction
Stellar.Horizon.Transactions.create(Stellar.Horizon.Server.testnet(), base64_tx_envelope)

# submit a transaction asynchronously
Stellar.Horizon.Transactions.create_async(Stellar.Horizon.Server.testnet(), base64_tx_envelope)

# retrieve a transaction
Stellar.Horizon.Transactions.retrieve(Stellar.Horizon.Server.testnet(), "5ebd5c0af4385500b53dd63b0ef5f6e8feef1a7e1c86989be3cdcce825f3c0cc")

Expand Down
30 changes: 30 additions & 0 deletions lib/horizon/ErrorMapper.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
defmodule Stellar.Horizon.ErrorMapper do
@moduledoc """
Assigns errors returned by the HTTP client to a custom structure.
"""
alias Stellar.Horizon.AsyncTransactionError
alias Stellar.Horizon.AsyncTransaction
alias Stellar.Horizon.Error

@type error_source :: :horizon | :network
@type error_body :: map() | atom() | String.t()
@type error :: {error_source(), error_body()}

@type t :: {:error, struct()}

@spec build(error :: error()) :: t()
def build(
{:horizon,
%{hash: _hash, errorResultXdr: _error_result_xdr, tx_status: _tx_status} = decoded_body}
) do
error = AsyncTransactionError.new(decoded_body)
{:error, error}
end

def build({:horizon, %{hash: _hash, tx_status: _tx_status} = decoded_body}) do
error = AsyncTransaction.new(decoded_body)
{:error, error}
end

def build(error), do: {:error, Error.new(error)}
end
24 changes: 24 additions & 0 deletions lib/horizon/asyncTransaction.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
defmodule Stellar.Horizon.AsyncTransaction do
@moduledoc """
Represents a `Asynchronous transaction` resource from Horizon API.
"""

@behaviour Stellar.Horizon.Resource

alias Stellar.Horizon.Mapping

@type t :: %__MODULE__{
hash: String.t() | nil,
tx_status: String.t() | nil
}

defstruct [
:hash,
:tx_status
]

@impl true
def new(attrs, opts \\ [])

def new(attrs, _opts), do: Mapping.build(%__MODULE__{}, attrs)
end
26 changes: 26 additions & 0 deletions lib/horizon/asyncTransactionError.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
defmodule Stellar.Horizon.AsyncTransactionError do
@moduledoc """
Represents a `Asynchronous transaction error` resource from Horizon API.
"""

@behaviour Stellar.Horizon.Resource

alias Stellar.Horizon.Mapping

@type t :: %__MODULE__{
hash: String.t() | nil,
tx_status: String.t() | nil,
errorResultXdr: String.t() | nil
}

defstruct [
:hash,
:tx_status,
:errorResultXdr
]

@impl true
def new(attrs, opts \\ [])

def new(attrs, _opts), do: Mapping.build(%__MODULE__{}, attrs)
end
10 changes: 4 additions & 6 deletions lib/horizon/client/default.ex
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ defmodule Stellar.Horizon.Client.Default do

@behaviour Stellar.Horizon.Client.Spec

alias Stellar.Horizon.{Error, Server}
alias Stellar.Horizon.{ErrorMapper, Server}

@type status :: pos_integer()
@type headers :: [{binary(), binary()}, ...]
@type body :: binary()
@type success_response :: {:ok, status(), headers(), body()}
@type error_response :: {:error, status(), headers(), body()} | {:error, any()}
@type client_response :: success_response() | error_response()
@type parsed_response :: {:ok, map()} | {:error, Error.t()}
@type parsed_response :: {:ok, map()} | {:error, struct()}

@impl true
def request(%Server{url: base_url}, method, path, headers \\ [], body \\ "", opts \\ []) do
Expand All @@ -34,13 +34,11 @@ defmodule Stellar.Horizon.Client.Default do

defp handle_response({:ok, status, _headers, body}) when status >= 400 and status <= 599 do
decoded_body = json_library().decode!(body, keys: :atoms)
error = Error.new({:horizon, decoded_body})
{:error, error}
ErrorMapper.build({:horizon, decoded_body})
end

defp handle_response({:error, reason}) do
error = Error.new({:network, reason})
{:error, error}
ErrorMapper.build({:network, reason})
end

@spec http_client() :: atom()
Expand Down
14 changes: 12 additions & 2 deletions lib/horizon/error.ex
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,18 @@ defmodule Stellar.Horizon.Error do
@type detail :: String.t() | nil
@type base64_xdr :: String.t()
@type result_code :: String.t()
@type hash :: String.t()

@type result_codes :: %{
optional(:transaction) => result_code(),
optional(:operations) => list(result_code())
}
@type extras :: %{
optional(:hash) => hash(),
optional(:envelope_xdr) => base64_xdr(),
optional(:result_codes) => result_codes(),
optional(:result_xdr) => base64_xdr()
optional(:result_xdr) => base64_xdr(),
optional(:error) => detail()
}
@type error_source :: :horizon | :network
@type error_body :: map() | atom() | String.t()
Expand All @@ -30,7 +34,13 @@ defmodule Stellar.Horizon.Error do
extras: extras()
}

defstruct [:type, :title, :status_code, :detail, extras: %{}]
defstruct [
:type,
:title,
:status_code,
:detail,
extras: %{}
]

@spec new(error :: error()) :: t()
def new({:horizon, %{type: type, title: title, status: status_code, detail: detail} = error}) do
Expand Down
6 changes: 3 additions & 3 deletions lib/horizon/request.ex
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ defmodule Stellar.Horizon.Request do
At a minimum, a request must have the endpoint and method specified to be valid.
"""

alias Stellar.Horizon.{Collection, Error, Server}
alias Stellar.Horizon.{Collection, Server}
alias Stellar.Horizon.Client, as: Horizon

@type server :: Server.t()
Expand All @@ -26,8 +26,8 @@ defmodule Stellar.Horizon.Request do
@type opts :: Keyword.t()
@type params :: Keyword.t()
@type query_params :: list(atom())
@type response :: {:ok, map()} | {:error, Error.t()}
@type parsed_response :: {:ok, struct()} | {:error, Error.t()}
@type response :: {:ok, map()} | {:error, struct()}
@type parsed_response :: {:ok, struct()} | {:error, struct()}

@type t :: %__MODULE__{
method: method(),
Expand Down
35 changes: 33 additions & 2 deletions lib/horizon/transactions.ex
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,24 @@ defmodule Stellar.Horizon.Transactions do
Horizon API reference: https://developers.stellar.org/api/resources/transactions/
"""

alias Stellar.Horizon.{Collection, Effect, Error, Operation, Transaction, Request, Server}
alias Stellar.Horizon.{
Collection,
Effect,
Operation,
Transaction,
AsyncTransaction,
Request,
Server
}

@type server :: Server.t()
@type hash :: String.t()
@type options :: Keyword.t()
@type resource :: Transaction.t() | Collection.t()
@type response :: {:ok, resource()} | {:error, Error.t()}
@type response :: {:ok, resource()} | {:error, struct()}

@endpoint "transactions"
@endpoint_async "transactions_async"

@doc """
Creates a transaction to the Stellar network.
Expand Down Expand Up @@ -152,4 +161,26 @@ defmodule Stellar.Horizon.Transactions do
|> Request.perform()
|> Request.results(collection: {Operation, &list_operations(server, hash, &1)})
end

@doc """
Creates a transaction to the Stellar network asynchronously.
## Parameters:
* `server`: The Horizon server to query.
* `tx`: The base64-encoded XDR of the transaction.
## Examples
iex> Transactions.create_async(Stellar.Horizon.Server.testnet(), "AAAAAgAAAACQcEK2yfQA9CHrX+2UMkRIb/1wzltKqHpbdIcJbp+b/QAAAGQAAiEYAAAAAQAAAAEAAAAAAAAAAAAAAABgXP3QAAAAAQAAABBUZXN0IFRyYW5zYWN0aW9uAAAAAQAAAAAAAAABAAAAAJBwQrbJ9AD0Ietf7ZQyREhv/XDOW0qoelt0hwlun5v9AAAAAAAAAAAF9eEAAAAAAAAAAAFun5v9AAAAQKdJnG8QRiv9xGp1Oq7ACv/xR2BnNqjfUHrGNua7m4tWbrun3+GmAj6ca3xz+4ZppWRTbvTUcCxvpbHERZ85QgY=")
{:ok, %AsyncTransaction{}}
"""
@spec create_async(server :: server(), base64_envelope :: String.t()) :: response()
def create_async(server, base64_envelope) do
server
|> Request.new(:post, @endpoint_async)
|> Request.add_headers([{"Content-Type", "application/x-www-form-urlencoded"}])
|> Request.add_body(tx: base64_envelope)
|> Request.perform()
|> Request.results(as: AsyncTransaction)
end
end
2 changes: 1 addition & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ defmodule Stellar.MixProject do
use Mix.Project

@github_url "https://github.com/kommitters/stellar_sdk"
@version "0.21.2"
@version "0.22.0"

def project do
[
Expand Down
28 changes: 28 additions & 0 deletions test/horizon/async_transaction_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
defmodule Stellar.Horizon.AsyncTransactionTest do
use ExUnit.Case

alias Stellar.Test.Fixtures.Horizon

alias Stellar.Horizon.AsyncTransaction

setup do
json_body = Horizon.fixture("async_transaction")
attrs = Jason.decode!(json_body, keys: :atoms)

%{attrs: attrs}
end

test "new/2", %{attrs: attrs} do
%AsyncTransaction{
hash: "12958c37b341802a19ddada4c2a56b453a9cba728b2eefdfbc0b622e37379222",
tx_status: "PENDING"
} = AsyncTransaction.new(attrs)
end

test "new/2 empty_attrs" do
%AsyncTransaction{
hash: nil,
tx_status: nil
} = AsyncTransaction.new(%{})
end
end
11 changes: 9 additions & 2 deletions test/horizon/client/default_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,15 @@ defmodule Stellar.Horizon.Client.DefaultTest do
end

test "timeout", %{server: server} do
{:error, %Error{title: "Timeout", status_code: 504}} =
Default.request(server, :post, "/transactions?tx=timeout")
{:error,
%Error{
title: "Transaction Submission Timeout",
status_code: 504,
extras: %{
hash: _hash,
envelope_xdr: _envelope_xdr
}
}} = Default.request(server, :post, "/transactions?tx=timeout")
end

test "network_error", %{server: server} do
Expand Down
Loading

0 comments on commit 61ad061

Please sign in to comment.