Skip to content

Commit

Permalink
Refactor bootstrap with NodeConfig module
Browse files Browse the repository at this point in the history
  • Loading branch information
Neylix committed Feb 10, 2025
1 parent 57be8b7 commit d48fe19
Show file tree
Hide file tree
Showing 22 changed files with 931 additions and 1,034 deletions.
384 changes: 133 additions & 251 deletions lib/archethic/bootstrap.ex

Large diffs are not rendered by default.

111 changes: 32 additions & 79 deletions lib/archethic/bootstrap/sync.ex
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ defmodule Archethic.Bootstrap.Sync do
alias Archethic.P2P.Message.GetStorageNonce
alias Archethic.P2P.Message.NotifyEndOfNodeSync
alias Archethic.P2P.Node
alias Archethic.P2P.NodeConfig

alias Archethic.SharedSecrets

Expand All @@ -36,95 +37,53 @@ defmodule Archethic.Bootstrap.Sync do
@doc """
Determines if network should be initialized
"""
@spec should_initialize_network?(list(Node.t())) :: boolean()
def should_initialize_network?([]) do
@spec should_initialize_network?(boostrapping_nodes :: list(Node.t()), node_key :: Crypto.key()) ::
boolean()
def should_initialize_network?([], _) do
TransactionChain.count_transactions_by_type(:node_shared_secrets) == 0
end

def should_initialize_network?([%Node{first_public_key: node_key} | _]) do
node_key == Crypto.first_node_public_key() and
TransactionChain.count_transactions_by_type(:node_shared_secrets) == 0
def should_initialize_network?([%Node{first_public_key: bootstrapping_node_key} | _], node_key)
when bootstrapping_node_key == node_key do
TransactionChain.count_transactions_by_type(:node_shared_secrets) == 0
end

def should_initialize_network?(_), do: false
def should_initialize_network?(_, _), do: false

@doc """
Determines if the node requires an update
"""
@spec require_update?(
:inet.ip_address(),
:inet.port_number(),
:inet.port_number(),
P2P.supported_transport(),
binary(),
DateTime.t() | nil
) :: boolean()
def require_update?(_ip, _port, _http_port, _transport, _geo_patch, nil), do: false

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

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
@spec require_update?(node_conig :: NodeConfig.t(), last_sync_date :: DateTime.t()) :: boolean()
def require_update?(_, nil), do: false

def require_update?(
node_config = %NodeConfig{first_public_key: first_public_key},
last_sync_date
) do
current_config = P2P.get_node_info() |> NodeConfig.from_node()
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

_ ->
false
cond do
first_node?(first_public_key) -> false
diff_sync > @out_of_sync_date_threshold -> true
true -> NodeConfig.different?(node_config, current_config)
end
end

defp first_node?(first_node_public_key) do
nodes = P2P.authorized_and_available_nodes()
match?([%Node{first_public_key: ^first_node_public_key}], nodes)
end

@doc """
Initialize the network by predefining the storage nonce, the first node transaction and the first node shared secrets and the genesis fund allocations
"""
@spec initialize_network(Transaction.t()) :: :ok
def initialize_network(node_tx = %Transaction{}) do
def initialize_network(node_tx = %Transaction{previous_public_key: first_public_key}) do
NetworkInit.create_storage_nonce()

secret_key = :crypto.strong_rand_bytes(32)
encrypted_secret_key = Crypto.ec_encrypt(secret_key, Crypto.last_node_public_key())
encrypted_secret_key = Crypto.ec_encrypt(secret_key, first_public_key)

encrypted_daily_nonce_seed = Crypto.aes_encrypt(@genesis_daily_nonce_seed, secret_key)
encrypted_transaction_seed = Crypto.aes_encrypt(:crypto.strong_rand_bytes(32), secret_key)
Expand All @@ -135,19 +94,13 @@ defmodule Archethic.Bootstrap.Sync do
encrypted_reward_seed::binary>>

:ok = Crypto.unwrap_secrets(secrets, encrypted_secret_key, ~U[1970-01-01 00:00:00Z])
:ok = node_tx |> NetworkInit.self_validation() |> NetworkInit.self_replication()

:ok =
node_tx
|> NetworkInit.self_validation()
|> NetworkInit.self_replication()

P2P.set_node_globally_available(Crypto.first_node_public_key(), DateTime.utc_now())
P2P.set_node_globally_synced(Crypto.first_node_public_key())
now = DateTime.utc_now()

P2P.authorize_node(
Crypto.last_node_public_key(),
SharedSecrets.next_application_date(DateTime.utc_now())
)
P2P.set_node_globally_available(first_public_key, now)
P2P.set_node_globally_synced(first_public_key)
P2P.authorize_node(first_public_key, SharedSecrets.next_application_date(now))

NetworkInit.init_software_origin_chain()
NetworkInit.init_node_shared_secrets_chain()
Expand Down
40 changes: 4 additions & 36 deletions lib/archethic/bootstrap/transaction_handler.ex
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
defmodule Archethic.Bootstrap.TransactionHandler do
@moduledoc false

alias Archethic.Crypto

alias Archethic.P2P
alias Archethic.P2P.Message.Ok
alias Archethic.P2P.Message.NewTransaction
alias Archethic.P2P.Node
alias Archethic.P2P.NodeConfig

alias Archethic.TransactionChain.Transaction
alias Archethic.TransactionChain.TransactionData
Expand Down Expand Up @@ -68,28 +67,8 @@ defmodule Archethic.Bootstrap.TransactionHandler do
@doc """
Create a new node transaction
"""
@spec create_node_transaction(
ip_address :: :inet.ip_address(),
p2p_port :: :inet.port_number(),
http_port :: :inet.port_number(),
transport :: P2P.supported_transport(),
reward_address :: Crypto.versioned_hash(),
geo_patch :: binary()
) ::
Transaction.t()
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_certificate = Crypto.get_key_certificate(origin_public_key)
mining_public_key = Crypto.mining_node_public_key()

@spec create_node_transaction(node_config :: NodeConfig.t()) :: Transaction.t()
def create_node_transaction(node_config) do
Transaction.new(:node, %TransactionData{
code: """
condition inherit: [
Expand All @@ -101,18 +80,7 @@ defmodule Archethic.Bootstrap.TransactionHandler do
token_transfers: true
]
""",
content:
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
})
content: Node.encode_transaction_content(node_config)
})
end
end
Loading

0 comments on commit d48fe19

Please sign in to comment.