Packages
elixium_core
0.2.0
0.6.3
0.6.2
0.6.1
0.6.0
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.12
0.4.11
0.4.10
0.4.9
0.4.8
0.4.7
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.3.19
0.3.18
0.3.17
0.3.16
0.3.15
0.3.14
0.3.13
0.3.12
0.3.11
0.3.10
0.3.9
0.3.8
0.3.7
0.3.6
0.3.5
0.3.4
0.3.3
0.3.1
0.2.13
0.2.12
0.2.11
0.2.10
0.2.9
0.2.8
0.2.7
0.2.6
0.2.5
0.2.4
0.2.3
0.2.2
0.2.1
0.2.0
0.1.4
0.1.3
The core package for the Elixium blockchain, containing all the modules needed to run the chain
Current section
Files
Jump to
Current section
Files
lib/p2p/peer.ex
defmodule Elixium.P2P.Peer do
alias Elixium.Store.Oracle
require Logger
@testnet_url 'https://registry.testnet.elixium.app/'
@moduledoc """
Contains functionality for communicating with other peers
"""
@spec initialize(integer) :: pid
def initialize(port \\ 31_013) do
Logger.info("Starting listener socket on port #{port}.")
{:ok, supervisor} =
port
|> start_listener()
|> generate_handlers(port)
|> Supervisor.start_link(strategy: :one_for_one)
supervisor
end
defp start_listener(port) do
options = [:binary, reuseaddr: true, active: false]
case :gen_tcp.listen(port, options) do
{:ok, socket} -> socket
_ -> Logger.warn("Listen socket not started, something went wrong.")
end
end
defp generate_handlers(socket, port, count \\ 10) do
{:ok, oracle} = Oracle.start_link(Elixium.Store.Peer)
# Fetch known peers. We're going to try to connect to them
# before setting up a listener
peers = find_potential_peers(port, oracle)
for i <- 1..count do
%{
id: "peer_handler_#{i}",
start: {
Elixium.P2P.ConnectionHandler,
:start_link,
[socket, self(), peers, i, oracle]
},
type: :worker,
name: "peer_handler_#{i}"
}
end
end
# Either loads peers from a local storage or connects to the
# bootstrapping registry
@spec find_potential_peers(integer, pid) :: List | :not_found
defp find_potential_peers(port, oracle) do
case Oracle.inquire(oracle, {:load_known_peers, []}) do
:not_found -> fetch_peers_from_registry(port)
peers -> peers
end
end
# Connects to the bootstrapping peer registry and returns a list of
# previously connected peers.
@spec fetch_peers_from_registry(integer) :: List
defp fetch_peers_from_registry(port) do
case :httpc.request(@testnet_url ++ '/' ++ Integer.to_charlist(port)) do
{:ok, {{'HTTP/1.1', 200, 'OK'}, _headers, body}} ->
peers =
body
|> Jason.decode!()
|> Enum.map(&peerstring_to_tuple(&1))
|> Enum.filter(fn {_, port} -> port != nil end)
if peers == [] do
:not_found
else
peers
end
{:error, _} ->
:not_found
end
end
defp peerstring_to_tuple(peer) do
[ip, port] = String.split(peer, ":")
ip = String.to_charlist(ip)
port =
case Integer.parse(port) do
{port, _} -> port
:error -> nil
end
{ip, port}
end
@doc """
Given a peer supervisor, return a list of all the
handlers that are currently connected to another peer
"""
@spec connected_handlers(pid) :: List
def connected_handlers(supervisor) do
supervisor
|> Supervisor.which_children()
|> Enum.filter(fn {_, p, _, _} ->
dictionary =
p
|> Process.info()
|> Keyword.get(:dictionary)
match?([connected: _], dictionary)
end)
|> Enum.map(fn {_, p, _, _} -> p end)
end
end