From fc4e76f9b0525bdf03561ca1fa5b55caaedaee65 Mon Sep 17 00:00:00 2001 From: bchamagne Date: Tue, 22 Oct 2024 10:21:22 +0200 Subject: [PATCH 1/2] add force_acceptance flag use it in the replication when we are sure the previous transaction exists --- .../mining/smart_contract_validation.ex | 11 ++- lib/archethic/mining/transaction_context.ex | 10 +- lib/archethic/replication.ex | 14 ++- .../replication/transaction_context.ex | 20 ++-- lib/archethic/self_repair.ex | 26 ++--- lib/archethic/self_repair/sync.ex | 8 +- lib/archethic/transaction_chain.ex | 55 +++++++++-- .../mining/distributed_workflow_test.exs | 30 +++--- .../mining/standalone_workflow_test.exs | 3 +- .../replication/transaction_context_test.exs | 95 +++++++++++++++---- 10 files changed, 195 insertions(+), 77 deletions(-) diff --git a/lib/archethic/mining/smart_contract_validation.ex b/lib/archethic/mining/smart_contract_validation.ex index c215eac69..c3392be1e 100644 --- a/lib/archethic/mining/smart_contract_validation.ex +++ b/lib/archethic/mining/smart_contract_validation.ex @@ -280,6 +280,8 @@ defmodule Archethic.Mining.SmartContractValidation do end end + # TODO: instead of address we could have a transaction_summary with proof of validation/replication + # TODO: to avoid downloading the tx defp validate_trigger({:transaction, address, recipient}, _, contract_genesis_address, inputs) do storage_nodes = Election.storage_nodes(address, P2P.authorized_and_available_nodes()) @@ -288,7 +290,10 @@ defmodule Archethic.Mining.SmartContractValidation do inputs, &(&1.type == :call and &1.from == address) ), - {:ok, tx} <- TransactionChain.fetch_transaction(address, storage_nodes), + {:ok, tx} <- + TransactionChain.fetch_transaction(address, storage_nodes, + acceptance_resolver: :accept_transaction + ), true <- Enum.member?(tx.data.recipients, recipient) do {:ok, tx} else @@ -311,7 +316,9 @@ defmodule Archethic.Mining.SmartContractValidation do defp validate_trigger({:oracle, address}, _, _, _) do storage_nodes = Election.chain_storage_nodes(address, P2P.authorized_and_available_nodes()) - case TransactionChain.fetch_transaction(address, storage_nodes) do + case TransactionChain.fetch_transaction(address, storage_nodes, + acceptance_resolver: :accept_transaction + ) do {:ok, tx} -> {:ok, tx} diff --git a/lib/archethic/mining/transaction_context.ex b/lib/archethic/mining/transaction_context.ex index 410564519..ff9a6d212 100644 --- a/lib/archethic/mining/transaction_context.ex +++ b/lib/archethic/mining/transaction_context.ex @@ -57,7 +57,13 @@ defmodule Archethic.Mining.TransactionContext do |> List.flatten() |> Enum.uniq() - prev_tx_task = request_previous_tx(previous_address, authorized_nodes) + prev_tx_task = + if previous_address == genesis_address do + Task.completed(nil) + else + request_previous_tx(previous_address, authorized_nodes) + end + utxos_task = request_utxos(genesis_address, authorized_nodes) nodes_view_task = request_nodes_view(node_public_keys) @@ -88,7 +94,7 @@ defmodule Archethic.Mining.TransactionContext 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(previous_address, previous_storage_nodes, - search_mode: :remote, + acceptance_resolver: :accept_transaction, timeout: 4000 ) do {:ok, tx} -> diff --git a/lib/archethic/replication.ex b/lib/archethic/replication.ex index 06f38ad71..6efa032e7 100644 --- a/lib/archethic/replication.ex +++ b/lib/archethic/replication.ex @@ -307,12 +307,22 @@ defmodule Archethic.Replication do genesis_task = Task.Supervisor.async(TaskSupervisor, fn -> - TransactionContext.fetch_genesis_address(previous_address) + fetch_opts = + if TransactionChain.first_transaction?(tx), + do: [], + else: [acceptance_resolver: :accept_different_genesis] + + TransactionContext.fetch_genesis_address(previous_address, fetch_opts) end) previous_transaction_task = Task.Supervisor.async(TaskSupervisor, fn -> - TransactionContext.fetch_transaction(previous_address) + fetch_opts = + if TransactionChain.first_transaction?(tx), + do: [], + else: [acceptance_resolver: :accept_transaction] + + TransactionContext.fetch_transaction(previous_address, fetch_opts) end) resolved_addresses_task = diff --git a/lib/archethic/replication/transaction_context.ex b/lib/archethic/replication/transaction_context.ex index 0e6f0a4cc..2c46aa276 100644 --- a/lib/archethic/replication/transaction_context.ex +++ b/lib/archethic/replication/transaction_context.ex @@ -1,30 +1,26 @@ defmodule Archethic.Replication.TransactionContext do @moduledoc false - alias Archethic.Crypto - alias Archethic.BeaconChain - + alias Archethic.Crypto alias Archethic.Election - + alias Archethic.P2P alias Archethic.TransactionChain alias Archethic.TransactionChain.Transaction alias Archethic.TransactionChain.Transaction.ValidationStamp.LedgerOperations.VersionedUnspentOutput - alias Archethic.P2P - require Logger @doc """ Fetch transaction """ - @spec fetch_transaction(address :: Crypto.versioned_hash()) :: + @spec fetch_transaction(address :: Crypto.versioned_hash(), opts :: Keyword.t()) :: Transaction.t() | nil - def fetch_transaction(address) when is_binary(address) do + def fetch_transaction(address, opts \\ []) when is_binary(address) do storage_nodes = Election.chain_storage_nodes(address, P2P.authorized_and_available_nodes()) - case TransactionChain.fetch_transaction(address, storage_nodes) do + case TransactionChain.fetch_transaction(address, storage_nodes, opts) do {:ok, tx} -> tx @@ -36,12 +32,12 @@ defmodule Archethic.Replication.TransactionContext do @doc """ Fetch genesis address """ - @spec fetch_genesis_address(address :: Crypto.prepended_hash()) :: + @spec fetch_genesis_address(address :: Crypto.prepended_hash(), opts :: Keyword.t()) :: genesis_address :: Crypto.prepended_hash() - def fetch_genesis_address(address) do + def fetch_genesis_address(address, opts \\ []) do storage_nodes = Election.chain_storage_nodes(address, P2P.authorized_and_available_nodes()) - case TransactionChain.fetch_genesis_address(address, storage_nodes) do + case TransactionChain.fetch_genesis_address(address, storage_nodes, opts) do {:ok, genesis_address} -> genesis_address {:error, _} -> address end diff --git a/lib/archethic/self_repair.ex b/lib/archethic/self_repair.ex index d0aba0ff5..90c31f205 100755 --- a/lib/archethic/self_repair.ex +++ b/lib/archethic/self_repair.ex @@ -3,29 +3,21 @@ defmodule Archethic.SelfRepair do Synchronization for all the Archethic nodes relies on the self-repair mechanism started during the bootstrapping phase and stores last synchronization date after each cycle. """ + alias __MODULE__.Notifier + alias __MODULE__.NotifierSupervisor + alias __MODULE__.RepairWorker + alias __MODULE__.Scheduler + alias __MODULE__.Sync alias Archethic.BeaconChain - alias Archethic.Crypto - alias Archethic.Election - alias Archethic.P2P alias Archethic.P2P.Message alias Archethic.P2P.Node - alias Archethic.Replication - alias Archethic.TransactionChain - alias Archethic.TransactionChain.Transaction - alias Archethic.Utils - alias __MODULE__.Notifier - alias __MODULE__.NotifierSupervisor - alias __MODULE__.Scheduler - alias __MODULE__.Sync - alias __MODULE__.RepairWorker - require Logger defmodule Error do @@ -287,19 +279,13 @@ defmodule Archethic.SelfRepair do defp fetch_transaction_data(address, authorized_nodes) do timeout = Message.get_max_timeout() - acceptance_resolver = fn - %Transaction{address: ^address} -> true - _ -> false - end - storage_nodes = Election.chain_storage_nodes(address, authorized_nodes) [ Task.async(fn -> TransactionChain.fetch_transaction(address, storage_nodes, - search_mode: :remote, timeout: timeout, - acceptance_resolver: acceptance_resolver + acceptance_resolver: :accept_transaction ) end), Task.async(fn -> TransactionChain.fetch_inputs(address, storage_nodes) end) diff --git a/lib/archethic/self_repair/sync.ex b/lib/archethic/self_repair/sync.ex index b99d24e7d..60cfad993 100644 --- a/lib/archethic/self_repair/sync.ex +++ b/lib/archethic/self_repair/sync.ex @@ -412,7 +412,9 @@ defmodule Archethic.SelfRepair.Sync do Task.async(fn -> storage_nodes = Election.chain_storage_nodes(tx_address, download_nodes) - case TransactionChain.fetch_genesis_address(tx_address, storage_nodes) do + case TransactionChain.fetch_genesis_address(tx_address, storage_nodes, + acceptance_resolver: :accept_different_genesis + ) do {:ok, genesis_address} -> genesis_address @@ -516,7 +518,9 @@ defmodule Archethic.SelfRepair.Sync do fn recipient -> genesis_nodes = Election.chain_storage_nodes(recipient, authorized_nodes) - case TransactionChain.fetch_genesis_address(recipient, genesis_nodes) do + case TransactionChain.fetch_genesis_address(recipient, genesis_nodes, + acceptance_resolver: :accept_different_genesis + ) do {:ok, genesis_address} -> [recipient, genesis_address] diff --git a/lib/archethic/transaction_chain.ex b/lib/archethic/transaction_chain.ex index f634f86e2..2fbb47292 100644 --- a/lib/archethic/transaction_chain.ex +++ b/lib/archethic/transaction_chain.ex @@ -69,7 +69,7 @@ defmodule Archethic.TransactionChain do @type search_options :: [ timeout: non_neg_integer(), - acceptance_resolver: (any() -> boolean()), + acceptance_resolver: (any() -> boolean()) | atom(), consistency_level: pos_integer(), search_mode: search_mode() ] @@ -366,7 +366,7 @@ defmodule Archethic.TransactionChain do @spec fetch_transaction( address :: Crypto.prepended_hash(), storage_nodes :: list(Node.t()), - search_options() + opts :: search_options() ) :: {:ok, Transaction.t()} | {:error, :transaction_not_exists} @@ -379,7 +379,18 @@ defmodule Archethic.TransactionChain do else _ -> timeout = Keyword.get(opts, :timeout, Message.get_max_timeout()) - acceptance_resolver = Keyword.get(opts, :acceptance_resolver, fn _ -> true end) + + acceptance_resolver = + case Keyword.get(opts, :acceptance_resolver, fn _ -> true end) do + fun when is_function(fun, 1) -> + fun + + :accept_transaction -> + fn + %Transaction{address: ^address} -> true + _ -> false + end + end conflict_resolver = fn results -> Enum.reduce(results, fn @@ -811,16 +822,37 @@ defmodule Archethic.TransactionChain do Retrieve the genesis address for a chain from P2P Quorom It queries the the network for genesis address. """ - @spec fetch_genesis_address(address :: binary(), list(Node.t())) :: + @spec fetch_genesis_address(address :: binary(), nodes :: list(Node.t()), opts :: Keyword.t()) :: {:ok, binary()} | {:error, :network_issue} - def fetch_genesis_address(address, nodes) when is_binary(address) do + def fetch_genesis_address(address, nodes, opts \\ []) when is_binary(address) do case find_genesis_address(address) do {:error, :not_found} -> conflict_resolver = fn results -> Enum.min_by(results, & &1.timestamp, DateTime) end - case P2P.quorum_read(nodes, %GetGenesisAddress{address: address}, conflict_resolver) do + timeout = Keyword.get(opts, :timeout, 0) + + acceptance_resolver = + case Keyword.get(opts, :acceptance_resolver, fn _ -> true end) do + fun when is_function(fun, 1) -> + fun + + :accept_different_genesis -> + # credo:disable-for-next-line + fn + %GenesisAddress{address: ^address} -> false + %GenesisAddress{address: _} -> true + end + end + + case P2P.quorum_read( + nodes, + %GetGenesisAddress{address: address}, + conflict_resolver, + timeout, + acceptance_resolver + ) do {:ok, %GenesisAddress{address: genesis_address}} -> {:ok, genesis_address} @@ -1225,6 +1257,17 @@ defmodule Archethic.TransactionChain do |> Crypto.hash() end + @doc """ + By checking at the proof of integrity (determined by the coordinator) we can ensure a transaction is not the first + (because the poi contains the hash of the previous if any) + """ + @spec first_transaction?(Transaction.t()) :: boolean() + def first_transaction?( + tx = %Transaction{validation_stamp: %ValidationStamp{proof_of_integrity: poi}} + ) do + poi == proof_of_integrity([tx]) + end + @doc """ Load the transaction into the TransactionChain context filling the memory tables """ diff --git a/test/archethic/mining/distributed_workflow_test.exs b/test/archethic/mining/distributed_workflow_test.exs index bf2334b53..93de7451c 100644 --- a/test/archethic/mining/distributed_workflow_test.exs +++ b/test/archethic/mining/distributed_workflow_test.exs @@ -119,6 +119,7 @@ defmodule Archethic.Mining.DistributedWorkflowTest do {:ok, %{ + genesis: Transaction.previous_address(tx), tx: tx, sorting_seed: Election.validation_nodes_election_seed_sorting(tx, ~U[2021-05-11 08:50:21Z]) }} @@ -127,6 +128,7 @@ defmodule Archethic.Mining.DistributedWorkflowTest do describe "start_link/1" do test "should start mining by fetching the transaction context and elect storage nodes", %{ tx: tx, + genesis: genesis, sorting_seed: sorting_seed } do validation_nodes = @@ -146,7 +148,7 @@ defmodule Archethic.Mining.DistributedWorkflowTest do {:ok, %NotFound{}} _, %GetGenesisAddress{}, _ -> - {:ok, %GenesisAddress{address: "@Alice0", timestamp: DateTime.utc_now()}} + {:ok, %GenesisAddress{address: genesis, timestamp: DateTime.utc_now()}} _, %GetUnspentOutputs{}, _ -> {:ok, %UnspentOutputList{unspent_outputs: []}} @@ -181,7 +183,7 @@ defmodule Archethic.Mining.DistributedWorkflowTest do describe "add_mining_context/6" do test "should aggregate context and wait enough confirmed validation nodes context building", - %{tx: tx, sorting_seed: sorting_seed} do + %{tx: tx, genesis: genesis, sorting_seed: sorting_seed} do P2P.add_and_connect_node(%Node{ ip: {80, 10, 20, 102}, port: 3006, @@ -229,7 +231,7 @@ defmodule Archethic.Mining.DistributedWorkflowTest do {:ok, %NotFound{}} _, %GetGenesisAddress{}, _ -> - {:ok, %GenesisAddress{address: "@Alice0", timestamp: DateTime.utc_now()}} + {:ok, %GenesisAddress{address: genesis, timestamp: DateTime.utc_now()}} _, %GetUnspentOutputs{}, _ -> {:ok, %UnspentOutputList{unspent_outputs: []}} @@ -316,6 +318,7 @@ defmodule Archethic.Mining.DistributedWorkflowTest do test "aggregate context and create validation stamp when enough context are retrieved", %{ tx: tx, + genesis: genesis, sorting_seed: sorting_seed } do validation_nodes = @@ -335,7 +338,7 @@ defmodule Archethic.Mining.DistributedWorkflowTest do {:ok, %NotFound{}} _, %GetGenesisAddress{}, _ -> - {:ok, %GenesisAddress{address: "@Alice0", timestamp: DateTime.utc_now()}} + {:ok, %GenesisAddress{address: genesis, timestamp: DateTime.utc_now()}} _, %GetUnspentOutputs{}, _ -> {:ok, %UnspentOutputList{unspent_outputs: []}} @@ -427,7 +430,7 @@ defmodule Archethic.Mining.DistributedWorkflowTest do end test "should evict validations nodes which didn't confirm by sending their context in time", - %{tx: tx, sorting_seed: sorting_seed} do + %{tx: tx, genesis: genesis, sorting_seed: sorting_seed} do {pub, _} = Crypto.generate_deterministic_keypair("seed3") P2P.add_and_connect_node(%Node{ @@ -462,7 +465,7 @@ defmodule Archethic.Mining.DistributedWorkflowTest do {:ok, %NotFound{}} _, %GetGenesisAddress{}, _ -> - {:ok, %GenesisAddress{address: "@Alice0", timestamp: DateTime.utc_now()}} + {:ok, %GenesisAddress{address: genesis, timestamp: DateTime.utc_now()}} _, %GetUnspentOutputs{}, _ -> {:ok, %UnspentOutputList{unspent_outputs: []}} @@ -558,7 +561,7 @@ defmodule Archethic.Mining.DistributedWorkflowTest do describe "cross_validate/2" do test "should cross validate the validation stamp and the replication tree and then notify other node about it", - %{tx: tx, sorting_seed: sorting_seed} do + %{tx: tx, genesis: genesis, sorting_seed: sorting_seed} do {pub, _} = Crypto.generate_deterministic_keypair("seed3") P2P.add_and_connect_node(%Node{ @@ -595,7 +598,7 @@ defmodule Archethic.Mining.DistributedWorkflowTest do {:ok, %NotFound{}} _, %GetGenesisAddress{}, _ -> - {:ok, %GenesisAddress{address: "@Alice0", timestamp: DateTime.utc_now()}} + {:ok, %GenesisAddress{address: genesis, timestamp: DateTime.utc_now()}} _, %GetUnspentOutputs{}, _ -> {:ok, %UnspentOutputList{unspent_outputs: []}} @@ -767,6 +770,7 @@ defmodule Archethic.Mining.DistributedWorkflowTest do test "should cross validate and start replication when all cross validations are received", %{ tx: tx, + genesis: genesis, sorting_seed: sorting_seed } do validation_nodes = @@ -837,7 +841,7 @@ defmodule Archethic.Mining.DistributedWorkflowTest do {:ok, %NotFound{}} _, %GetGenesisAddress{}, _ -> - {:ok, %GenesisAddress{address: "@Alice0", timestamp: DateTime.utc_now()}} + {:ok, %GenesisAddress{address: genesis, timestamp: DateTime.utc_now()}} _, %Ping{}, _ -> {:ok, %Ok{}} @@ -1057,7 +1061,7 @@ defmodule Archethic.Mining.DistributedWorkflowTest do end end - test "should not replicate if there is a validation error", %{tx: tx} do + test "should not replicate if there is a validation error", %{tx: tx, genesis: genesis} do error = Error.new(:invalid_pending_transaction, "Transactiion already exists") validation_context = %ValidationContext{create_context(tx) | mining_error: error} @@ -1077,7 +1081,7 @@ defmodule Archethic.Mining.DistributedWorkflowTest do {:ok, %UnspentOutputList{unspent_outputs: []}} _, %GetGenesisAddress{}, _ -> - {:ok, %GenesisAddress{address: "@Alice0", timestamp: DateTime.utc_now()}} + {:ok, %GenesisAddress{address: genesis, timestamp: DateTime.utc_now()}} _, %ValidationError{}, _ -> send(me, :validation_error) @@ -1140,7 +1144,7 @@ defmodule Archethic.Mining.DistributedWorkflowTest do refute Process.alive?(coordinator_pid) end - test "should not replicate if there is a cross validation error", %{tx: tx} do + test "should not replicate if there is a cross validation error", %{tx: tx, genesis: genesis} do validation_context = create_context(tx) context = @@ -1155,7 +1159,7 @@ defmodule Archethic.Mining.DistributedWorkflowTest do {:ok, %Ok{}} _, %GetGenesisAddress{}, _ -> - {:ok, %GenesisAddress{address: "@Alice0", timestamp: DateTime.utc_now()}} + {:ok, %GenesisAddress{address: genesis, timestamp: DateTime.utc_now()}} _, %GetUnspentOutputs{}, _ -> {:ok, %UnspentOutputList{unspent_outputs: []}} diff --git a/test/archethic/mining/standalone_workflow_test.exs b/test/archethic/mining/standalone_workflow_test.exs index 4f732933b..e96af3ddd 100644 --- a/test/archethic/mining/standalone_workflow_test.exs +++ b/test/archethic/mining/standalone_workflow_test.exs @@ -105,7 +105,8 @@ defmodule Archethic.Mining.StandaloneWorkflowTest do end _, %GetGenesisAddress{}, _ -> - {:ok, %GenesisAddress{address: "@Alice0", timestamp: DateTime.utc_now()}} + {:ok, + %GenesisAddress{address: Transaction.previous_address(tx), timestamp: DateTime.utc_now()}} _, %ValidateTransaction{transaction: tx}, _ -> Agent.update(agent_pid, fn _ -> tx end) diff --git a/test/archethic/replication/transaction_context_test.exs b/test/archethic/replication/transaction_context_test.exs index 299dac0d3..6e0a89b7a 100644 --- a/test/archethic/replication/transaction_context_test.exs +++ b/test/archethic/replication/transaction_context_test.exs @@ -4,13 +4,16 @@ defmodule Archethic.Replication.TransactionContextTest do alias Archethic.Crypto alias Archethic.P2P + alias Archethic.P2P.Message.GetGenesisAddress alias Archethic.P2P.Message.GetTransaction alias Archethic.P2P.Message.GetTransactionChain + alias Archethic.P2P.Message.GenesisAddress alias Archethic.P2P.Message.GetUnspentOutputs alias Archethic.P2P.Message.UnspentOutputList alias Archethic.P2P.Message.TransactionList alias Archethic.P2P.Message.GetUnspentOutputs alias Archethic.P2P.Message.UnspentOutputList + alias Archethic.P2P.Message.NotFound alias Archethic.P2P.Node alias Archethic.Replication.TransactionContext alias Archethic.TransactionChain.Transaction @@ -22,25 +25,67 @@ defmodule Archethic.Replication.TransactionContextTest do import Mox - test "fetch_transaction/1 should retrieve the transaction" do - MockClient - |> stub(:send_message, fn _, %GetTransaction{}, _ -> - {:ok, %Transaction{}} - end) + describe "fetch_transaction/2" do + test "should retrieve the transaction" do + address = random_address() - P2P.add_and_connect_node(%Node{ - ip: {127, 0, 0, 1}, - port: 3000, - first_public_key: Crypto.last_node_public_key(), - last_public_key: Crypto.last_node_public_key(), - available?: true, - geo_patch: "AAA", - network_patch: "AAA", - authorized?: true, - authorization_date: DateTime.utc_now() - }) + MockClient + |> expect(:send_message, 3, fn _, %GetTransaction{}, _ -> + {:ok, %Transaction{address: address}} + end) + + connect_to_n_nodes(5) + + assert %Transaction{} = TransactionContext.fetch_transaction(address) + end + + test "should ask every node if acceptance_resolver is :accept_transaction" do + address = random_address() + + MockClient + |> expect(:send_message, 5, fn _, %GetTransaction{}, _ -> + # acceptance will fail + {:ok, %NotFound{}} + end) + + connect_to_n_nodes(5) - assert %Transaction{} = TransactionContext.fetch_transaction("@Alice1") + # no assert, we use expect(5) in the mock + TransactionContext.fetch_transaction(address, acceptance_resolver: :accept_transaction) + end + end + + describe "fetch_genesis_address/2" do + test "should retrieve the genesis" do + address = random_address() + genesis = random_address() + + MockClient + |> expect(:send_message, 3, fn _, %GetGenesisAddress{}, _ -> + {:ok, %GenesisAddress{address: genesis, timestamp: DateTime.utc_now()}} + end) + + connect_to_n_nodes(5) + + assert genesis == TransactionContext.fetch_genesis_address(address) + end + + test "should ask every node if acceptance_resolver is :accept_different_genesis" do + address = random_address() + + MockClient + |> expect(:send_message, 5, fn _, %GetGenesisAddress{}, _ -> + # acceptance will fail + {:ok, %GenesisAddress{address: address, timestamp: DateTime.utc_now()}} + end) + + connect_to_n_nodes(5) + + # no assert, we use expect(5) in the mock + TransactionContext.fetch_genesis_address(address, + acceptance_resolver: :accept_different_genesis + ) + end end describe "stream_transaction_chain/3" do @@ -199,4 +244,20 @@ defmodule Archethic.Replication.TransactionContextTest do assert [^v_utxo] = TransactionContext.fetch_transaction_unspent_outputs(genesis_address) end + + def connect_to_n_nodes(n) do + Enum.each(1..n, fn i -> + P2P.add_and_connect_node(%Node{ + ip: {127, 0, 0, 1}, + port: 3000 + i, + first_public_key: random_public_key(), + last_public_key: random_public_key(), + available?: true, + geo_patch: "AAA", + network_patch: "AAA", + authorized?: true, + authorization_date: DateTime.utc_now() + }) + end) + end end From 84cfaed06d477c414eff5a7492504c308bd5da23 Mon Sep 17 00:00:00 2001 From: bchamagne Date: Fri, 25 Oct 2024 10:47:26 +0200 Subject: [PATCH 2/2] add back search mode remote --- lib/archethic/self_repair.ex | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/archethic/self_repair.ex b/lib/archethic/self_repair.ex index 90c31f205..c93da4c6a 100755 --- a/lib/archethic/self_repair.ex +++ b/lib/archethic/self_repair.ex @@ -284,6 +284,7 @@ defmodule Archethic.SelfRepair do [ Task.async(fn -> TransactionChain.fetch_transaction(address, storage_nodes, + search_mode: :remote, timeout: timeout, acceptance_resolver: :accept_transaction )