Skip to content

Commit

Permalink
Augment Message.NewTransaction with a welcome node key
Browse files Browse the repository at this point in the history
  • Loading branch information
apoorv-2204 committed Mar 2, 2023
1 parent 014ceee commit 5f449df
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 31 deletions.
15 changes: 8 additions & 7 deletions lib/archethic.ex
Original file line number Diff line number Diff line change
Expand Up @@ -61,36 +61,37 @@ defmodule Archethic do
do_send_transaction(tx, welcome_node_key)

{:error, :node_out_of_sync} ->
forward_transaction(tx)
forward_transaction(tx, welcome_node_key)

{:error, last_address_to_sync} ->
Resync.node_out_of_sync(last_address_to_sync)
forward_transaction(tx)
forward_transaction(tx, welcome_node_key)
end
else
# node not authorized
forward_transaction(tx)
forward_transaction(tx, welcome_node_key)
end
end

defp forward_transaction(
tx,
welcome_node_key,
nodes \\ P2P.authorized_and_available_nodes()
|> Enum.filter(&Node.locally_available?/1)
|> P2P.nearest_nodes()
)

defp forward_transaction(tx, [node | rest]) do
case P2P.send_message(node, %NewTransaction{transaction: tx}) 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

{:error, _} ->
forward_transaction(tx, rest)
forward_transaction(tx, welcome_node_key, rest)
end
end

defp forward_transaction(_, []), do: {:error, :network_issue}
defp forward_transaction(_, _, []), do: {:error, :network_issue}

defp do_send_transaction(tx = %Transaction{type: tx_type}, welcome_node_key) do
current_date = DateTime.utc_now()
Expand Down
5 changes: 4 additions & 1 deletion lib/archethic/bootstrap/transaction_handler.ex
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@ defmodule Archethic.Bootstrap.TransactionHandler do
@spec do_send_transaction(list(Node.t()), Transaction.t()) ::
:ok
defp do_send_transaction([node | rest], tx) do
case P2P.send_message(node, %NewTransaction{transaction: tx}) do
case P2P.send_message(node, %NewTransaction{
transaction: tx,
welcome_node: node.first_public_key
}) do
{:ok, %Ok{}} ->
Logger.info("Waiting transaction validation",
transaction_address: Base.encode16(tx.address),
Expand Down
23 changes: 12 additions & 11 deletions lib/archethic/p2p/message/new_transaction.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,20 @@ defmodule Archethic.P2P.Message.NewTransaction do
This message is used locally within a node during the bootstrap
"""
defstruct [:transaction]
@enforce_keys [:transaction, :welcome_node]
defstruct [:transaction, :welcome_node]

alias Archethic.TransactionChain.Transaction
alias Archethic.P2P.Message.Ok
alias Archethic.P2P.Message.Error
alias Archethic.Crypto
alias Archethic.{TransactionChain.Transaction, Crypto, Utils, P2P.Message}
alias Message.{Ok, Error}

@type t :: %__MODULE__{
transaction: Transaction.t()
transaction: Transaction.t(),
welcome_node: Crypto.key()
}

@spec process(__MODULE__.t(), Crypto.key()) :: Ok.t() | Error.t()
def process(%__MODULE__{transaction: tx}, sender_public_key) do
case Archethic.send_new_transaction(tx, sender_public_key) do
def process(%__MODULE__{transaction: tx, welcome_node: node_pbkey}, _) do
case Archethic.send_new_transaction(tx, node_pbkey) do
:ok ->
%Ok{}

Expand All @@ -27,13 +27,14 @@ defmodule Archethic.P2P.Message.NewTransaction do
end

@spec serialize(t()) :: bitstring()
def serialize(%__MODULE__{transaction: tx}) do
<<Transaction.serialize(tx)::bitstring>>
def serialize(%__MODULE__{transaction: tx, welcome_node: node_pbkey}) do
<<Transaction.serialize(tx)::bitstring, node_pbkey::binary>>
end

@spec deserialize(bitstring()) :: {t(), bitstring}
def deserialize(<<rest::bitstring>>) do
{tx, rest} = Transaction.deserialize(rest)
{%__MODULE__{transaction: tx}, rest}
{node_pbkey, rest} = Utils.deserialize_public_key(rest)
{%__MODULE__{transaction: tx, welcome_node: node_pbkey}, rest}
end
end
4 changes: 2 additions & 2 deletions test/archethic/p2p/messages_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,8 @@ defmodule Archethic.P2P.MessageTest do
test "NewTransaction message" do
tx = Transaction.new(:transfer, %TransactionData{}, "seed", 0)

assert %NewTransaction{transaction: tx} ==
%NewTransaction{transaction: tx}
assert %NewTransaction{transaction: tx, welcome_node: Crypto.first_node_public_key()} ==
%NewTransaction{transaction: tx, welcome_node: Crypto.first_node_public_key()}
|> Message.encode()
|> Message.decode()
|> elem(0)
Expand Down
30 changes: 20 additions & 10 deletions test/archethic_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,11 @@ defmodule ArchethicTest do
assert :ok = Archethic.send_new_transaction(tx)
end

test "When NOT synced should forward the tx, start repair " do
test "When NOT synced should forward the tx and start repair " do
nss_genesis_address = "nss_genesis_address"
nss_last_address = "nss_last_address"
:persistent_term.put(:node_shared_secrets_gen_addr, nss_genesis_address)

P2P.add_and_connect_node(%Node{
ip: {127, 0, 0, 1},
port: 3000,
Expand All @@ -94,9 +98,6 @@ defmodule ArchethicTest do

start_supervised!({SummaryTimer, Application.get_env(:archethic, SummaryTimer)})

nss_genesis_address = "nss_genesis_address"
nss_last_address = "nss_last_address"

MockDB
|> stub(:get_last_chain_address, fn ^nss_genesis_address ->
{nss_last_address, DateTime.utc_now()}
Expand All @@ -109,7 +110,8 @@ defmodule ArchethicTest do
%Transaction{
validation_stamp: %{
__struct__: :ValidationStamp,
# fail mathematical ccheck with irregular timestamp
# fail mathematical check with irregular timestamp
# causes validate_scheduling_time() to fail
timestamp: DateTime.utc_now() |> DateTime.add(-86_400)
}
}}
Expand All @@ -120,26 +122,34 @@ defmodule ArchethicTest do
)

MockClient
|> expect(:send_message, 3, fn
|> expect(:send_message, 4, fn
# validate nss chain from network
# anticippated to be failed
_, %GetLastTransactionAddress{}, _ ->
{:ok, %LastTransactionAddress{address: "willnotmatchaddress"}}

_, %NewTransaction{}, _ ->
_, %NewTransaction{transaction: _, welcome_node: _}, _ ->
# forward the tx
{:ok, %Ok{}}

_, %GetTransaction{address: _}, _ ->
{:ok, %NotFound{}}

_, _, _ ->
{:ok, %Ok{}}
end)

tx = Transaction.new(:transfer, %TransactionData{}, "seed", 0)
# last address is d/f it returns last address from quorum
assert {:error, "willnotmatchaddress"} = P2P.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)

# start repair and should bottleneck requests
pid = SelfRepair.repair_in_progress?(nss_genesis_address)
Process.sleep(50)
assert pid != false
Process.sleep(150)
assert pid != nil
end
end

Expand Down

0 comments on commit 5f449df

Please sign in to comment.