diff --git a/lib/archethic/bootstrap.ex b/lib/archethic/bootstrap.ex index 4e7d7555c..aa9a5ee31 100644 --- a/lib/archethic/bootstrap.ex +++ b/lib/archethic/bootstrap.ex @@ -230,7 +230,8 @@ defmodule Archethic.Bootstrap do &(&1.first_public_key == Crypto.first_node_public_key()) ) - do_resync_network_chain([:oracle, :node_shared_secrets], nodes) + [:oracle, :node_shared_secrets, :reward] + |> Enum.each(&do_resync_network_chain(&1, nodes)) end end @@ -240,34 +241,31 @@ defmodule Archethic.Bootstrap do # by type: Get gen addr, get last address (remotely & locally) # compare, if dont match, fetch last tx remotely - def do_resync_network_chain(type_list, nodes) when is_list(nodes) do - Task.Supervisor.async_stream_nolink(Archethic.TaskSupervisor, type_list, fn type -> - with addr when is_binary(addr) <- get_genesis_addr(type), - {:ok, rem_last_addr} <- TransactionChain.resolve_last_address(addr), - {local_last_addr, _} <- TransactionChain.get_last_address(addr), - false <- rem_last_addr == local_last_addr, - {:ok, tx} <- TransactionChain.fetch_transaction_remotely(rem_last_addr, nodes), - :ok <- Replication.validate_and_store_transaction_chain(tx) do - Logger.info("Enforced Resync: Success", transaction_type: type) + def do_resync_network_chain(type, nodes) when is_list(nodes) do + with addr when is_binary(addr) <- get_genesis_addr(type), + {:ok, rem_last_addr} <- TransactionChain.resolve_last_address(addr), + {local_last_addr, _} <- TransactionChain.get_last_address(addr), + false <- rem_last_addr == local_last_addr, + {:ok, tx} <- TransactionChain.fetch_transaction_remotely(rem_last_addr, nodes), + :ok <- Replication.validate_and_store_transaction_chain(tx) do + Logger.info("Enforced Resync: Success", transaction_type: type) + :ok + else + true -> + Logger.info("Enforced Resync: No new transaction to sync", transaction_type: type) :ok - else - true -> - Logger.info("Enforced Resync: No new transaction to sync", transaction_type: type) - :ok - e when e in [nil, []] -> - Logger.debug("Enforced Resync: Transaction not available", transaction_type: type) - :ok + e when e in [nil, []] -> + Logger.debug("Enforced Resync: Transaction not available", transaction_type: type) + :ok - e -> - Logger.debug("Enforced Resync: Unexpected Error", transaction_type: type) - Logger.debug(e) - end - end) - |> Stream.run() + e -> + Logger.debug("Enforced Resync: Unexpected Error", transaction_type: type) + Logger.debug(e) + end end - @spec get_genesis_addr(:node_shared_secrets | :oracle) :: binary() | nil + @spec get_genesis_addr(:node_shared_secrets | :oracle | :reward) :: binary() | nil defp get_genesis_addr(:oracle) do Archethic.OracleChain.genesis_address().current |> elem(0) end @@ -276,6 +274,10 @@ defmodule Archethic.Bootstrap do Archethic.SharedSecrets.genesis_address(:node_shared_secrets) end + defp get_genesis_addr(:reward) do + Archethic.Reward.genesis_address() + end + defp first_initialization( ip, port, diff --git a/lib/archethic/mining/transaction_context.ex b/lib/archethic/mining/transaction_context.ex index 3016146ac..ede5d409b 100644 --- a/lib/archethic/mining/transaction_context.ex +++ b/lib/archethic/mining/transaction_context.ex @@ -10,7 +10,6 @@ defmodule Archethic.Mining.TransactionContext do alias Archethic.Election alias Archethic.P2P - alias Archethic.P2P.Message alias Archethic.P2P.Message.Ok alias Archethic.P2P.Message.Ping alias Archethic.P2P.Node @@ -61,7 +60,7 @@ defmodule Archethic.Mining.TransactionContext do prev_tx_task = request_previous_tx(previous_address, prev_tx_nodes_split) nodes_view_task = request_nodes_view(node_public_keys) - prev_tx = Task.await(prev_tx_task, Message.get_max_timeout()) + prev_tx = Task.await(prev_tx_task) nodes_view = Task.await(nodes_view_task) %{ @@ -102,15 +101,16 @@ defmodule Archethic.Mining.TransactionContext do Task.Supervisor.async( TaskSupervisor, fn -> - case TransactionChain.fetch_transaction_remotely(previous_address, nodes) do + # Timeout of 4 sec because the coordinator node wait 5 sec to get the context + # from the cross validation nodes + case TransactionChain.fetch_transaction_remotely(previous_address, nodes, 4000) do {:ok, tx} -> tx {:error, _} -> nil end - end, - timeout: Message.get_max_timeout() + end ) end diff --git a/lib/archethic/replication.ex b/lib/archethic/replication.ex index 89a3fb497..18afd8ee5 100644 --- a/lib/archethic/replication.ex +++ b/lib/archethic/replication.ex @@ -268,10 +268,10 @@ defmodule Archethic.Replication do {previous_transaction, inputs} = if self_repair? do - {Task.await(t1, Message.get_max_timeout()), []} + {Task.await(t1, Message.get_max_timeout() + 1000), []} else - t2 = Task.Supervisor.async(TaskSupervisor, fn -> fetch_inputs(tx, download_nodes) end) - {Task.await(t1, Message.get_max_timeout()), Task.await(t2)} + inputs = fetch_inputs(tx, download_nodes) + {Task.await(t1, Message.get_max_timeout() + 1000), inputs} end Logger.debug("Previous transaction #{inspect(previous_transaction)}", diff --git a/lib/archethic/transaction_chain.ex b/lib/archethic/transaction_chain.ex index d5d131d3d..49b01a20e 100644 --- a/lib/archethic/transaction_chain.ex +++ b/lib/archethic/transaction_chain.ex @@ -687,14 +687,21 @@ defmodule Archethic.TransactionChain do If no nodes are available to answer the request, `{:error, :network_issue}` is returned. """ - @spec fetch_transaction_remotely(address :: Crypto.versioned_hash(), list(Node.t())) :: + @spec fetch_transaction_remotely( + address :: Crypto.versioned_hash(), + list(Node.t()), + non_neg_integer() + ) :: {:ok, Transaction.t()} | {:error, :transaction_not_exists} | {:error, :transaction_invalid} | {:error, :network_issue} - def fetch_transaction_remotely(_, []), do: {:error, :transaction_not_exists} + def fetch_transaction_remotely(address, nodes, timeout \\ Message.get_max_timeout()) + + def fetch_transaction_remotely(_, [], _), do: {:error, :transaction_not_exists} - def fetch_transaction_remotely(address, nodes) when is_binary(address) and is_list(nodes) do + def fetch_transaction_remotely(address, nodes, timeout) + when is_binary(address) and is_list(nodes) do conflict_resolver = fn results -> # Prioritize transactions results over not found with nil <- Enum.find(results, &match?(%Transaction{}, &1)), @@ -709,7 +716,8 @@ defmodule Archethic.TransactionChain do case P2P.quorum_read( nodes, %GetTransaction{address: address}, - conflict_resolver + conflict_resolver, + timeout ) do {:ok, %NotFound{}} -> {:error, :transaction_not_exists} diff --git a/test/archethic/bootstrap_test.exs b/test/archethic/bootstrap_test.exs index 5718a0f51..f313b8a47 100644 --- a/test/archethic/bootstrap_test.exs +++ b/test/archethic/bootstrap_test.exs @@ -495,7 +495,7 @@ defmodule Archethic.BootstrapTest do assert :ok = Bootstrap.do_resync_network_chain( - [:node_shared_secrets], + :node_shared_secrets, _nodes = P2P.authorized_and_available_nodes() ) end @@ -523,7 +523,7 @@ defmodule Archethic.BootstrapTest do assert :ok = Bootstrap.do_resync_network_chain( - [:node_shared_secrets], + :node_shared_secrets, _nodes = P2P.authorized_and_available_nodes() ) @@ -598,7 +598,7 @@ defmodule Archethic.BootstrapTest do assert :ok = Bootstrap.do_resync_network_chain( - [:node_shared_secrets], + :node_shared_secrets, _nodes = P2P.authorized_and_available_nodes() )