diff --git a/README.md b/README.md index de07103..e937963 100644 --- a/README.md +++ b/README.md @@ -421,6 +421,31 @@ Soroban.RPC.get_ledger_entries(server, keys) ``` +#### Get Version Info + +Version information about the RPC and Captive core. + +**Parameters** + +- `server`: `Soroban.RPC.Server` struct - The Soroban-RPC server to interact with. + +**Example** + +```elixir +server = Soroban.RPC.Server.testnet() +Soroban.RPC.get_version_info(server) + +{:ok, + %Soroban.RPC.GetVersionInfoResponse{ + version: "21.4.0-dbb390c6bb99024122fccb12c8219af67d50db04", + commit_hash: "dbb390c6bb99024122fccb12c8219af67d50db04", + build_time_stamp: "2024-07-10T14:50:09", + captive_core_version: "stellar-core 21.1.1 (b3aeb14cc798f6d11deb2be913041be916f3b0cc)", + protocol_version: 21 + }} + +``` + #### Get Events Clients can request a filtered list of events emitted by a given ledger range. diff --git a/lib/rpc.ex b/lib/rpc.ex index 4b0484b..2173306 100644 --- a/lib/rpc.ex +++ b/lib/rpc.ex @@ -11,6 +11,7 @@ defmodule Soroban.RPC do GetLedgerEntriesResponse, GetNetwork, GetTransaction, + GetVersionInfo, SendTransaction, SimulateTransaction } @@ -41,6 +42,7 @@ defmodule Soroban.RPC do defdelegate get_health(server), to: GetHealth, as: :request defdelegate get_latest_ledger(server), to: GetLatestLedger, as: :request defdelegate get_network(server), to: GetNetwork, as: :request + defdelegate get_version_info(server), to: GetVersionInfo, as: :request defp encode_xdr(%LedgerKey{} = ledger_key) do ledger_key diff --git a/lib/rpc/endpoints/get_version_info.ex b/lib/rpc/endpoints/get_version_info.ex new file mode 100644 index 0000000..3a34c9d --- /dev/null +++ b/lib/rpc/endpoints/get_version_info.ex @@ -0,0 +1,19 @@ +defmodule Soroban.RPC.GetVersionInfo do + @moduledoc """ + GetVersionInfo request implementation for Soroban RPC. + """ + @behaviour Soroban.RPC.Endpoint.Spec + + alias Soroban.RPC.{GetVersionInfoResponse, Request} + + @endpoint "getVersionInfo" + + @impl true + def request(server, _params \\ nil) do + server + |> Request.new(@endpoint) + |> Request.add_headers([{"Content-Type", "application/json"}]) + |> Request.perform() + |> Request.results(as: GetVersionInfoResponse) + end +end diff --git a/lib/rpc/responses/get_version_info_response.ex b/lib/rpc/responses/get_version_info_response.ex new file mode 100644 index 0000000..38cbf07 --- /dev/null +++ b/lib/rpc/responses/get_version_info_response.ex @@ -0,0 +1,24 @@ +defmodule Soroban.RPC.GetVersionInfoResponse do + @moduledoc """ + `GetVersionInfoResponse` struct definition. + """ + @behaviour Soroban.RPC.Response.Spec + + @type version :: String.t() + @type commit_hash :: String.t() + @type build_time_stamp :: String.t() + @type captive_core_version :: String.t() + @type protocol_version :: non_neg_integer() + @type t :: %__MODULE__{ + version: version(), + commit_hash: commit_hash(), + build_time_stamp: build_time_stamp(), + captive_core_version: captive_core_version(), + protocol_version: protocol_version() + } + + defstruct [:version, :commit_hash, :build_time_stamp, :captive_core_version, :protocol_version] + + @impl true + def new(attrs), do: struct(%__MODULE__{}, attrs) +end diff --git a/test/rpc/endpoints/get_version_info_test.exs b/test/rpc/endpoints/get_version_info_test.exs new file mode 100644 index 0000000..aab1f67 --- /dev/null +++ b/test/rpc/endpoints/get_version_info_test.exs @@ -0,0 +1,50 @@ +defmodule Soroban.RPC.CannedGetVersionInfoClientImpl do + @moduledoc false + @behaviour Soroban.RPC.Client.Spec + + @impl true + def request(_endpoint, _url, _headers, _body, _opts) do + send(self(), {:request, "RESPONSE"}) + + {:ok, + %{ + version: "21.1.0", + commit_hash: "fcd2f0523f04279bae4502f3e3fa00ca627e6f6a", + build_time_stamp: "2024-05-10T11:18:38", + captive_core_version: "stellar-core 21.0.0.rc2 (c6f474133738ae5f6d11b07963ca841909210273)", + protocol_version: 21 + }} + end +end + +defmodule Soroban.RPC.GetVersionInfoTest do + use ExUnit.Case + + alias Soroban.RPC.{ + CannedGetVersionInfoClientImpl, + GetVersionInfo, + GetVersionInfoResponse, + Server + } + + setup do + Application.put_env(:soroban, :http_client_impl, CannedGetVersionInfoClientImpl) + + on_exit(fn -> + Application.delete_env(:soroban, :http_client_impl) + end) + + %{server: Server.testnet()} + end + + test "request/1", %{server: server} do + {:ok, + %GetVersionInfoResponse{ + version: "21.1.0", + commit_hash: "fcd2f0523f04279bae4502f3e3fa00ca627e6f6a", + build_time_stamp: "2024-05-10T11:18:38", + captive_core_version: "stellar-core 21.0.0.rc2 (c6f474133738ae5f6d11b07963ca841909210273)", + protocol_version: 21 + }} = GetVersionInfo.request(server) + end +end diff --git a/test/rpc/responses/get_versions_info_test.exs b/test/rpc/responses/get_versions_info_test.exs new file mode 100644 index 0000000..8f94f93 --- /dev/null +++ b/test/rpc/responses/get_versions_info_test.exs @@ -0,0 +1,39 @@ +defmodule Soroban.RPC.GetVetsionInfoResponseTest do + use ExUnit.Case + + alias Soroban.RPC.GetVersionInfoResponse + + setup do + %{ + result: %{ + version: "21.1.0", + commit_hash: "fcd2f0523f04279bae4502f3e3fa00ca627e6f6a", + build_time_stamp: "2024-05-10T11:18:38", + captive_core_version: + "stellar-core 21.0.0.rc2 (c6f474133738ae5f6d11b07963ca841909210273)", + protocol_version: 21 + } + } + end + + describe "new/1" do + test "when successful transaction", %{ + result: + %{ + version: version, + commit_hash: commit_hash, + build_time_stamp: build_time_stamp, + captive_core_version: captive_core_version, + protocol_version: protocol_version + } = result + } do + %GetVersionInfoResponse{ + version: ^version, + commit_hash: ^commit_hash, + build_time_stamp: ^build_time_stamp, + captive_core_version: ^captive_core_version, + protocol_version: ^protocol_version + } = GetVersionInfoResponse.new(result) + end + end +end diff --git a/test/rpc_test.exs b/test/rpc_test.exs index a5456ae..213ba2a 100644 --- a/test/rpc_test.exs +++ b/test/rpc_test.exs @@ -226,6 +226,25 @@ defmodule Soroban.RPC.CannedRPCGetTransactionClientImpl do end end +defmodule Soroban.RPC.CannedRPCGetVersionInfoClientImpl do + @moduledoc false + @behaviour Soroban.RPC.Client.Spec + + @impl true + def request(_endpoint, _url, _headers, _body, _opts) do + send(self(), {:request, "RESPONSE"}) + + {:ok, + %{ + version: "21.1.0", + commit_hash: "fcd2f0523f04279bae4502f3e3fa00ca627e6f6a", + build_time_stamp: "2024-05-10T11:18:38", + captive_core_version: "stellar-core 21.0.0.rc2 (c6f474133738ae5f6d11b07963ca841909210273)", + protocol_version: 21 + }} + end +end + defmodule Soroban.RPCTest do use ExUnit.Case @@ -239,6 +258,7 @@ defmodule Soroban.RPCTest do CannedRPCGetLedgerEntriesForAccountClientImpl, CannedRPCGetNetworkClientImpl, CannedRPCGetTransactionClientImpl, + CannedRPCGetVersionInfoClientImpl, CannedRPCSendTransactionClientImpl, CannedRPCSimulateTransactionClientImpl, EventFilter, @@ -519,4 +539,26 @@ defmodule Soroban.RPCTest do }} = RPC.get_events(server, event) end end + + describe "get_version_info/1" do + setup do + Application.put_env(:soroban, :http_client_impl, CannedRPCGetVersionInfoClientImpl) + + on_exit(fn -> + Application.delete_env(:soroban, :http_client_impl) + end) + end + + test "request/1", %{server: server} do + {:ok, + %{ + version: "21.1.0", + commit_hash: "fcd2f0523f04279bae4502f3e3fa00ca627e6f6a", + build_time_stamp: "2024-05-10T11:18:38", + captive_core_version: + "stellar-core 21.0.0.rc2 (c6f474133738ae5f6d11b07963ca841909210273)", + protocol_version: 21 + }} = RPC.get_version_info(server) + end + end end