From c313f502a6b575c797bb13f8c61deda20601645f Mon Sep 17 00:00:00 2001 From: joaop21 Date: Tue, 5 Aug 2025 18:06:31 +0100 Subject: [PATCH 1/6] update readme --- README.md | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/README.md b/README.md index e3d5020..d93aea6 100644 --- a/README.md +++ b/README.md @@ -228,6 +228,51 @@ request = Rpc.request("eth_subscribe", ["newHeads"]) - Real-time updates - Automatic connection management +### IPC Transport + +The IPC transport provides communication with local Ethereum nodes via Unix domain sockets: + +```elixir +# Provider configuration +defmodule MyProvider do + use Exth.Provider, + transport_type: :ipc, + path: "/tmp/ethereum.ipc", + # Optional IPC-specific configuration + timeout: 30_000, # Request timeout in ms + pool_size: 10, # Number of connections in the pool + socket_opts: [:binary, active: false, reuseaddr: true] +end + +# Direct client configuration +{:ok, client} = Exth.Rpc.new( + transport_type: :ipc, + path: "/tmp/ethereum.ipc", + timeout: 30_000, + pool_size: 5 +) + +# Make requests +request = Rpc.request("eth_blockNumber", []) +{:ok, response} = Rpc.send(client, request) +``` + +- 🔌 **IPC** (`:ipc`) + - Unix domain socket communication + - Connection pooling with NimblePool + - Low latency for local nodes + - Efficient resource utilization + - **Note**: Only available on Unix-like systems + +**IPC Configuration Options:** +- `:path` - (required) The Unix domain socket path (e.g., "/tmp/ethereum.ipc") +- `:timeout` - Request timeout in milliseconds (default: 30000) +- `:socket_opts` - TCP socket options (default: [:binary, active: false, reuseaddr: true]) +- `:pool_size` - Number of connections in the pool (default: 10) +- `:pool_lazy_workers` - Whether to create workers lazily (default: true) +- `:pool_worker_idle_timeout` - Worker idle timeout (default: nil) +- `:pool_max_idle_pings` - Maximum idle pings before worker termination (default: -1) + ### Custom Transport Implement your own transport by creating a module and implementing the From 6ee7136cb6be52af5d14e673a4579a28bdb8546f Mon Sep 17 00:00:00 2001 From: joaop21 Date: Tue, 5 Aug 2025 18:07:16 +0100 Subject: [PATCH 2/6] update transport docs --- lib/exth/transport.ex | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/lib/exth/transport.ex b/lib/exth/transport.ex index 5b4b588..07b239e 100644 --- a/lib/exth/transport.ex +++ b/lib/exth/transport.ex @@ -19,12 +19,9 @@ defmodule Exth.Transport do Currently supported: * `:http` - HTTP/HTTPS transport using Tesla with Mint adapter * `:websocket` - WebSocket transport using Fresh + * `:ipc` - Unix domain socket transport using NimblePool * `:custom` - Custom transport implementations - Coming soon: - * `:ws` - WebSocket transport - * `:ipc` - Unix domain socket transport - ## Usage # Create an HTTP transport @@ -40,6 +37,13 @@ defmodule Exth.Transport do dispatch_callback: fn response -> handle_response(response) end ) + # Create an IPC transport + transport = Transport.new(:ipc, + path: "/tmp/ethereum.ipc", + timeout: 30_000, + pool_size: 10 + ) + # Make requests {:ok, response} = Transport.call(transport, request) @@ -58,6 +62,16 @@ defmodule Exth.Transport do * `:dispatch_callback` - Callback function to handle incoming messages * `:module` - Optional custom WebSocket implementation + IPC-specific options: + + * `:path` - The Unix domain socket path (e.g., "/tmp/ethereum.ipc") + * `:timeout` - Request timeout in milliseconds (default: 30000) + * `:socket_opts` - TCP socket options (default: [:binary, active: false, reuseaddr: true]) + * `:pool_size` - Number of connections in the pool (default: 10) + * `:pool_lazy_workers` - Whether to create workers lazily (default: true) + * `:pool_worker_idle_timeout` - Worker idle timeout (default: nil) + * `:pool_max_idle_pings` - Maximum idle pings before worker termination (default: -1) + ## Custom Transport Implementation To implement a custom transport: @@ -107,6 +121,10 @@ defmodule Exth.Transport do * `{:error, :invalid_url}` - Invalid WebSocket URL format * `{:error, :missing_callback}` - Missing dispatch callback + IPC-specific errors: + * `{:error, {:socket_error, reason}}` - Socket communication error + * `{:error, :timeout}` - Request timeout + ## Best Practices * Use appropriate timeouts for your use case From 24bcf72fd28be7d2b2380171ff3560adb90d31d5 Mon Sep 17 00:00:00 2001 From: joaop21 Date: Tue, 5 Aug 2025 18:11:29 +0100 Subject: [PATCH 3/6] add example provider --- examples/lib/examples/provider/ipc_ethereum.ex | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 examples/lib/examples/provider/ipc_ethereum.ex diff --git a/examples/lib/examples/provider/ipc_ethereum.ex b/examples/lib/examples/provider/ipc_ethereum.ex new file mode 100644 index 0000000..f404a08 --- /dev/null +++ b/examples/lib/examples/provider/ipc_ethereum.ex @@ -0,0 +1,10 @@ +defmodule Examples.Provider.IpcEthereum do + @moduledoc false + + use Exth.Provider, + transport_type: :ipc, + path: "/tmp/anvil.ipc", + timeout: 30_000, + pool_size: 3, + socket_opts: [:binary, active: false, reuseaddr: true] +end From 1b02a5c6712417c7b3701b85e2344f740f463c73 Mon Sep 17 00:00:00 2001 From: joaop21 Date: Tue, 5 Aug 2025 18:11:36 +0100 Subject: [PATCH 4/6] add function to examples --- examples/lib/examples.ex | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/examples/lib/examples.ex b/examples/lib/examples.ex index 660d90b..230560c 100644 --- a/examples/lib/examples.ex +++ b/examples/lib/examples.ex @@ -18,6 +18,24 @@ defmodule Examples do end) end + def run_with_ipc(address \\ @vitalik_address) do + case Provider.IpcEthereum.block_number() do + {:ok, block_number} -> + case Provider.IpcEthereum.get_balance(address, block_number) do + {:ok, balance} -> + Logger.info("IPC Ethereum: block_number: #{block_number}") + Logger.info("IPC Ethereum: get_balance: #{balance}") + + {:error, reason} -> + Logger.error("IPC Ethereum: failed to get balance: #{inspect(reason)}") + end + + {:error, reason} -> + Logger.error("IPC Ethereum: failed to get block number: #{inspect(reason)}") + Logger.info("Make sure you have a local Ethereum node running with IPC enabled") + end + end + def run_with_clients(address \\ @vitalik_address) do [Provider.Ethereum, Provider.Polygon] |> Enum.map(fn provider -> {provider, provider.get_client()} end) From 2b1bd1ffc786fa8d48ed193abc31eb299ae06d66 Mon Sep 17 00:00:00 2001 From: joaop21 Date: Tue, 5 Aug 2025 18:11:41 +0100 Subject: [PATCH 5/6] improve readme --- examples/README.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/examples/README.md b/examples/README.md index d38df16..83914d6 100644 --- a/examples/README.md +++ b/examples/README.md @@ -51,9 +51,17 @@ For real-time updates and subscriptions: iex> Examples.subscribe_to_new_blocks() ``` +### 4. Using IPC Transport + +For local node communication via Unix domain sockets: + +```elixir +iex> Examples.run_with_ipc() +``` + ## Configuration -The app demonstrates three different ways to configure providers: +The app demonstrates four different ways to configure providers: 1. **Runtime Configuration** (Ethereum Provider): @@ -66,3 +74,7 @@ The app demonstrates three different ways to configure providers: 3. **WebSocket Subscriptions** (WsEthereum Provider): - Configuration is specified directly in the provider module + +4. **IPC Configuration** (IpcEthereum Provider): + + - Configuration is specified directly in the provider module From 48a204822e6bf4dbcf631bab322e10a18ff90972 Mon Sep 17 00:00:00 2001 From: joaop21 Date: Tue, 5 Aug 2025 18:11:47 +0100 Subject: [PATCH 6/6] update packages --- examples/mix.lock | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/mix.lock b/examples/mix.lock index ff7463a..022d27b 100644 --- a/examples/mix.lock +++ b/examples/mix.lock @@ -5,5 +5,6 @@ "mime": {:hex, :mime, "2.0.6", "8f18486773d9b15f95f4f4f1e39b710045fa1de891fada4516559967276e4dc2", [:mix], [], "hexpm", "c9945363a6b26d747389aac3643f8e0e09d30499a138ad64fe8fd1d13d9b153e"}, "mint": {:hex, :mint, "1.7.1", "113fdb2b2f3b59e47c7955971854641c61f378549d73e829e1768de90fc1abf1", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1 or ~> 0.2.0 or ~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "fceba0a4d0f24301ddee3024ae116df1c3f4bb7a563a731f45fdfeb9d39a231b"}, "mint_web_socket": {:hex, :mint_web_socket, "1.0.4", "0b539116dbb3d3f861cdf5e15e269a933cb501c113a14db7001a3157d96ffafd", [:mix], [{:mint, ">= 1.4.1 and < 2.0.0-0", [hex: :mint, repo: "hexpm", optional: false]}], "hexpm", "027d4c5529c45a4ba0ce27a01c0f35f284a5468519c045ca15f43decb360a991"}, + "nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"}, "tesla": {:hex, :tesla, "1.14.1", "71c5b031b4e089c0fbfb2b362e24b4478465773ae4ef569760a8c2899ad1e73c", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:finch, "~> 0.13", [hex: :finch, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:gun, ">= 1.0.0", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.21", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "4.4.2", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.0", [hex: :mint, repo: "hexpm", optional: true]}, {:mox, "~> 1.0", [hex: :mox, repo: "hexpm", optional: true]}, {:msgpax, "~> 2.3", [hex: :msgpax, repo: "hexpm", optional: true]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "c1dde8140a49a3bef5bb622356e77ac5a24ad0c8091f12c3b7fc1077ce797155"}, }