Skip to content

Commit

Permalink
Check if transaction already during transaction validation
Browse files Browse the repository at this point in the history
  • Loading branch information
samuelmanzanera committed Nov 17, 2022
1 parent 5466387 commit 94db819
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 8 deletions.
34 changes: 32 additions & 2 deletions lib/archethic/mining/pending_transaction_validation.ex
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ defmodule Archethic.Mining.PendingTransactionValidation do
P2P,
P2P.Message.FirstPublicKey,
P2P.Message.GetFirstPublicKey,
P2P.Message.GetTransactionSummary,
P2P.Message.NotFound,
P2P.Node,
Reward,
SharedSecrets.NodeRenewal,
Expand All @@ -26,7 +28,8 @@ defmodule Archethic.Mining.PendingTransactionValidation do
TransactionData,
TransactionData.Ledger,
TransactionData.Ownership,
TransactionData.TokenLedger
TransactionData.TokenLedger,
TransactionSummary
}

alias Archethic.Governance.Code.Proposal, as: CodeProposal
Expand All @@ -44,7 +47,8 @@ defmodule Archethic.Mining.PendingTransactionValidation do
) do
start = System.monotonic_time()

with true <- Transaction.verify_previous_signature?(tx),
with :ok <- valid_not_exists(tx),
:ok <- valid_previous_signature(tx),
:ok <- validate_contract(tx),
:ok <- validate_content_size(tx),
:ok <- do_accept_transaction(tx, validation_time),
Expand Down Expand Up @@ -79,6 +83,32 @@ defmodule Archethic.Mining.PendingTransactionValidation do
end
end

defp valid_not_exists(%Transaction{address: address}) do
storage_nodes = Election.chain_storage_nodes(address, P2P.authorized_and_available_nodes())

case P2P.quorum_read(
storage_nodes,
%GetTransactionSummary{address: address}
) do
{:ok, %TransactionSummary{address: ^address}} ->
{:error, "transaction already exists"}

{:ok, %NotFound{}} ->
:ok

{:error, _} = e ->
e
end
end

defp valid_previous_signature(tx = %Transaction{}) do
if Transaction.verify_previous_signature?(tx) do
:ok
else
{:error, "Invalid previous signature"}
end
end

def validate_previous_transaction_type?(tx) do
case Transaction.network_type?(tx.type) do
false ->
Expand Down
27 changes: 21 additions & 6 deletions test/archethic/mining/pending_transaction_validation_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ defmodule Archethic.Mining.PendingTransactionValidationTest do
alias Archethic.P2P
alias Archethic.P2P.Message.FirstPublicKey
alias Archethic.P2P.Message.GetFirstPublicKey
alias Archethic.P2P.Message.GetTransactionSummary
alias Archethic.P2P.Message.NotFound
alias Archethic.P2P.Node

alias Archethic.TransactionChain.Transaction
Expand All @@ -28,9 +30,18 @@ defmodule Archethic.Mining.PendingTransactionValidationTest do
setup do
P2P.add_and_connect_node(%Node{
first_public_key: Crypto.last_node_public_key(),
network_patch: "AAA"
network_patch: "AAA",
available?: true,
authorized?: true,
authorization_date: DateTime.utc_now(),
geo_patch: "AAA"
})

MockClient
|> stub(:send_message, fn _, %GetTransactionSummary{}, _ ->
{:ok, %NotFound{}}
end)

on_exit(fn ->
Application.put_env(:archethic, Archethic.Mining.PendingTransactionValidation,
allowed_node_key_origins: []
Expand Down Expand Up @@ -409,8 +420,12 @@ defmodule Archethic.Mining.PendingTransactionValidationTest do
end)

MockClient
|> expect(:send_message, fn _, %GetFirstPublicKey{}, _ ->
{:ok, %FirstPublicKey{public_key: tx.previous_public_key}}
|> stub(:send_message, fn
_, %GetFirstPublicKey{}, _ ->
{:ok, %FirstPublicKey{public_key: tx.previous_public_key}}

_, %GetTransactionSummary{}, _ ->
{:ok, %NotFound{}}
end)

assert :ok = PendingTransactionValidation.validate(tx)
Expand Down Expand Up @@ -492,7 +507,7 @@ defmodule Archethic.Mining.PendingTransactionValidationTest do

send(pid, :node_up)

assert {:idle, %{interval: "0 * * * * *"}} = :sys.get_state(pid)
assert {:scheduled, %{interval: "0 * * * * *"}} = :sys.get_state(pid)

MockDB
|> stub(:get_latest_burned_fees, fn -> 300_000_000 end)
Expand Down Expand Up @@ -533,7 +548,7 @@ defmodule Archethic.Mining.PendingTransactionValidationTest do

send(pid, :node_up)

assert {:idle, %{interval: "0 * * * * *"}} = :sys.get_state(pid)
assert {:scheduled, %{interval: "0 * * * * *"}} = :sys.get_state(pid)

MockDB
|> stub(:get_latest_burned_fees, fn -> 200_000_000 end)
Expand Down Expand Up @@ -573,7 +588,7 @@ defmodule Archethic.Mining.PendingTransactionValidationTest do

send(pid, :node_up)

assert {:idle, %{interval: "0 * * * * *"}} = :sys.get_state(pid)
assert {:scheduled, %{interval: "0 * * * * *"}} = :sys.get_state(pid)

MockDB
|> stub(:get_latest_burned_fees, fn -> 300_000_000 end)
Expand Down

0 comments on commit 94db819

Please sign in to comment.