Skip to content

Commit

Permalink
use the validation_time to discard responses on conflict
Browse files Browse the repository at this point in the history
  • Loading branch information
bchamagne authored and Neylix committed Apr 17, 2024
1 parent 6c6b7f1 commit 4e45e8b
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 51 deletions.
7 changes: 6 additions & 1 deletion lib/archethic/mining/smart_contract_validation.ex
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,12 @@ defmodule Archethic.Mining.SmartContractValidation do
|> Election.get_synchronized_nodes_before(previous_summary_time)

conflicts_resolver = fn results ->
Enum.sort_by(results, fn
%SmartContractCallValidation{last_chain_sync_date: highest_date} =
Enum.max_by(results, & &1.last_chain_sync_date, DateTime)

results
|> Enum.filter(&(&1.last_chain_sync_date == highest_date))
|> Enum.sort_by(fn
%SmartContractCallValidation{status: :ok} -> 1
%SmartContractCallValidation{status: {:error, :invalid_condition, _}} -> 2
%SmartContractCallValidation{status: {:error, :invalid_execution, _}} -> 3
Expand Down
134 changes: 85 additions & 49 deletions test/archethic/mining/smart_contract_validation_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,28 @@ defmodule Archethic.Mining.SmartContractValidationTest do
:send_message,
fn
_, %ValidateSmartContractCall{recipient: %Recipient{address: "@SC1"}}, _ ->
{:ok, %SmartContractCallValidation{status: :ok, fee: 123_456}}
{:ok,
%SmartContractCallValidation{
status: :ok,
fee: 123_456,
last_chain_sync_date: DateTime.utc_now()
}}

_, %ValidateSmartContractCall{recipient: %Recipient{address: "@SC2"}}, _ ->
{:ok, %SmartContractCallValidation{status: :ok, fee: 654_321}}
{:ok,
%SmartContractCallValidation{
status: :ok,
fee: 654_321,
last_chain_sync_date: DateTime.utc_now()
}}
end
)

node = %Node{
ip: "127.0.0.1",
port: 1234,
first_public_key: :crypto.strong_rand_bytes(32),
last_public_key: :crypto.strong_rand_bytes(32),
first_public_key: random_public_key(),
last_public_key: random_public_key(),
available?: true,
authorized?: true,
authorization_date: DateTime.utc_now(),
Expand All @@ -70,18 +80,27 @@ defmodule Archethic.Mining.SmartContractValidationTest do
fn
_, %ValidateSmartContractCall{recipient: %Recipient{address: "@SC1"}}, _ ->
{:ok,
%SmartContractCallValidation{status: {:error, :invalid_condition, "content"}, fee: 0}}
%SmartContractCallValidation{
status: {:error, :invalid_condition, "content"},
fee: 0,
last_chain_sync_date: DateTime.utc_now()
}}

_, %ValidateSmartContractCall{recipient: %Recipient{address: "@SC2"}}, _ ->
{:ok, %SmartContractCallValidation{status: :ok, fee: 0}}
{:ok,
%SmartContractCallValidation{
status: :ok,
fee: 0,
last_chain_sync_date: DateTime.utc_now()
}}
end
)

node = %Node{
ip: "127.0.0.1",
port: 1234,
first_public_key: :crypto.strong_rand_bytes(32),
last_public_key: :crypto.strong_rand_bytes(32),
first_public_key: random_public_key(),
last_public_key: random_public_key(),
available?: true,
authorized?: true,
authorization_date: DateTime.utc_now(),
Expand All @@ -105,28 +124,14 @@ defmodule Archethic.Mining.SmartContractValidationTest do
)
end

test "should resolve the conflict" do
MockClient
|> stub(
:send_message,
fn
%Node{port: 1234},
%ValidateSmartContractCall{recipient: %Recipient{address: "@SC1"}},
_ ->
{:ok, %SmartContractCallValidation{status: :ok, fee: 777_777}}

%Node{port: 1235},
%ValidateSmartContractCall{recipient: %Recipient{address: "@SC1"}},
_ ->
{:ok, %SmartContractCallValidation{status: :ok, fee: 123_456}}
end
)
test "should resolve the conflict (ok)" do
last_chain_sync_date = DateTime.utc_now()

node1 = %Node{
ip: "127.0.0.1",
port: 1234,
first_public_key: :crypto.strong_rand_bytes(32),
last_public_key: :crypto.strong_rand_bytes(32),
first_public_key: random_public_key(),
last_public_key: random_public_key(),
available?: true,
authorized?: true,
authorization_date: DateTime.utc_now(),
Expand All @@ -136,8 +141,8 @@ defmodule Archethic.Mining.SmartContractValidationTest do
node2 = %Node{
ip: "127.0.0.1",
port: 1235,
first_public_key: :crypto.strong_rand_bytes(32),
last_public_key: :crypto.strong_rand_bytes(32),
first_public_key: random_public_key(),
last_public_key: random_public_key(),
available?: true,
authorized?: true,
authorization_date: DateTime.utc_now(),
Expand All @@ -147,33 +152,42 @@ defmodule Archethic.Mining.SmartContractValidationTest do
P2P.add_and_connect_node(node1)
P2P.add_and_connect_node(node2)

assert {:ok, _} =
SmartContractValidation.validate_contract_calls(
[%Recipient{address: "@SC1"}],
%Transaction{},
DateTime.utc_now()
)
end

test "should return error if one smart contract is invalid" do
MockClient
|> stub(
:send_message,
fn
_, %ValidateSmartContractCall{recipient: %Recipient{address: "@SC1"}}, _ ->
^node1, %ValidateSmartContractCall{}, _ ->
{:ok,
%SmartContractCallValidation{status: {:error, :invalid_condition, "content"}, fee: 0}}
%SmartContractCallValidation{
status: :ok,
fee: 777_777,
last_chain_sync_date: last_chain_sync_date
}}

_, %ValidateSmartContractCall{recipient: %Recipient{address: "@SC2"}}, _ ->
{:ok, %SmartContractCallValidation{status: :ok, fee: 123_456}}
^node2, %ValidateSmartContractCall{}, _ ->
{:ok,
%SmartContractCallValidation{
status: {:error, :transaction_not_exists},
fee: 0,
last_chain_sync_date: last_chain_sync_date
}}
end
)

assert {:ok, _} =
SmartContractValidation.validate_contract_calls(
[%Recipient{address: random_address()}],
%Transaction{},
DateTime.utc_now()
)
end

test "should resolve the conflict (last_chain_sync_date)" do
node1 = %Node{
ip: "127.0.0.1",
port: 1234,
first_public_key: :crypto.strong_rand_bytes(32),
last_public_key: :crypto.strong_rand_bytes(32),
first_public_key: random_public_key(),
last_public_key: random_public_key(),
available?: true,
authorized?: true,
authorization_date: DateTime.utc_now(),
Expand All @@ -183,8 +197,8 @@ defmodule Archethic.Mining.SmartContractValidationTest do
node2 = %Node{
ip: "127.0.0.1",
port: 1235,
first_public_key: :crypto.strong_rand_bytes(32),
last_public_key: :crypto.strong_rand_bytes(32),
first_public_key: random_public_key(),
last_public_key: random_public_key(),
available?: true,
authorized?: true,
authorization_date: DateTime.utc_now(),
Expand All @@ -194,9 +208,31 @@ defmodule Archethic.Mining.SmartContractValidationTest do
P2P.add_and_connect_node(node1)
P2P.add_and_connect_node(node2)

assert {:error, %Error{data: %{"message" => "Invalid condition on content"}}} =
MockClient
|> stub(
:send_message,
fn
^node1, %ValidateSmartContractCall{}, _ ->
{:ok,
%SmartContractCallValidation{
status: :ok,
fee: 777_777,
last_chain_sync_date: ~U[2024-04-10 00:00:00Z]
}}

^node2, %ValidateSmartContractCall{}, _ ->
{:ok,
%SmartContractCallValidation{
status: {:error, :invalid_condition, "content"},
fee: 0,
last_chain_sync_date: ~U[2024-04-09 00:00:00Z]
}}
end
)

assert {:ok, _} =
SmartContractValidation.validate_contract_calls(
[%Recipient{address: "@SC1"}, %Recipient{address: "@SC2"}],
[%Recipient{address: random_address()}],
%Transaction{},
DateTime.utc_now()
)
Expand All @@ -208,8 +244,8 @@ defmodule Archethic.Mining.SmartContractValidationTest do
P2P.add_and_connect_node(%Node{
ip: {127, 0, 0, 1},
port: 3000,
first_public_key: ArchethicCase.random_public_key(),
last_public_key: ArchethicCase.random_public_key(),
first_public_key: random_public_key(),
last_public_key: random_public_key(),
network_patch: "AAA",
geo_patch: "AAA",
available?: true,
Expand Down
6 changes: 5 additions & 1 deletion test/archethic/replication/transaction_validator_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,11 @@ defmodule Archethic.Replication.TransactionValidatorTest do
end)
|> expect(:send_message, fn _, %ValidateSmartContractCall{}, _ ->
{:ok,
%SmartContractCallValidation{status: {:error, :invalid_condition, "content"}, fee: 0}}
%SmartContractCallValidation{
status: {:error, :invalid_condition, "content"},
fee: 0,
last_chain_sync_date: DateTime.utc_now()
}}
end)
|> expect(:send_message, fn _, %GetGenesisAddress{address: ^recipient_address}, _ ->
{:ok, %GenesisAddress{address: recipient_genesis, timestamp: DateTime.utc_now()}}
Expand Down

0 comments on commit 4e45e8b

Please sign in to comment.