Skip to content

Commit

Permalink
Add geopatch to node transactions
Browse files Browse the repository at this point in the history
  • Loading branch information
Wassim Mansouri authored and Neylix committed Feb 7, 2025
1 parent 1807121 commit 57be8b7
Show file tree
Hide file tree
Showing 18 changed files with 698 additions and 212 deletions.
55 changes: 41 additions & 14 deletions lib/archethic/bootstrap.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ defmodule Archethic.Bootstrap do

alias Archethic.Crypto

alias Archethic.P2P.GeoPatch

alias Archethic.Networking

alias Archethic.P2P
Expand Down Expand Up @@ -98,15 +100,17 @@ defmodule Archethic.Bootstrap do
)
when is_number(port) and is_list(bootstrapping_seeds) and is_binary(reward_address) do
network_patch = get_network_patch(ip)
geo_patch = GeoPatch.from_ip(ip)

closest_bootstrapping_nodes = get_closest_nodes(bootstrapping_seeds, network_patch)

if should_bootstrap?(ip, port, http_port, transport, last_sync_date) do
if should_bootstrap?(ip, port, http_port, transport, geo_patch, last_sync_date) do
start_bootstrap(
ip,
port,
http_port,
transport,
geo_patch,
closest_bootstrapping_nodes,
reward_address
)
Expand Down Expand Up @@ -147,12 +151,12 @@ defmodule Archethic.Bootstrap do
end
end

defp should_bootstrap?(_ip, _port, _http_port, _, nil), do: true
defp should_bootstrap?(_ip, _port, _http_port, _, _, nil), do: true

defp should_bootstrap?(ip, port, http_port, transport, last_sync_date) do
defp should_bootstrap?(ip, port, http_port, transport, geo_patch, last_sync_date) do
case P2P.get_node_info(Crypto.first_node_public_key()) do
{:ok, _} ->
if Sync.require_update?(ip, port, http_port, transport, last_sync_date) do
if Sync.require_update?(ip, port, http_port, transport, geo_patch, last_sync_date) do
Logger.debug("Node chain need to updated")
true
else
Expand All @@ -171,6 +175,7 @@ defmodule Archethic.Bootstrap do
port,
http_port,
transport,
geo_patch,
closest_bootstrapping_nodes,
configured_reward_address
) do
Expand All @@ -187,7 +192,8 @@ defmodule Archethic.Bootstrap do
port,
http_port,
transport,
configured_reward_address
configured_reward_address,
geo_patch
)

Sync.initialize_network(tx)
Expand All @@ -203,7 +209,8 @@ defmodule Archethic.Bootstrap do
http_port,
transport,
closest_bootstrapping_nodes,
configured_reward_address
configured_reward_address,
geo_patch
)

true ->
Expand All @@ -215,15 +222,17 @@ defmodule Archethic.Bootstrap do
)

{:ok, _ip, _p2p_port, _http_port, _transport, last_reward_address, _origin_public_key,
_key_certificate, _mining_public_key} = Node.decode_transaction_content(content)
_key_certificate, _mining_public_key,
_geo_patch} = Node.decode_transaction_content(content)

update_node(
ip,
port,
http_port,
transport,
closest_bootstrapping_nodes,
last_reward_address
last_reward_address,
geo_patch
)
end
end
Expand Down Expand Up @@ -265,7 +274,8 @@ defmodule Archethic.Bootstrap do
http_port,
transport,
closest_bootstrapping_nodes,
configured_reward_address
configured_reward_address,
geo_patch
) do
# In case node had lose it's DB, we ask the network if the node chain already exists
{:ok, length} =
Expand All @@ -286,15 +296,23 @@ defmodule Archethic.Bootstrap do
TransactionChain.fetch_transaction(last_address, closest_bootstrapping_nodes)

{:ok, _ip, _p2p_port, _http_port, _transport, last_reward_address, _origin_public_key,
_key_certificate, _mining_public_key} = Node.decode_transaction_content(content)
_key_certificate, _mining_public_key,
_geo_patch} = Node.decode_transaction_content(content)

last_reward_address
else
configured_reward_address
end

tx =
TransactionHandler.create_node_transaction(ip, port, http_port, transport, reward_address)
TransactionHandler.create_node_transaction(
ip,
port,
http_port,
transport,
reward_address,
geo_patch
)

{:ok, validated_tx} = TransactionHandler.send_transaction(tx, closest_bootstrapping_nodes)

Expand All @@ -307,18 +325,27 @@ defmodule Archethic.Bootstrap do
)
end

defp update_node(_ip, _port, _http_port, _transport, [], _reward_address) do
defp update_node(_ip, _port, _http_port, _transport, [], _reward_address, _geo_patch) do
Logger.warning("Not enough nodes in the network. No node update")
end

defp update_node(ip, port, http_port, transport, closest_bootstrapping_nodes, reward_address) do
defp update_node(
ip,
port,
http_port,
transport,
closest_bootstrapping_nodes,
reward_address,
geo_patch
) do
tx =
TransactionHandler.create_node_transaction(
ip,
port,
http_port,
transport,
reward_address
reward_address,
geo_patch
)

{:ok, validated_tx} = TransactionHandler.send_transaction(tx, closest_bootstrapping_nodes)
Expand Down
73 changes: 50 additions & 23 deletions lib/archethic/bootstrap/sync.ex
Original file line number Diff line number Diff line change
Expand Up @@ -56,36 +56,63 @@ defmodule Archethic.Bootstrap.Sync do
:inet.port_number(),
:inet.port_number(),
P2P.supported_transport(),
binary(),
DateTime.t() | nil
) :: boolean()
def require_update?(_ip, _port, _http_port, _transport, nil), do: false
def require_update?(_ip, _port, _http_port, _transport, _geo_patch, nil), do: false

def require_update?(ip, port, http_port, transport, last_sync_date) do
def require_update?(ip, port, http_port, transport, geo_patch, last_sync_date) do
first_node_public_key = Crypto.first_node_public_key()

case P2P.authorized_and_available_nodes() do
[%Node{first_public_key: ^first_node_public_key}] ->
false
if is_node_active?(first_node_public_key) do
false
else
needs_update?(
ip,
port,
http_port,
transport,
geo_patch,
last_sync_date,
first_node_public_key
)
end
end

defp is_node_active?(first_node_public_key) do
P2P.authorized_and_available_nodes()
|> Enum.any?(fn %Node{first_public_key: pk} -> pk == first_node_public_key end)
end

defp needs_update?(
ip,
port,
http_port,
transport,
geo_patch,
last_sync_date,
first_node_public_key
) do
diff_sync = DateTime.diff(DateTime.utc_now(), last_sync_date, :second)

case P2P.get_node_info(first_node_public_key) do
{:ok,
%Node{
ip: prev_ip,
port: prev_port,
http_port: prev_http_port,
transport: prev_transport,
geo_patch: prev_geo_patch
}} ->
ip != prev_ip or
port != prev_port or
http_port != prev_http_port or
geo_patch != prev_geo_patch or
diff_sync > @out_of_sync_date_threshold or
prev_transport != transport

_ ->
diff_sync = DateTime.diff(DateTime.utc_now(), last_sync_date, :second)

case P2P.get_node_info(first_node_public_key) do
{:ok,
%Node{
ip: prev_ip,
port: prev_port,
http_port: prev_http_port,
transport: prev_transport
}}
when ip != prev_ip or port != prev_port or http_port != prev_http_port or
diff_sync > @out_of_sync_date_threshold or
prev_transport != transport ->
true

_ ->
false
end
false
end
end

Expand Down
35 changes: 22 additions & 13 deletions lib/archethic/bootstrap/transaction_handler.ex
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,21 @@ defmodule Archethic.Bootstrap.TransactionHandler do
p2p_port :: :inet.port_number(),
http_port :: :inet.port_number(),
transport :: P2P.supported_transport(),
reward_address :: Crypto.versioned_hash()
reward_address :: Crypto.versioned_hash(),
geo_patch :: binary()
) ::
Transaction.t()
def create_node_transaction(ip = {_, _, _, _}, port, http_port, transport, reward_address)
def create_node_transaction(
ip = {_, _, _, _},
port,
http_port,
transport,
reward_address,
geo_patch
)
when is_number(port) and port >= 0 and is_binary(reward_address) do
origin_public_key = Crypto.origin_node_public_key()
origin_public_key_certificate = Crypto.get_key_certificate(origin_public_key)
origin_public_certificate = Crypto.get_key_certificate(origin_public_key)
mining_public_key = Crypto.mining_node_public_key()

Transaction.new(:node, %TransactionData{
Expand All @@ -94,16 +102,17 @@ defmodule Archethic.Bootstrap.TransactionHandler do
]
""",
content:
Node.encode_transaction_content(
ip,
port,
http_port,
transport,
reward_address,
origin_public_key,
origin_public_key_certificate,
mining_public_key
)
Node.encode_transaction_content(%{
ip: ip,
port: port,
http_port: http_port,
transport: transport,
reward_address: reward_address,
origin_public_key: origin_public_key,
key_certificate: origin_public_certificate,
mining_public_key: mining_public_key,
geo_patch: geo_patch
})
})
end
end
15 changes: 13 additions & 2 deletions lib/archethic/mining/pending_transaction_validation.ex
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ defmodule Archethic.Mining.PendingTransactionValidation do
alias Archethic.OracleChain

alias Archethic.P2P
alias Archethic.P2P.GeoPatch
alias Archethic.P2P.Message.FirstPublicKey
alias Archethic.P2P.Message.GetFirstPublicKey
alias Archethic.P2P.Node
Expand Down Expand Up @@ -350,7 +351,8 @@ defmodule Archethic.Mining.PendingTransactionValidation do
},
_
) do
with {:ok, ip, port, _http_port, _, _, origin_public_key, key_certificate, mining_public_key} <-
with {:ok, ip, port, _http_port, _, _, origin_public_key, key_certificate, mining_public_key,
geo_patch} <-
Node.decode_transaction_content(content),
{:auth_origin, true} <-
{:auth_origin,
Expand All @@ -371,7 +373,9 @@ defmodule Archethic.Mining.PendingTransactionValidation do
{:mining_public_key, true} <-
{:mining_public_key,
Crypto.valid_public_key?(mining_public_key) and
Crypto.get_public_key_curve(mining_public_key) == :bls} do
Crypto.get_public_key_curve(mining_public_key) == :bls},
{:geo_patch, true} <-
{:geo_patch, valid_geopatch?(ip, geo_patch)} do
:ok
else
:error ->
Expand All @@ -395,6 +399,9 @@ defmodule Archethic.Mining.PendingTransactionValidation do

{:mining_public_key, false} ->
{:error, "Invalid mining public key"}

{:geo_patch, false} ->
{:error, "Invalid geo patch from IP"}
end
end

Expand Down Expand Up @@ -1000,6 +1007,10 @@ defmodule Archethic.Mining.PendingTransactionValidation do
end
end

defp valid_geopatch?(ip, calculated_geopatch) do
calculated_geopatch == GeoPatch.from_ip(ip)
end

defp get_allowed_node_key_origins do
:archethic
|> Application.get_env(__MODULE__, [])
Expand Down
3 changes: 2 additions & 1 deletion lib/archethic/mining/proof_of_work.ex
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,8 @@ defmodule Archethic.Mining.ProofOfWork do
}
}) do
{:ok, _ip, _p2p_port, _http_port, _transport, _reward_address, origin_public_key,
_origin_certificate, _mining_public_key} = Node.decode_transaction_content(content)
_origin_certificate, _mining_public_key,
_geo_patch} = Node.decode_transaction_content(content)

[origin_public_key]
end
Expand Down
Loading

0 comments on commit 57be8b7

Please sign in to comment.