Lately, I’ve been working on my Ethereum JSON RPC Client https://github.com/hswick/exw3. One of the dependencies it uses is https://github.com/exthereum/ethereumex which is a lower level RPC Client and handles sending messages back and forth from an Ethereum node. The team behind ethereumex had an open issue https://github.com/exthereum/ethereumex to add an IPC client. Along with this issue they included a nice little bounty of 0.4 eth. The idea behind this issue is that your program can communicate with the Ethereum node using IPC instead of HTTP. The benefits of this are performance and security. The security aspect is crucial because it enables signing transactions which involves sending the password to the Ethereum node. However, doing this over the wire with HTTP exposes you to packet sniffing attacks. Having this feature was a must, and receiving a nice little bounty was an extra bonus! In the end I was able to get this to work, and wanted to share my experience with the community because I didn’t feel this feature was well documented.

The reason this feature had not been added to ethereumex before is that the dogma around IPC with Elixir is that it couldn’t be done. Erlang communicates with processes in its VM not ones of the outside world. https://stackoverflow.com/questions/34711738/unix-domain-sockets-in-elixi r A lot of folks pointed towards the prockets library. But it didn’t look like a very elegant solution. After some digging it seemed that this feature was possible without using a library. I stumbled upon this post https://elixirforum.com/t/running-phoenix-on-a-unix-socket/9703. The user Voltone mentioned looking into Erlang’s :gen_tcp. And included this link http://erlang.org/doc/man/inet.html#type-local_address. I found this to be a bit cryptic, but it was a good start.

I’ve never used :gen_tcp before so I looked up some tutorials to get me started. Elixir provides a good tutorial https://elixir-lang.org/getting-started/mix-otp/task-and-gen-tcp.html. Basically create a GenServer that acts as the Server and you can send and receive messages over a port. Easy enough. What I wasn’t sure about was what to put for the connection information.

Turns out it was fairly trivial:

opts = [:binary, active: false, reuseaddr: true] response = :gen_tcp.connect({:local, state[:path]}, 0, opts)

Instead of a url pass a tuple: {:local, *path to unix socket*}. And instead of a port number, simply pass in 0. Wala! The feature worked. One thing to look out for is that your receive message might be getting cut off, so you’ll have to make sure to receive all of it.

If you want to see the full solution check it out here: https://github.com/exthereum/ethereumex

So in the end, I go the feature working, submitted the PR and it was merged. I included the new version into my library and I was able to reduce my test’s time by 5x. So big performance and security gain, couldn’t be more happy!