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 committed Apr 10, 2024
1 parent ccce421 commit f20dcab
Show file tree
Hide file tree
Showing 4 changed files with 196 additions and 99 deletions.
84 changes: 39 additions & 45 deletions lib/archethic/mining/smart_contract_validation.ex
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ defmodule Archethic.Mining.SmartContractValidation do
|> Election.get_synchronized_nodes_before(previous_summary_time)

conflicts_resolver = fn results ->
Enum.reduce(results, &priorize/2)
Enum.reduce(results, &resolve_conflict/2)
end

case P2P.quorum_read(
Expand Down Expand Up @@ -388,49 +388,43 @@ defmodule Archethic.Mining.SmartContractValidation do
do:
{:error, Error.new(:invalid_contract_execution, "Contract should not output a transaction")}

@doc """
Priorize validation call
## Examples
iex> SmartContractValidation.priorize(%SmartContractCallValidation{status: {:error, :transaction_not_exists}}, %SmartContractCallValidation{status: :ok})
%SmartContractCallValidation{status: :ok}
iex> SmartContractValidation.priorize(%SmartContractCallValidation{status: :ok}, %SmartContractCallValidation{status: {:error, :transaction_not_exists}})
%SmartContractCallValidation{status: :ok}
iex> SmartContractValidation.priorize(%SmartContractCallValidation{status: {:error, :invalid_execution, nil}}, %SmartContractCallValidation{status: {:error, :transaction_not_exists}})
%SmartContractCallValidation{status: {:error, :invalid_execution, nil}}
iex> SmartContractValidation.priorize(%SmartContractCallValidation{status: {:error, :transaction_not_exists}}, %SmartContractCallValidation{status: {:error, :invalid_execution, nil}})
%SmartContractCallValidation{status: {:error, :invalid_execution, nil}}
iex> SmartContractValidation.priorize(%SmartContractCallValidation{status: :ok}, %SmartContractCallValidation{status: {:error, :invalid_execution, nil}})
%SmartContractCallValidation{status: {:error, :invalid_execution, nil}}
# conflict resolution rules:
# validation_time > invalid_execution > ok > transaction_not_exists
defp resolve_conflict(
a = %SmartContractCallValidation{latest_validation_time: latest_validation_time_a},
b = %SmartContractCallValidation{latest_validation_time: latest_validation_time_b}
)
when latest_validation_time_a != latest_validation_time_b do
if DateTime.compare(latest_validation_time_a, latest_validation_time_b) == :gt do
a
else
b
end
end

iex> SmartContractValidation.priorize(%SmartContractCallValidation{status: {:error, :invalid_execution, nil}}, %SmartContractCallValidation{status: :ok})
%SmartContractCallValidation{status: {:error, :invalid_execution, nil}}
"""
@spec priorize(SmartContractCallValidation.t(), SmartContractCallValidation.t()) ::
SmartContractCallValidation.t()
def priorize(a = %SmartContractCallValidation{status: :ok}, %SmartContractCallValidation{
status: {:error, :transaction_not_exists}
}),
do: a

def priorize(
%SmartContractCallValidation{status: {:error, :transaction_not_exists}},
b = _
),
do: b

def priorize(a = %SmartContractCallValidation{status: {:error, _, _}}, _), do: a

def priorize(
%SmartContractCallValidation{status: :ok},
b = %SmartContractCallValidation{status: {:error, _, _}}
),
do: b

def priorize(a, _), do: a
defp resolve_conflict(
a,
%SmartContractCallValidation{status: {:error, :transaction_not_exists}}
),
do: a

defp resolve_conflict(
%SmartContractCallValidation{status: {:error, :transaction_not_exists}},
b
),
do: b

defp resolve_conflict(
a = %SmartContractCallValidation{status: {:error, _, _}},
_
),
do: a

defp resolve_conflict(
_,
b = %SmartContractCallValidation{status: {:error, _, _}}
),
do: b

defp resolve_conflict(a, _), do: a
end
Loading

0 comments on commit f20dcab

Please sign in to comment.