Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 88 additions & 21 deletions apps/aecore/lib/aecore/peers/worker.ex
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ defmodule Aecore.Peers.Worker do
require Logger

@mersenne_prime 2147483647
@max_peers 50

def start_link(_args) do
GenServer.start_link(__MODULE__, %{peers: %{}, nonce: :rand.uniform(@mersenne_prime)}, name: __MODULE__)
Expand Down Expand Up @@ -48,6 +49,11 @@ defmodule Aecore.Peers.Worker do
GenServer.call(__MODULE__, :get_peers_nonce)
end

@spec add_peers_from_peers() :: :ok
def add_peers_from_peers() do
GenServer.call(__MODULE__, :add_peers_from_peers)
end

@spec genesis_block_header_hash() :: term()
def genesis_block_header_hash() do
Block.genesis_block().header
Expand All @@ -72,28 +78,17 @@ defmodule Aecore.Peers.Worker do
{:ok, initial_peers}
end

def handle_call({:add_peer,uri}, _from, %{peers: peers, nonce: own_nonce} = state) do
case(Client.get_info(uri)) do
{:ok, info} ->
case own_nonce == info.peer_nonce do
false ->
if(info.genesis_block_hash == genesis_block_header_hash()) do
updated_peers = Map.put(peers, uri, info.current_block_hash)
Logger.info(fn -> "Added #{uri} to the peer list" end)
{:reply, :ok, %{state | peers: updated_peers}}
else
Logger.error(fn ->
"Failed to add #{uri}, genesis header hash not valid" end)
{:reply, {:error, "Genesis header hash not valid"}, %{state | peers: peers}}
end
true ->
Logger.debug(fn ->
"Failed to add #{uri}, equal peer nonces" end)
{:reply, {:error, "Equal peer nonces"}, %{state | peers: peers}}
def handle_call({:add_peer, uri}, _from, state) do
case add_peer(uri, state) do
{:ok, state_with_peer} ->
case add_peer_peers(uri, state_with_peer) do
{:ok, state_with_peer_peers} ->
{:reply, :ok, state_with_peer_peers}
{:error, message} ->
{:reply, {:error, message}, state}
end
:error ->
Logger.error("GET /info request error")
{:reply, :error, %{state | peers: peers}}
{:error, message} ->
{:reply, {:error, message}, state}
end
end

Expand Down Expand Up @@ -142,6 +137,27 @@ def handle_call({:add_peer,uri}, _from, %{peers: peers, nonce: own_nonce} = stat
{:reply, state.nonce, state}
end

def handle_call(:add_peers_from_peers, _from, %{peers: peers, } = state) do
peers = Enum.reduce(peers, peers, fn({uri, _}, own_peers_acc) ->
case HttpClient.get_peers(uri) do
{:ok, peer_peers} ->
Enum.reduce(peer_peers, own_peers_acc, fn({uri, _}, updated_own_peers_acc) ->
case add_peer(uri, state) do
{:reply, :ok, state} ->
%{peers: updated_state_peers} = state
updated_state_peers
{:reply, :error, _} ->
updated_own_peers_acc
end
end)
:error ->
own_peers_acc
end
end)

{:reply, peers, %{state | peers: peers}}
end

## Async operations

def handle_cast({:broadcast_to_all, {type, data}}, %{peers: peers} = state) do
Expand All @@ -164,4 +180,55 @@ def handle_call({:add_peer,uri}, _from, %{peers: peers, nonce: own_nonce} = stat
defp prep_data(:new_tx, %{}=data), do: Serialization.tx(data, :serialize)
defp prep_data(:new_block, %{}=data), do: Serialization.block(data, :serialize)

defp add_peer(uri, state) do
%{peers: peers, nonce: own_nonce} = state
if(peers |> Map.keys() |> Enum.count() < @max_peers) do
case(Client.get_info(uri)) do
{:ok, info} ->
case own_nonce == info.peer_nonce do
false ->
if(info.genesis_block_hash == genesis_block_header_hash()) do
updated_peers = Map.put(peers, uri, info.current_block_hash)
Logger.info(fn -> "Added #{uri} to the peer list" end)
{:ok, %{state | peers: updated_peers}}
else
Logger.error(fn ->
"Failed to add #{uri}, genesis header hash not valid" end)
{:error, "Genesis header hash not valid"}
end
true ->
Logger.debug(fn ->
"Failed to add #{uri}, equal peer nonces" end)
{:error, "Equal peer nonces"}
end
:error ->
Logger.error("GET /info request error")
{:error, "GET /info request error"}
end
else
Logger.info("Max peers count reached")
{:error, "Max peers count reached"}
end
end

defp add_peer_peers(uri, state) do
%{peers: peers, } = state
case HttpClient.get_peers(uri) do
{:ok, peer_peers} ->
updated_peers = Enum.reduce(peer_peers, peers, fn({uri, _}, acc) ->
case add_peer(uri, %{state | peers: acc}) do
{:ok, state} ->
%{peers: updated_state_peers} = state
updated_state_peers
{:error, _} ->
acc
end
end)

{:ok, %{state | peers: updated_peers}}
:error ->
{:error, "GET /peers request error"}
end
end

end
2 changes: 1 addition & 1 deletion apps/aecore/test/aecore_peers_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ defmodule AecorePeersTest do
end

test "add peer, get all peers, check peers and remove the peer" do
assert :error = Peers.add_peer("localhost:4000")
assert {:error, _} = Peers.add_peer("localhost:4000")
assert Enum.count(Peers.all_peers) == 0
assert :ok = Peers.check_peers
assert {:error, "Peer not found"} =
Expand Down