Skip to content

Commit

Permalink
Update interpreters
Browse files Browse the repository at this point in the history
  • Loading branch information
samuelmanzanera committed Nov 24, 2022
1 parent e7e4187 commit 12c09b0
Show file tree
Hide file tree
Showing 21 changed files with 1,329 additions and 2,264 deletions.
38 changes: 18 additions & 20 deletions lib/archethic/contracts.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ defmodule Archethic.Contracts do
"""

alias __MODULE__.Contract
alias __MODULE__.Contract.Conditions
alias __MODULE__.Contract.Constants
alias __MODULE__.Contract.Trigger
alias __MODULE__.ContractConditions, as: Conditions
alias __MODULE__.ContractConstants, as: Constants
alias __MODULE__.ConditionInterpreter
alias __MODULE__.Interpreter
alias __MODULE__.Loader
alias __MODULE__.TransactionLookup
Expand Down Expand Up @@ -59,9 +59,8 @@ defmodule Archethic.Contracts do
contract: nil,
transaction: nil
},
triggers: [
%Trigger{
actions: {:__block__, [], [
triggers: %{
{:datetime, ~U[2020-09-25 13:18:43Z]} => {:__block__, [], [
{
:=,
[line: 7],
Expand All @@ -79,11 +78,9 @@ defmodule Archethic.Contracts do
]
}
]},
opts: [at: ~U[2020-09-25 13:18:43Z]],
type: :datetime
}
]
}}
}
}
"""
@spec parse(binary()) :: {:ok, Contract.t()} | {:error, binary()}
def parse(contract_code) when is_binary(contract_code) do
Expand All @@ -100,11 +97,10 @@ defmodule Archethic.Contracts do
})

cond do
Enum.any?(triggers, &(&1.type == :transaction)) and
Conditions.empty?(transaction_conditions) ->
Map.has_key?(triggers, :transaction) and Conditions.empty?(transaction_conditions) ->
{:error, "missing transaction conditions"}

Enum.any?(triggers, &(&1.type == :oracle)) and Conditions.empty?(oracle_conditions) ->
Map.has_key?(triggers, :oracle) and Conditions.empty?(oracle_conditions) ->
{:error, "missing oracle conditions"}

true ->
Expand Down Expand Up @@ -168,18 +164,20 @@ defmodule Archethic.Contracts do
end

defp validate_conditions(inherit_conditions, constants) do
if Interpreter.valid_conditions?(inherit_conditions, constants) do
if ConditionInterpreter.valid_conditions?(inherit_conditions, constants) do
:ok
else
Logger.error("Inherit constraints not respected")
{:error, :invalid_inherit_constraints}
end
end

defp validate_triggers([], _, _), do: :ok
defp validate_triggers(triggers, _next_tx, _date) when map_size(triggers) == 0, do: :ok

defp validate_triggers(triggers, next_tx, date) do
if Enum.any?(triggers, &valid_from_trigger?(&1, next_tx, date)) do
if Enum.any?(triggers, fn {trigger_type, _} ->
valid_from_trigger?(trigger_type, next_tx, date)
end) do
:ok
else
Logger.error("Transaction not processed by a valid smart contract trigger")
Expand All @@ -188,7 +186,7 @@ defmodule Archethic.Contracts do
end

defp valid_from_trigger?(
%Trigger{type: :datetime, opts: [at: datetime]},
{:datetime, datetime},
%Transaction{},
validation_date = %DateTime{}
) do
Expand All @@ -198,16 +196,16 @@ defmodule Archethic.Contracts do
end

defp valid_from_trigger?(
%Trigger{type: :interval, opts: [at: interval]},
{:interval, interval},
%Transaction{},
validation_date = %DateTime{}
) do
interval
|> CronParser.parse!(true)
|> CronParser.parse!()
|> CronDateChecker.matches_date?(DateTime.to_naive(validation_date))
end

defp valid_from_trigger?(%Trigger{type: :transaction}, _, _), do: true
defp valid_from_trigger?(_, _, _), do: true

@doc """
List the address of the transaction which has contacted a smart contract
Expand Down
54 changes: 16 additions & 38 deletions lib/archethic/contracts/contract.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@ defmodule Archethic.Contracts.Contract do
Represents a smart contract
"""

alias Archethic.Contracts.Contract.Conditions
alias Archethic.Contracts.Contract.Constants
alias Archethic.Contracts.Contract.Trigger
alias Archethic.Contracts.ContractConditions, as: Conditions
alias Archethic.Contracts.ContractConstants, as: Constants

alias Archethic.Contracts.Interpreter

Expand All @@ -14,7 +13,7 @@ defmodule Archethic.Contracts.Contract do
alias Archethic.TransactionChain.Transaction
alias Archethic.TransactionChain.TransactionData

defstruct triggers: [],
defstruct triggers: %{},
conditions: %{
transaction: %Conditions{},
inherit: %Conditions{},
Expand All @@ -23,12 +22,15 @@ defmodule Archethic.Contracts.Contract do
constants: %Constants{},
next_transaction: %Transaction{data: %TransactionData{}}

@type trigger_type() :: :datetime | :interval | :transaction
@type trigger_type() ::
{:datetime, DateTime.t()} | {:interval, String.t()} | :transaction | :oracle
@type condition() :: :transaction | :inherit | :oracle
@type origin_family :: SharedSecrets.origin_family()

@type t() :: %__MODULE__{
triggers: list(Trigger.t()),
triggers: %{
trigger_type() => Macro.t()
},
conditions: %{
transaction: Conditions.t(),
inherit: Conditions.t(),
Expand All @@ -55,48 +57,24 @@ defmodule Archethic.Contracts.Contract do
@doc """
Add a trigger to the contract
"""
@spec add_trigger(t(), Trigger.type(), Keyword.t(), Macro.t()) :: t()
@spec add_trigger(t(), trigger_type(), Macro.t()) :: t()
def add_trigger(
contract = %__MODULE__{},
:datetime,
opts = [at: _datetime = %DateTime{}],
type,
actions
) do
do_add_trigger(contract, %Trigger{type: :datetime, opts: opts, actions: actions})
end

def add_trigger(
contract = %__MODULE__{},
:interval,
opts = [at: interval],
actions
)
when is_binary(interval) do
do_add_trigger(contract, %Trigger{type: :interval, opts: opts, actions: actions})
end

def add_trigger(contract = %__MODULE__{}, :transaction, _, actions) do
do_add_trigger(contract, %Trigger{type: :transaction, actions: actions})
end

def add_trigger(contract = %__MODULE__{}, :oracle, _, actions) do
do_add_trigger(contract, %Trigger{type: :oracle, actions: actions})
end

defp do_add_trigger(contract, trigger = %Trigger{}) do
Map.update!(contract, :triggers, &(&1 ++ [trigger]))
Map.update!(contract, :triggers, &Map.put(&1, type, actions))
end

@doc """
Add a condition to the contract
"""
@spec add_condition(t(), condition(), any()) :: t()
@spec add_condition(t(), condition(), Conditions.t()) :: t()
def add_condition(
contract = %__MODULE__{conditions: conditions},
contract = %__MODULE__{},
condition_name,
condition
)
when condition_name in [:transaction, :inherit, :oracle] do
%{contract | conditions: Map.put(conditions, condition_name, condition)}
conditions = %Conditions{}
) do
Map.update!(contract, :conditions, &Map.put(&1, condition_name, conditions))
end
end
5 changes: 4 additions & 1 deletion lib/archethic/contracts/contract/conditions.ex
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
defmodule Archethic.Contracts.Contract.Conditions do
defmodule Archethic.Contracts.ContractConditions do
@moduledoc """
Represents the smart contract conditions
"""

defstruct [
:address,
:type,
:content,
:code,
Expand All @@ -20,6 +21,7 @@ defmodule Archethic.Contracts.Contract.Conditions do
alias Archethic.TransactionChain.Transaction

@type t :: %__MODULE__{
address: binary() | Macro.t() | nil,
type: Transaction.transaction_type() | nil,
content: binary() | Macro.t() | nil,
code: binary() | Macro.t() | nil,
Expand All @@ -33,6 +35,7 @@ defmodule Archethic.Contracts.Contract.Conditions do
}

def empty?(%__MODULE__{
address: nil,
type: nil,
content: nil,
code: nil,
Expand Down
4 changes: 2 additions & 2 deletions lib/archethic/contracts/contract/constants.ex
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
defmodule Archethic.Contracts.Contract.Constants do
defmodule Archethic.Contracts.ContractConstants do
@moduledoc """
Represents the smart contract constants and bindings
"""

defstruct [:contract, :transaction]

@type t :: %__MODULE__{
contract: map(),
contract: map() | nil,
transaction: map() | nil
}

Expand Down
19 changes: 0 additions & 19 deletions lib/archethic/contracts/contract/trigger.ex

This file was deleted.

Loading

0 comments on commit 12c09b0

Please sign in to comment.