Skip to content

Commit

Permalink
support wasm onInherit
Browse files Browse the repository at this point in the history
  • Loading branch information
samuelmanzanera committed Sep 17, 2024
1 parent 488517b commit a010199
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 19 deletions.
92 changes: 76 additions & 16 deletions lib/archethic/contracts.ex
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,13 @@ defmodule Archethic.Contracts do

upgrade_state =
if "onUpgrade" in WasmModule.list_exported_functions_name(new_module) do
{:ok, %UpdateResult{state: migrated_state}} =
WasmModule.execute(new_module, "onUpgrade", state: state)
case WasmModule.execute(new_module, "onUpgrade", state: state) do
{:ok, %UpdateResult{state: migrated_state}} ->
migrated_state

migrated_state
_ ->
state
end
else
state
end
Expand Down Expand Up @@ -352,6 +355,16 @@ defmodule Archethic.Contracts do
end
end

defp cast_trigger_result({:ok, nil}, _, _),
do:
{:error,
%Failure{
logs: [],
error: :invalid_trigger_output,
stacktrace: [],
user_friendly_error: "Trigger must return either a new transaction or a new state"
}}

defp cast_trigger_result(err = {:error, %Failure{}}, _, _), do: err

defp cast_trigger_result({:error, :trigger_not_exists}, _, _) do
Expand Down Expand Up @@ -447,14 +460,24 @@ defmodule Archethic.Contracts do
nil
end

{:ok, %ReadResult{value: value}} =
WasmModule.execute(module, function_name,
state: state,
balance: UTXO.get_balance(inputs),
arguments: arguments
)
case WasmModule.execute(module, function_name,
state: state,
balance: UTXO.get_balance(inputs),
arguments: arguments
) do
{:ok, %ReadResult{value: value}} ->
{:ok, value, []}

{:ok, value, []}
{:ok, nil} ->
{:ok, nil, []}

{:error, reason} ->
{:error,
%Failure{
user_friendly_error: "#{inspect(reason)}",
error: :invalid_function_call
}}
end
end
end

Expand Down Expand Up @@ -616,15 +639,52 @@ defmodule Archethic.Contracts do
)

def execute_condition(
_condition_key,
_contract = %WasmContract{},
_transaction = %Transaction{},
:inherit,
%WasmContract{module: module},
transaction = %Transaction{
validation_stamp: %ValidationStamp{
ledger_operations: %LedgerOperations{
unspent_outputs: next_unspent_outputs
}
}
},
_maybe_recipient,
_datetime,
_inputs,
inputs,
_opts
),
do: {:ok, []}
) do
if "onInherit" in WasmModule.list_exported_functions_name(module) do
next_state =
case Enum.find(next_unspent_outputs, &(&1.type == :state)) do
nil ->
%{}

%UnspentOutput{encoded_payload: encoded_payload} ->
{state, _} = State.deserialize(encoded_payload)
state
end

case WasmModule.execute(module, "onInherit",
state: next_state,
balance: UTXO.get_balance(inputs),
transaction: transaction
) do
{:ok, _} ->
{:ok, []}

{:error, reason} ->
{:error,
%Failure{
error: :invalid_inherit_condition,
user_friendly_error: "#{inspect(reason)}",
logs: [],
stacktrace: []
}}
end
else
{:ok, []}
end
end

def execute_condition(
condition_key,
Expand Down
6 changes: 3 additions & 3 deletions lib/archethic/contracts/wasm/module.ex
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ defmodule Archethic.Contracts.WasmModule do
alias Archethic.TransactionChain.Transaction
alias Archethic.Utils

@reserved_functions ["onInit", "onUpgrade"]
@reserved_functions ["onInit", "onUpgrade", "onInherit"]

defstruct [:module, :store, :spec]

Expand Down Expand Up @@ -164,7 +164,7 @@ defmodule Archethic.Contracts.WasmModule do
end

@spec execute(module :: t(), functionName :: binary(), opts :: execution_opts()) ::
{:ok, ReadResult.t() | UpdateResult.t()}
{:ok, ReadResult.t() | UpdateResult.t() | nil}
| {:error, any()}
def execute(%__MODULE__{module: module, store: store}, function_name, opts \\ [])
when is_binary(function_name) do
Expand Down Expand Up @@ -230,7 +230,7 @@ defmodule Archethic.Contracts.WasmModule do
}
end

defp cast_output(nil), do: {:error, {:invalid_output, nil}}
defp cast_output(nil), do: {:ok, nil}

defp cast_output(output) do
with {:ok, json} <- Jason.decode(output) do
Expand Down
37 changes: 37 additions & 0 deletions test/archethic/contracts_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,43 @@ defmodule Archethic.ContractsTest do
[]
)
end

test "should execute wasm onInherit function" do
bytes = File.read!("test/support/contract.wasm")
manifest = File.read!("test/support/contract_manifest.json")

contract_tx =
ContractFactory.create_valid_contract_tx(
Jason.encode!(%{
manifest: Jason.decode!(manifest),
bytecode: Base.encode16(:zlib.zip(bytes))
})
)

contract = WasmContract.from_transaction!(contract_tx)

assert {:ok, []} =
Contracts.execute_condition(
:inherit,
contract,
contract_tx,
nil,
DateTime.utc_now(),
[]
)

invalid_tx = TransactionFactory.create_valid_transaction([], content: "hello")

assert {:error, %Failure{error: :invalid_inherit_condition}} =
Contracts.execute_condition(
:inherit,
contract,
invalid_tx,
nil,
DateTime.utc_now(),
[]
)
end
end

describe "execute_condition/5 (transaction)" do
Expand Down
Binary file modified test/support/contract.wasm
Binary file not shown.

0 comments on commit a010199

Please sign in to comment.