Skip to content

Commit

Permalink
getBalance IO function
Browse files Browse the repository at this point in the history
  • Loading branch information
bchamagne committed Sep 13, 2024
1 parent 83206bb commit 808386b
Show file tree
Hide file tree
Showing 12 changed files with 110 additions and 50 deletions.
2 changes: 1 addition & 1 deletion config/test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -213,4 +213,4 @@ config :archethic, Archethic.Contracts.Interpreter.Library.Common.HttpImpl,
config :archethic, Archethic.P2P.Message.GetUnspentOutputs, threshold: 1_000
config :archethic, Archethic.P2P.Message.ValidateSmartContractCall, timeout: 50

config :archethic, Archethic.Contracts.WasmIO, MockWasmIO
config :archethic, Archethic.Contracts.Wasm.IO, MockWasmIO
35 changes: 13 additions & 22 deletions lib/archethic/contracts/wasm/imports.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ defmodule Archethic.Contracts.WasmImports do
"""

alias Archethic.Contracts.WasmMemory
alias Archethic.Contracts.WasmIO
alias Archethic.Contracts.Wasm.IO, as: WasmIO
alias Archethic.Utils

import Bitwise

Expand Down Expand Up @@ -60,31 +61,21 @@ defmodule Archethic.Contracts.WasmImports do
def set_error(offset, length, io_mem_pid),
do: WasmMemory.set_error(io_mem_pid, offset, length)

# FIXME: to be modifier with the JSON RPC approach
def get_balance(offset, length, io_mem_pid) do
address = WasmMemory.read(io_mem_pid, offset, length)

%{uco: uco, token: token_balance} = WasmIO.get_balance(address)

encoded_balance =
%{
uco: uco,
token:
Enum.map(token_balance, fn {{address, token_id}, amount} ->
%{
tokenAddress: address,
tokenId: token_id,
amount: amount
}
end)
}
@doc """
Query the node for some I/O function
"""
def jsonrpc(offset, length, io_mem_pid) do
encoded_response =
WasmMemory.read(io_mem_pid, offset, length)
|> Jason.decode!()
|> WasmIO.request()
|> Utils.bin2hex()
|> Jason.encode!()

size = byte_size(encoded_balance)

size = byte_size(encoded_response)
offset = WasmMemory.alloc(io_mem_pid, size)

encoded_balance
encoded_response
|> :erlang.binary_to_list()
|> Enum.with_index()
|> Enum.each(fn {byte, i} ->
Expand Down
19 changes: 14 additions & 5 deletions lib/archethic/contracts/wasm/io.ex
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
defmodule Archethic.Contracts.WasmIO do
defmodule Archethic.Contracts.Wasm.IO do
@moduledoc """
Represents callbacks for WebAssembly contract to performs I/O operations
Query some data of the blockchain from the SC
"""
alias Archethic.Contracts.Wasm.Result

alias Archethic.UTXO
defmodule Request do
@moduledoc false

use Knigge, otp_app: :archethic, default: __MODULE__.NetworkImpl
@callback get_balance(address :: binary()) :: UTXO.balance()
@type t :: %{
method: String.t(),
params: term()
}
defstruct [:method, :params]
end

use Knigge, otp_app: :archethic, default: __MODULE__.JSONRPCImpl
@callback request(request :: Request.t()) :: Result.t()
end
15 changes: 15 additions & 0 deletions lib/archethic/contracts/wasm/io/jsonrpc_impl.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
defmodule Archethic.Contracts.Wasm.IO.JSONRPCImpl do
@moduledoc """
Implementation of IO functions via JSONRPC serialization
"""
alias Archethic.Contracts.Wasm.IO, as: WasmIO
alias Archethic.Contracts.Wasm.Result

@spec request(req :: WasmIO.Request.t()) :: Result.t()
def request(%{method: "getBalance", params: %{address: address}}) do
address
|> Base.decode16!()
|> Archethic.get_balance()
|> Result.wrap_ok()
end
end
11 changes: 0 additions & 11 deletions lib/archethic/contracts/wasm/io/network_impl.ex

This file was deleted.

12 changes: 5 additions & 7 deletions lib/archethic/contracts/wasm/module.ex
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ defmodule Archethic.Contracts.WasmModule do
allowed_imports =
[
"archethic/env::log",
"archethic/IO::get_balance"
"archethic/env::jsonrpc"
]
|> MapSet.new()

Expand Down Expand Up @@ -220,12 +220,10 @@ defmodule Archethic.Contracts.WasmModule do
fn _context, offset, length -> WasmImports.set_error(offset, length, io_mem_pid) end},
store_u8:
{:fn, [:i64, :i32], [],
fn _context, offset, value -> WasmImports.store_u8(offset, value, io_mem_pid) end}
},
"archethic/IO" => %{
get_balance:
{:fn, [:i64, :i64], [:i64],
fn _context, offset, length -> WasmImports.get_balance(offset, length, io_mem_pid) end}
fn _context, offset, value -> WasmImports.store_u8(offset, value, io_mem_pid) end},
jsonrpc:
{:fn, [:i64, :i64], [:i64],
fn _context, offset, length -> WasmImports.jsonrpc(offset, length, io_mem_pid) end}
}
}
end
Expand Down
21 changes: 21 additions & 0 deletions lib/archethic/contracts/wasm/result.ex
Original file line number Diff line number Diff line change
@@ -1,3 +1,24 @@
defmodule Archethic.Contracts.Wasm.Result do
@moduledoc """
Represents a result which mutate the transaction or state
"""
@type t :: %__MODULE__{
ok: %{value: term()} | nil,
error: String.t() | nil
}

@derive Jason.Encoder
defstruct [:ok, :error]

def wrap_ok(value) do
%__MODULE__{ok: %{value: value}}
end

def wrap_error(message) do
%__MODULE__{error: message}
end
end

defmodule Archethic.Contracts.Wasm.UpdateResult do
@moduledoc """
Represents a result which mutate the transaction or state
Expand Down
9 changes: 8 additions & 1 deletion lib/archethic/utils.ex
Original file line number Diff line number Diff line change
Expand Up @@ -1334,7 +1334,14 @@ defmodule Archethic.Utils do
Replace bitstring by hex
"""
@spec bin2hex(any()) :: any()
def bin2hex(data = %{__struct__: _}), do: data
def bin2hex(data = %DateTime{}), do: data

def bin2hex(data = %{__struct__: struct}) do
data
|> Map.from_struct()
|> bin2hex()
|> Map.put(:__struct__, struct)
end

def bin2hex(data) when is_map(data) do
Enum.reduce(data, %{}, fn {key, value}, acc ->
Expand Down
14 changes: 12 additions & 2 deletions test/archethic/contracts_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ defmodule Archethic.ContractsTest do
alias Archethic.Contracts
alias Archethic.Contracts.Contract
alias Archethic.Contracts.WasmContract
alias Archethic.Contracts.Wasm.Result
alias Archethic.Contracts.Contract.ActionWithTransaction
alias Archethic.Contracts.Contract.ActionWithoutTransaction
alias Archethic.Contracts.Contract.ConditionRejected
Expand Down Expand Up @@ -882,8 +883,17 @@ defmodule Archethic.ContractsTest do
address = ArchethicCase.random_address()

MockWasmIO
|> expect(:get_balance, fn ^address ->
%{uco: 500_000_000, token: %{}}
|> expect(:request, fn _request ->
Result.wrap_ok(%{
uco: 500_000_000,
token: [
%{
tokenAddress: :crypto.strong_rand_bytes(32),
amount: 100,
tokenId: 0
}
]
})
end)

bytes = File.read!("test/support/contract.wasm")
Expand Down
Binary file modified test/support/contract.wasm
Binary file not shown.
20 changes: 20 additions & 0 deletions test/support/contract_manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,26 @@
"address": "string"
}
},
"printDeposit": {
"type": "action",
"triggerType": "transaction",
"input": {
"amount": "u64",
"level": "u8"
}
},
"printSum": {
"type": "action",
"triggerType": "transaction",
"input": {}
},
"printTx": {
"type": "action",
"triggerType": "transaction",
"input": {
"address": "string"
}
},
"tick": {
"type": "action",
"triggerType": "interval",
Expand Down
2 changes: 1 addition & 1 deletion test/test_helper.exs
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,4 @@ Mox.defmock(MockUCOPrice, for: Archethic.OracleChain.Services.Impl)
Mox.defmock(MockUCOProvider1, for: Archethic.OracleChain.Services.UCOPrice.Providers.Impl)
Mox.defmock(MockUCOProvider2, for: Archethic.OracleChain.Services.UCOPrice.Providers.Impl)

Mox.defmock(MockWasmIO, for: Archethic.Contracts.WasmIO)
Mox.defmock(MockWasmIO, for: Archethic.Contracts.Wasm.IO)

0 comments on commit 808386b

Please sign in to comment.