Skip to content

Commit f083784

Browse files
committed
[GH-704] Handle Sophia contracts in checks upon creating
1 parent 374dd88 commit f083784

File tree

6 files changed

+116
-6
lines changed

6 files changed

+116
-6
lines changed

apps/aecore/lib/aecore/contract/contract_constants.ex

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,8 @@ defmodule Aecore.Contract.ContractConstants do
1313
defmacro aevm_solidity_01 do
1414
quote do: 2
1515
end
16+
17+
defmacro sophia_init_function do
18+
<<"init">>
19+
end
1620
end
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
defmodule Aecore.Contract.Sophia.SophiaAbi do
2+
3+
def get_function_name_from_type_info(function_hash, type_info) do
4+
function_info =
5+
Enum.find(type_info, nil, fn function_info ->
6+
Enum.at(function_info, 0) == function_hash
7+
end)
8+
9+
case function_info do
10+
nil ->
11+
{:error, :no_such_function}
12+
_ ->
13+
{:ok, Enum.at(function_info, 1)}
14+
end
15+
end
16+
17+
end
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
defmodule Aecore.Contract.Sophia.SophiaData do
2+
3+
@word_size_bits 256
4+
5+
def get_function_hash_from_call_data(call_data) do
6+
<<_::size(@word_size_bits), function_hash_int::size(@word_size_bits), _::binary>> = call_data
7+
8+
<<function_hash_int::size(@word_size_bits)>>
9+
end
10+
11+
end
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
defmodule Aecore.Contract.Sophia.SophiaWrappedCode do
2+
@moduledoc """
3+
Module, defining the wrapped Sophia code structure
4+
"""
5+
6+
alias __MODULE__
7+
8+
@version 1
9+
10+
@type t :: %SophiaWrappedCode{
11+
source_hash: binary(),
12+
# [type_hash, name, arg_type, out_type]
13+
type_info: map(),
14+
byte_code: binary()
15+
}
16+
17+
defstruct [:source_hash, :type_info, :byte_code]
18+
19+
use Aecore.Util.Serializable
20+
21+
@spec encode_to_list(SophiaWrappedCode.t()) :: list()
22+
def encode_to_list(%SophiaWrappedCode{
23+
source_hash: source_hash,
24+
type_info: type_info,
25+
byte_code: byte_code
26+
}) do
27+
[@version, source_hash, type_info, byte_code]
28+
end
29+
30+
@spec decode_from_list(binary(), atom()) :: term() | {:error, binary()}
31+
def decode_from_list(@version, [source_hash, type_info, byte_code]) do
32+
{:ok,
33+
%SophiaWrappedCode{
34+
source_hash: source_hash,
35+
type_info: type_info,
36+
byte_code: byte_code
37+
}}
38+
end
39+
end

apps/aecore/lib/aecore/contract/tx/contract_create_tx.ex

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ defmodule Aecore.Contract.Tx.ContractCreateTx do
1010
alias Aecore.Account.{Account, AccountStateTree}
1111
alias Aecore.Chain.{Identifier, Chainstate}
1212
alias Aecore.Contract.{Contract, Call, CallStateTree, ContractStateTree, Dispatch}
13+
alias Aecore.Contract.Sophia.{SophiaWrappedCode, SophiaData, SophiaAbi}
1314
alias Aecore.Governance.GovernanceConstants
1415
alias Aecore.Tx.{DataTx, Transaction}
1516
require Aecore.Contract.ContractConstants, as: Constants
@@ -178,12 +179,25 @@ defmodule Aecore.Contract.Tx.ContractCreateTx do
178179
Account.apply_transfer!(acc, block_height, (gas_cost + deposit) * -1)
179180
end)
180181

181-
updated_store = ContractStateTree.get(updated_state.contracts, contract.id.value).store
182-
updated_contract = %{contract | code: call_result.return_value, store: updated_store}
182+
updated_contract =
183+
case vm_version do
184+
Constants.aevm_sophia_01() ->
185+
# updated_store = call_result.return_value
186+
# TODO: extract Sophia state from return value and save it in contract state
187+
contract
188+
189+
Constants.aevm_solidity_01() ->
190+
updated_store =
191+
ContractStateTree.get(updated_state.contracts, contract.id.value).store
192+
193+
%{contract | code: call_result.return_value, store: updated_store}
194+
end
195+
196+
cleared_call_result = %{call_result | return_value: <<>>}
183197

184198
chain_state_with_call = %{
185199
updated_state
186-
| calls: CallStateTree.insert_call(updated_state.calls, call_result),
200+
| calls: CallStateTree.insert_call(updated_state.calls, cleared_call_result),
187201
accounts: accounts_after_gas_spent,
188202
contracts:
189203
ContractStateTree.enter_contract(updated_state.contracts, updated_contract)
@@ -220,10 +234,13 @@ defmodule Aecore.Contract.Tx.ContractCreateTx do
220234
_chainstate,
221235
_block_height,
222236
%ContractCreateTx{
223-
amount: amount,
237+
code: code,
238+
vm_version: vm_version,
224239
deposit: deposit,
240+
amount: amount,
225241
gas: gas,
226-
gas_price: gas_price
242+
gas_price: gas_price,
243+
call_data: call_data
227244
},
228245
%DataTx{fee: fee, senders: [%Identifier{value: sender}]},
229246
_context
@@ -233,7 +250,27 @@ defmodule Aecore.Contract.Tx.ContractCreateTx do
233250
if AccountStateTree.get(accounts, sender).balance - total_deduction < 0 do
234251
{:error, "#{__MODULE__}: Negative balance"}
235252
else
236-
:ok
253+
case vm_version do
254+
Constants.aevm_sophia_01() ->
255+
case Serialization.rlp_decode_only(code, SophiaWrappedCode) do
256+
{:ok, %SophiaWrappedCode{type_info: type_info}} ->
257+
function_hash = SophiaData.get_function_hash_from_call_data(call_data)
258+
259+
case SophiaAbi.get_function_name_from_type_info(function_hash, type_info) do
260+
{:ok, Constants.sophia_init_function()} ->
261+
:ok
262+
263+
{:error, _} ->
264+
{:error, "#{__MODULE__}: Bad init function"}
265+
end
266+
267+
{:error, message} ->
268+
{:error, "#{__MODULE__}: #{message}"}
269+
end
270+
271+
Constants.aevm_solidity_01() ->
272+
:ok
273+
end
237274
end
238275
end
239276

apps/aeutil/lib/type_to_tag.ex

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ defmodule Aeutil.TypeToTag do
4141
def tag_to_type(58), do: {:ok, Aecore.Channel.ChannelStateOnChain}
4242
# Channel snapshot transaction - 59
4343
def tag_to_type(60), do: {:ok, Aecore.Poi.Poi}
44+
def tag_to_type(70), do: {:ok, Aecore.Contract.Sophia.SophiaWrappedCode}
4445
# Non Epoch tags:
4546
def tag_to_type(100), do: {:ok, Aecore.Chain.Block}
4647
def tag_to_type(tag), do: {:error, "#{__MODULE__}: Unknown tag: #{inspect(tag)}"}
@@ -83,6 +84,7 @@ defmodule Aeutil.TypeToTag do
8384
def type_to_tag(Aecore.Channel.ChannelStateOnChain), do: {:ok, 58}
8485
# Channel snapshot transaction - 59
8586
def type_to_tag(Aecore.Poi.Poi), do: {:ok, 60}
87+
def type_to_tag(Aecore.Contract.Sophia.SophiaWrappedCode), do: {:ok, 70}
8688
# Non Epoch tags
8789
def type_to_tag(Aecore.Chain.Block), do: {:ok, 100}
8890
def type_to_tag(type), do: {:error, "#{__MODULE__}: Non serializable type: #{type}"}

0 commit comments

Comments
 (0)