From d0fda0cca5adaf31a283eda5442fd99dc7abb4ec Mon Sep 17 00:00:00 2001 From: apoorv-2204 Date: Tue, 14 Mar 2023 13:10:58 +0530 Subject: [PATCH] Infinite looping in forward transaction #931 --- lib/archethic.ex | 14 +++--- test/archethic_test.exs | 94 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 101 insertions(+), 7 deletions(-) diff --git a/lib/archethic.ex b/lib/archethic.ex index 6621cf98ef..5da4729632 100644 --- a/lib/archethic.ex +++ b/lib/archethic.ex @@ -83,12 +83,16 @@ defmodule Archethic do ) defp forward_transaction(tx, welcome_node_key, [node | rest]) do - case P2P.send_message(node, %NewTransaction{transaction: tx, welcome_node: welcome_node_key}) do - {:ok, %Ok{}} -> - :ok + if node.first_public_key == welcome_node_key do + forward_transaction(tx, welcome_node_key, rest) + else + case P2P.send_message(node, %NewTransaction{transaction: tx, welcome_node: welcome_node_key}) do + {:ok, %Ok{}} -> + :ok - {:error, _} -> - forward_transaction(tx, welcome_node_key, rest) + {:error, _} -> + forward_transaction(tx, welcome_node_key, rest) + end end end diff --git a/test/archethic_test.exs b/test/archethic_test.exs index 16ca42d648..ceaac45392 100644 --- a/test/archethic_test.exs +++ b/test/archethic_test.exs @@ -58,7 +58,7 @@ defmodule ArchethicTest do assert :ok = Archethic.send_new_transaction(tx) end - test "When NOT synced should forward the tx and start repair " do + test "should return error when node not synced,and try to forward the tx to itself " do nss_genesis_address = "nss_genesis_address" nss_last_address = "nss_last_address" :persistent_term.put(:node_shared_secrets_gen_addr, nss_genesis_address) @@ -101,7 +101,7 @@ defmodule ArchethicTest do ) MockClient - |> expect(:send_message, 4, fn + |> expect(:send_message, 3, fn # validate nss chain from network # anticippated to be failed _, %GetLastTransactionAddress{}, _ -> @@ -121,6 +121,96 @@ defmodule ArchethicTest do # last address is d/f it returns last address from quorum assert {:error, "willnotmatchaddress"} = SharedSecrets.verify_synchronization() + # trying to ssend a tx when NSS chain not synced + tx = Transaction.new(:transfer, %TransactionData{}, "seed", 0) + assert {:error, :network_issue} = Archethic.send_new_transaction(tx) + + # start repair and should bottleneck requests + pid = SelfRepair.repair_in_progress?(nss_genesis_address) + Process.sleep(150) + assert pid != nil + end + + test "should forward tx to other nodes " do + nss_genesis_address = "nss_genesis_address" + nss_last_address = "nss_last_address" + :persistent_term.put(:node_shared_secrets_gen_addr, nss_genesis_address) + first_pb_key = Crypto.first_node_public_key() + + P2P.add_and_connect_node(%Node{ + ip: {127, 0, 0, 1}, + port: 3000, + first_public_key: Crypto.first_node_public_key(), + last_public_key: Crypto.first_node_public_key(), + network_patch: "AAA", + geo_patch: "AAA", + available?: true, + authorized?: true, + authorization_date: DateTime.utc_now() |> DateTime.add(-20_000) + }) + + node2_fpbk = "node2" + + P2P.add_and_connect_node(%Node{ + ip: {127, 0, 0, 1}, + port: 3000, + first_public_key: node2_fpbk, + last_public_key: node2_fpbk, + network_patch: "AAA", + geo_patch: "AAA", + available?: true, + authorized?: true, + authorization_date: DateTime.utc_now() |> DateTime.add(-20_000) + }) + + start_supervised!({SummaryTimer, Application.get_env(:archethic, SummaryTimer)}) + + MockDB + |> stub(:get_last_chain_address, fn ^nss_genesis_address -> + {nss_last_address, DateTime.utc_now()} + end) + |> stub( + :get_transaction, + fn + ^nss_last_address, [validation_stamp: [:timestamp]], :chain -> + {:ok, + %Transaction{ + validation_stamp: %{ + __struct__: :ValidationStamp, + # fail mathematical check with irregular timestamp + # causes validate_scheduling_time() to fail + timestamp: DateTime.utc_now() |> DateTime.add(-86_400) + } + }} + + _, _, _ -> + {:error, :transaction_not_exists} + end + ) + + MockClient + |> expect(:send_message, 5, fn + # validate nss chain from network + # anticippated to be failed + _, %GetLastTransactionAddress{}, _ -> + {:ok, %LastTransactionAddress{address: "willnotmatchaddress"}} + + %Node{first_public_key: ^node2_fpbk}, + %NewTransaction{transaction: _, welcome_node: ^first_pb_key}, + _ -> + # forward the tx + {:ok, %Ok{}} + + _, %GetTransaction{address: _}, _ -> + {:ok, %NotFound{}} + + _, _, _ -> + {:ok, %Ok{}} + end) + + # last address is d/f it returns last address from quorum + assert {:error, "willnotmatchaddress"} = SharedSecrets.verify_synchronization() + # trying to ssend a tx when NSS chain not synced tx = Transaction.new(:transfer, %TransactionData{}, "seed", 0) assert :ok = Archethic.send_new_transaction(tx)