Compare commits
29 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3f85375cb2 | |||
| e7f2be7ce8 | |||
| c6475fe1c2 | |||
| 4e4c20c387 | |||
| 1d5e5be252 | |||
| 6efa4a0cb8 | |||
| 59b7b786ac | |||
| f31887c2ed | |||
| d794566363 | |||
| 850a5e2c35 | |||
| c270c794c3 | |||
| 10cc127883 | |||
| 50df849709 | |||
| dfa9b80a3c | |||
| befa1e3ff9 | |||
| efb4afeafa | |||
| e75336486e | |||
| fdd660a219 | |||
| 3954bd22da | |||
| 13211887a3 | |||
| 834ab298d1 | |||
| 52781060b2 | |||
| 3721fde7e8 | |||
| 23ee7e0ca4 | |||
| 197dfd5da1 | |||
| 44ec31d958 | |||
| 8fde1e5e24 | |||
| 7c6a80fef7 | |||
| c0bc71b0b7 |
@@ -17,6 +17,7 @@
|
|||||||
-define(FATE_VOID_T, void).
|
-define(FATE_VOID_T, void).
|
||||||
-define(FATE_TUPLE_T, {tuple, tuple()}).
|
-define(FATE_TUPLE_T, {tuple, tuple()}).
|
||||||
-define(FATE_BITS_T, {bits, integer()}).
|
-define(FATE_BITS_T, {bits, integer()}).
|
||||||
|
-define(FATE_TYPEREP_T, {typerep, fate_type_type()}).
|
||||||
|
|
||||||
-define(IS_FATE_INTEGER(X), (is_integer(X))).
|
-define(IS_FATE_INTEGER(X), (is_integer(X))).
|
||||||
-define(IS_FATE_LIST(X), (is_list(X))).
|
-define(IS_FATE_LIST(X), (is_list(X))).
|
||||||
|
|||||||
+11
-7
@@ -176,6 +176,7 @@
|
|||||||
-define(PRIM_CALL_AENS_UPDATE, 203).
|
-define(PRIM_CALL_AENS_UPDATE, 203).
|
||||||
-define(PRIM_CALL_AENS_TRANSFER, 204).
|
-define(PRIM_CALL_AENS_TRANSFER, 204).
|
||||||
-define(PRIM_CALL_AENS_REVOKE, 205).
|
-define(PRIM_CALL_AENS_REVOKE, 205).
|
||||||
|
-define(PRIM_CALL_AENS_SUBNAME, 206).
|
||||||
|
|
||||||
-define(PRIM_CALL_IN_MAP_RANGE(__TTYPE__), (((__TTYPE__) > 299) andalso ((__TTYPE__) < 400))).
|
-define(PRIM_CALL_IN_MAP_RANGE(__TTYPE__), (((__TTYPE__) > 299) andalso ((__TTYPE__) < 400))).
|
||||||
-define(PRIM_CALL_MAP_EMPTY, 300).
|
-define(PRIM_CALL_MAP_EMPTY, 300).
|
||||||
@@ -186,13 +187,15 @@
|
|||||||
-define(PRIM_CALL_MAP_TOLIST, 305).
|
-define(PRIM_CALL_MAP_TOLIST, 305).
|
||||||
|
|
||||||
-define(PRIM_CALL_IN_CRYPTO_RANGE(__TTYPE__), (((__TTYPE__) > 399) andalso ((__TTYPE__) < 500))).
|
-define(PRIM_CALL_IN_CRYPTO_RANGE(__TTYPE__), (((__TTYPE__) > 399) andalso ((__TTYPE__) < 500))).
|
||||||
-define(PRIM_CALL_CRYPTO_ECVERIFY, 400).
|
-define(PRIM_CALL_CRYPTO_VERIFY_SIG, 400).
|
||||||
-define(PRIM_CALL_CRYPTO_SHA3, 401).
|
-define(PRIM_CALL_CRYPTO_SHA3, 401).
|
||||||
-define(PRIM_CALL_CRYPTO_SHA256, 402).
|
-define(PRIM_CALL_CRYPTO_SHA256, 402).
|
||||||
-define(PRIM_CALL_CRYPTO_BLAKE2B, 403).
|
-define(PRIM_CALL_CRYPTO_BLAKE2B, 403).
|
||||||
-define(PRIM_CALL_CRYPTO_SHA256_STRING, 404).
|
-define(PRIM_CALL_CRYPTO_SHA256_STRING, 404).
|
||||||
-define(PRIM_CALL_CRYPTO_BLAKE2B_STRING, 405).
|
-define(PRIM_CALL_CRYPTO_BLAKE2B_STRING, 405).
|
||||||
-define(PRIM_CALL_CRYPTO_ECVERIFY_SECP256K1, 410).
|
-define(PRIM_CALL_CRYPTO_VERIFY_SIG_SECP256K1, 410).
|
||||||
|
-define(PRIM_CALL_CRYPTO_ECVERIFY_SECP256K1, 420).
|
||||||
|
-define(PRIM_CALL_CRYPTO_ECRECOVER_SECP256K1, 421).
|
||||||
|
|
||||||
-define(PRIM_CALL_IN_AUTH_RANGE(__TTYPE__), (((__TTYPE__) > 499) andalso ((__TTYPE__) < 600))).
|
-define(PRIM_CALL_IN_AUTH_RANGE(__TTYPE__), (((__TTYPE__) > 499) andalso ((__TTYPE__) < 600))).
|
||||||
-define(PRIM_CALL_AUTH_TX_HASH, 500).
|
-define(PRIM_CALL_AUTH_TX_HASH, 500).
|
||||||
@@ -200,3 +203,4 @@
|
|||||||
-define(PRIM_CALL_IN_ADDRESS_RANGE(__TTYPE__), (((__TTYPE__) > 599) andalso ((__TTYPE__) < 700))).
|
-define(PRIM_CALL_IN_ADDRESS_RANGE(__TTYPE__), (((__TTYPE__) > 599) andalso ((__TTYPE__) < 700))).
|
||||||
-define(PRIM_CALL_ADDR_IS_ORACLE, 600).
|
-define(PRIM_CALL_ADDR_IS_ORACLE, 600).
|
||||||
-define(PRIM_CALL_ADDR_IS_CONTRACT, 601).
|
-define(PRIM_CALL_ADDR_IS_CONTRACT, 601).
|
||||||
|
-define(PRIM_CALL_ADDR_IS_PAYABLE, 610).
|
||||||
|
|||||||
@@ -22,5 +22,6 @@ quickcheck_test_() ->
|
|||||||
{setup, fun() -> eqc:start() end,
|
{setup, fun() -> eqc:start() end,
|
||||||
[ ?EQC_EUNIT(aefate_type_eqc, prop_roundtrip, 1000),
|
[ ?EQC_EUNIT(aefate_type_eqc, prop_roundtrip, 1000),
|
||||||
?EQC_EUNIT(aefate_eqc, prop_serializes, 1000),
|
?EQC_EUNIT(aefate_eqc, prop_serializes, 1000),
|
||||||
|
?EQC_EUNIT(aefate_eqc, prop_no_maps_in_keys, 1000),
|
||||||
?EQC_EUNIT(aefate_eqc, prop_idempotent, 1000)
|
?EQC_EUNIT(aefate_eqc, prop_idempotent, 1000)
|
||||||
]}.
|
]}.
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ prop_opcodes() ->
|
|||||||
|
|
||||||
|
|
||||||
valid_opcodes() ->
|
valid_opcodes() ->
|
||||||
lists:seq(0, 16#7c) ++ lists:seq(16#fa, 16#fd).
|
lists:seq(0, 16#7f) ++ lists:seq(16#fa, 16#fd).
|
||||||
|
|
||||||
|
|
||||||
fate_code(Failure) ->
|
fate_code(Failure) ->
|
||||||
@@ -85,7 +85,8 @@ fate_code(Failure) ->
|
|||||||
?LET({FMap, SMap, AMap},
|
?LET({FMap, SMap, AMap},
|
||||||
{non_empty(map(if Failure == 1 -> binary(1);
|
{non_empty(map(if Failure == 1 -> binary(1);
|
||||||
true -> binary(4) end,
|
true -> binary(4) end,
|
||||||
{{list(aefate_type_eqc:fate_type(Size div 3)), aefate_type_eqc:fate_type(Size div 3)}, bbs_code(Failure)})),
|
{sublist(lists:sort([private, payable])), %% deserialize sorts them
|
||||||
|
{list(aefate_type_eqc:fate_type(Size div 3)), aefate_type_eqc:fate_type(Size div 3)}, bbs_code(Failure)})),
|
||||||
small_map(small_fate_data_key(5), small_fate_data(4)),
|
small_map(small_fate_data_key(5), small_fate_data(4)),
|
||||||
small_map(small_fate_data_key(5), small_fate_data(4))},
|
small_map(small_fate_data_key(5), small_fate_data(4))},
|
||||||
aeb_fate_code:update_annotations(
|
aeb_fate_code:update_annotations(
|
||||||
|
|||||||
+52
-10
@@ -10,6 +10,7 @@
|
|||||||
-module(aefate_eqc).
|
-module(aefate_eqc).
|
||||||
|
|
||||||
-include_lib("eqc/include/eqc.hrl").
|
-include_lib("eqc/include/eqc.hrl").
|
||||||
|
-include("../include/aeb_fate_data.hrl").
|
||||||
|
|
||||||
-compile([export_all, nowarn_export_all]).
|
-compile([export_all, nowarn_export_all]).
|
||||||
|
|
||||||
@@ -23,7 +24,7 @@ prop_roundtrip() ->
|
|||||||
end)).
|
end)).
|
||||||
|
|
||||||
prop_format_scan() ->
|
prop_format_scan() ->
|
||||||
?FORALL(FateData, fate_data(),
|
?FORALL(FateData, fate_data([variant, map]),
|
||||||
?WHENFAIL(eqc:format("Trying to format ~p failed~n", [FateData]),
|
?WHENFAIL(eqc:format("Trying to format ~p failed~n", [FateData]),
|
||||||
begin
|
begin
|
||||||
String = aeb_fate_data:format(FateData),
|
String = aeb_fate_data:format(FateData),
|
||||||
@@ -43,6 +44,18 @@ prop_serializes() ->
|
|||||||
{size, size(Binary) < 500000}]))
|
{size, size(Binary) < 500000}]))
|
||||||
end)).
|
end)).
|
||||||
|
|
||||||
|
prop_no_maps_in_keys() ->
|
||||||
|
?FORALL(FateData, fate_bad_map(), %% may contain a map in its keys
|
||||||
|
begin
|
||||||
|
HasMapInKeys = lists:any(fun(K) -> has_map(K) end, maps:keys(FateData)),
|
||||||
|
try aeb_fate_encoding:serialize(FateData),
|
||||||
|
?WHENFAIL(eqc:format("Should not serialize, contains a map in key\n", []),
|
||||||
|
not HasMapInKeys)
|
||||||
|
catch error:Reason ->
|
||||||
|
?WHENFAIL(eqc:format("(~p) Should serialize\n", [Reason]), HasMapInKeys)
|
||||||
|
end
|
||||||
|
end).
|
||||||
|
|
||||||
prop_fuzz() ->
|
prop_fuzz() ->
|
||||||
in_parallel(
|
in_parallel(
|
||||||
?FORALL(Binary, ?LET(FateData, ?SIZED(Size, resize(Size div 4, fate_data())), aeb_fate_encoding:serialize(FateData)),
|
?FORALL(Binary, ?LET(FateData, ?SIZED(Size, resize(Size div 4, fate_data())), aeb_fate_encoding:serialize(FateData)),
|
||||||
@@ -59,13 +72,14 @@ prop_fuzz() ->
|
|||||||
|
|
||||||
|
|
||||||
prop_order() ->
|
prop_order() ->
|
||||||
?FORALL(Items, vector(3, fate_data()),
|
?FORALL(Items, vector(3, fate_data([variant, map])),
|
||||||
begin
|
begin
|
||||||
%% Use lt to take minimum
|
%% Use lt to take minimum
|
||||||
Min = lt_min(Items),
|
Min = lt_min(Items),
|
||||||
Max = lt_max(Items),
|
Max = lt_max(Items),
|
||||||
conjunction([ {minimum, is_empty([ {Min, '>', I} || I<-Items, aeb_fate_data:lt(I, Min)])},
|
conjunction([ {minimum, is_empty([ {Min, '>', I} || I<-Items, aeb_fate_data:lt(I, Min)])},
|
||||||
{maximum, is_empty([ {Max, '<', I} || I<-Items, aeb_fate_data:lt(Max, I)])}])
|
{maximum, is_empty([ {Max, '<', I} || I<-Items, aeb_fate_data:lt(Max, I)])},
|
||||||
|
{asym, aeb_fate_data:lt(Min, Max) orelse Min == Max}])
|
||||||
end).
|
end).
|
||||||
|
|
||||||
lt_min([X, Y | Rest]) ->
|
lt_min([X, Y | Rest]) ->
|
||||||
@@ -88,18 +102,24 @@ prop_idempotent() ->
|
|||||||
aeb_fate_encoding:sort(aeb_fate_encoding:sort(Items)))).
|
aeb_fate_encoding:sort(aeb_fate_encoding:sort(Items)))).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
fate_data(Kind) ->
|
||||||
|
?SIZED(Size, ?LET(Data, fate_data(Size, Kind), eqc_symbolic:eval(Data))).
|
||||||
|
|
||||||
fate_data() ->
|
fate_data() ->
|
||||||
?SIZED(Size, ?LET(Data, fate_data(Size, [map, variant]), eqc_symbolic:eval(Data))).
|
fate_data([map, variant, store_map]).
|
||||||
|
|
||||||
|
%% keys may contain variants but no maps
|
||||||
fate_data_key() ->
|
fate_data_key() ->
|
||||||
?SIZED(Size, ?LET(Data, fate_data(Size div 4, [variant]), eqc_symbolic:eval(Data))).
|
fate_data([variant]).
|
||||||
|
|
||||||
fate_data(0, _Options) ->
|
fate_data(0, Options) ->
|
||||||
?LAZY(
|
?LAZY(
|
||||||
frequency(
|
frequency(
|
||||||
[{5, oneof([fate_integer(), fate_boolean(), fate_nil(), fate_unit()])},
|
[{50, oneof([fate_integer(), fate_boolean(), fate_nil(), fate_unit()])},
|
||||||
{1, oneof([fate_string(), fate_address(), fate_bytes(), fate_contract(),
|
{10, oneof([fate_string(), fate_address(), fate_bytes(), fate_contract(),
|
||||||
fate_oracle(), fate_oracle_q(), fate_bits(), fate_channel()])}]));
|
fate_oracle(), fate_oracle_q(), fate_bits(), fate_channel()])}] ++
|
||||||
|
[{1, fate_store_map()} || lists:member(store_map, Options)]));
|
||||||
fate_data(Size, Options) ->
|
fate_data(Size, Options) ->
|
||||||
?LAZY(
|
?LAZY(
|
||||||
oneof([fate_data(0, Options),
|
oneof([fate_data(0, Options),
|
||||||
@@ -148,9 +168,20 @@ fate_list(Size, Options) ->
|
|||||||
fate_map(Size, Options) ->
|
fate_map(Size, Options) ->
|
||||||
?LET(N, choose(0, 6),
|
?LET(N, choose(0, 6),
|
||||||
?LETSHRINK(Values, fate_values(Size, N, Options),
|
?LETSHRINK(Values, fate_values(Size, N, Options),
|
||||||
?LET(Keys, vector(length(Values), fate_data(Size div max(1, N * 2), Options -- [map])),
|
?LET(Keys, vector(length(Values), fate_data(Size div max(1, N * 2), Options -- [map, store_map])),
|
||||||
return(aeb_fate_data:make_map(maps:from_list(lists:zip(Keys, Values))))))).
|
return(aeb_fate_data:make_map(maps:from_list(lists:zip(Keys, Values))))))).
|
||||||
|
|
||||||
|
fate_store_map() ->
|
||||||
|
%% only #{} is allowed as cache in serialization
|
||||||
|
?LET(X, oneof([int(), largeint()]),
|
||||||
|
return(aeb_fate_data:make_store_map(abs(X)))).
|
||||||
|
|
||||||
|
fate_bad_map() ->
|
||||||
|
?LET(N, choose(0, 6),
|
||||||
|
?LET(Values, vector(N, ?SIZED(Size, resize(Size div 8, fate_data()))),
|
||||||
|
?LET(Keys, vector(N, ?SIZED(Size, resize(Size div 4, fate_data()))),
|
||||||
|
return(aeb_fate_data:make_map(maps:from_list(lists:zip(Keys, Values))))))).
|
||||||
|
|
||||||
non_quote_string() ->
|
non_quote_string() ->
|
||||||
?SUCHTHAT(S, utf8(), [ quote || <<34>> <= S ] == []).
|
?SUCHTHAT(S, utf8(), [ quote || <<34>> <= S ] == []).
|
||||||
|
|
||||||
@@ -167,3 +198,14 @@ injection(Binary) ->
|
|||||||
|
|
||||||
is_empty(L) ->
|
is_empty(L) ->
|
||||||
?WHENFAIL(eqc:format("~p\n", [L]), L == []).
|
?WHENFAIL(eqc:format("~p\n", [L]), L == []).
|
||||||
|
|
||||||
|
has_map(L) when is_list(L) ->
|
||||||
|
lists:any(fun(V) -> has_map(V) end, L);
|
||||||
|
has_map(T) when is_tuple(T) ->
|
||||||
|
has_map(tuple_to_list(T));
|
||||||
|
has_map(M) when is_map(M) ->
|
||||||
|
true;
|
||||||
|
has_map(?FATE_STORE_MAP(_, _)) ->
|
||||||
|
true;
|
||||||
|
has_map(_) ->
|
||||||
|
false.
|
||||||
|
|||||||
+71
-33
@@ -11,14 +11,15 @@
|
|||||||
-define(HASH_SIZE, 32).
|
-define(HASH_SIZE, 32).
|
||||||
|
|
||||||
-export([ create_calldata/4
|
-export([ create_calldata/4
|
||||||
, check_calldata/2
|
, check_calldata/3
|
||||||
, function_type_info/3
|
, function_type_info/4
|
||||||
, function_type_hash/3
|
, function_type_hash/3
|
||||||
, arg_typerep_from_function/2
|
, arg_typerep_from_function/2
|
||||||
, type_hash_from_function_name/2
|
, type_hash_from_function_name/2
|
||||||
, typereps_from_type_hash/2
|
, typereps_from_type_hash/2
|
||||||
, function_name_from_type_hash/2
|
, function_name_from_type_hash/2
|
||||||
, get_function_hash_from_calldata/1
|
, get_function_hash_from_calldata/1
|
||||||
|
, is_payable/2
|
||||||
, abi_version/0
|
, abi_version/0
|
||||||
]).
|
]).
|
||||||
|
|
||||||
@@ -27,6 +28,7 @@
|
|||||||
-type typerep() :: aeb_aevm_data:type().
|
-type typerep() :: aeb_aevm_data:type().
|
||||||
-type function_type_info() :: { FunctionHash :: hash()
|
-type function_type_info() :: { FunctionHash :: hash()
|
||||||
, FunctionName :: function_name()
|
, FunctionName :: function_name()
|
||||||
|
, Payable :: boolean()
|
||||||
, ArgType :: binary() %% binary typerep
|
, ArgType :: binary() %% binary typerep
|
||||||
, OutType :: binary() %% binary typerep
|
, OutType :: binary() %% binary typerep
|
||||||
}.
|
}.
|
||||||
@@ -51,30 +53,40 @@ create_calldata(FunName, Args, ArgTypes0, RetType) ->
|
|||||||
Data = aeb_heap:to_binary({TypeHashInt, list_to_tuple(Args)}),
|
Data = aeb_heap:to_binary({TypeHashInt, list_to_tuple(Args)}),
|
||||||
{ok, Data}.
|
{ok, Data}.
|
||||||
|
|
||||||
-spec check_calldata(binary(), type_info()) ->
|
-spec check_calldata(binary(), type_info(), boolean()) ->
|
||||||
{'ok', typerep(), typerep()} | {'error', atom()}.
|
{'ok', typerep(), typerep()} | {'error', atom()}.
|
||||||
check_calldata(CallData, TypeInfo) ->
|
check_calldata(CallData, TypeInfo, CheckPayable) ->
|
||||||
%% The first element of the CallData should be the function name
|
%% The first element of the CallData should be the function name
|
||||||
case get_function_hash_from_calldata(CallData) of
|
case get_function_hash_from_calldata(CallData) of
|
||||||
{ok, Hash} ->
|
{ok, Hash} ->
|
||||||
case typereps_from_type_hash(Hash, TypeInfo) of
|
check_calldata(Hash, CallData, TypeInfo, CheckPayable);
|
||||||
{ok, ArgType, OutType} ->
|
|
||||||
try aeb_heap:from_binary({tuple, [word, ArgType]}, CallData) of
|
|
||||||
{ok, _Something} ->
|
|
||||||
{ok, {tuple, [word, ArgType]}, OutType};
|
|
||||||
{error, _} ->
|
|
||||||
{error, bad_call_data}
|
|
||||||
catch
|
|
||||||
_T:_E ->
|
|
||||||
{error, bad_call_data}
|
|
||||||
end;
|
|
||||||
{error, _} ->
|
|
||||||
{error, unknown_function}
|
|
||||||
end;
|
|
||||||
{error, _What} ->
|
{error, _What} ->
|
||||||
{error, bad_call_data}
|
{error, bad_call_data}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
check_calldata(Hash, CallData, TypeInfo, true) ->
|
||||||
|
case is_payable(Hash, TypeInfo) of
|
||||||
|
{ok, true} -> check_calldata(Hash, CallData, TypeInfo, false);
|
||||||
|
{ok, false} -> {error, function_is_not_payable};
|
||||||
|
Err = {error, _} -> Err
|
||||||
|
end;
|
||||||
|
check_calldata(Hash, CallData, TypeInfo, false) ->
|
||||||
|
case typereps_from_type_hash(Hash, TypeInfo) of
|
||||||
|
{ok, ArgType, OutType} ->
|
||||||
|
try aeb_heap:from_binary({tuple, [word, ArgType]}, CallData) of
|
||||||
|
{ok, _Something} ->
|
||||||
|
{ok, {tuple, [word, ArgType]}, OutType};
|
||||||
|
{error, _} ->
|
||||||
|
{error, bad_call_data}
|
||||||
|
catch
|
||||||
|
_T:_E ->
|
||||||
|
{error, bad_call_data}
|
||||||
|
end;
|
||||||
|
{error, _} ->
|
||||||
|
{error, unknown_function}
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
-spec get_function_hash_from_calldata(CallData::binary()) ->
|
-spec get_function_hash_from_calldata(CallData::binary()) ->
|
||||||
{ok, binary()} | {error, term()}.
|
{ok, binary()} | {error, term()}.
|
||||||
get_function_hash_from_calldata(CallData) ->
|
get_function_hash_from_calldata(CallData) ->
|
||||||
@@ -86,12 +98,13 @@ get_function_hash_from_calldata(CallData) ->
|
|||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
%%% Handle type info from contract meta data
|
%%% Handle type info from contract meta data
|
||||||
|
|
||||||
-spec function_type_info(function_name(), [typerep()], typerep()) ->
|
-spec function_type_info(function_name(), boolean(), [typerep()], typerep()) ->
|
||||||
function_type_info().
|
function_type_info().
|
||||||
function_type_info(Name, ArgTypes, OutType) ->
|
function_type_info(Name, Payable, ArgTypes, OutType) ->
|
||||||
ArgType = {tuple, ArgTypes},
|
ArgType = {tuple, ArgTypes},
|
||||||
{ function_type_hash(Name, ArgType, OutType)
|
{ function_type_hash(Name, ArgType, OutType)
|
||||||
, Name
|
, Name
|
||||||
|
, Payable
|
||||||
, aeb_heap:to_binary(ArgType)
|
, aeb_heap:to_binary(ArgType)
|
||||||
, aeb_heap:to_binary(OutType)
|
, aeb_heap:to_binary(OutType)
|
||||||
}.
|
}.
|
||||||
@@ -110,35 +123,46 @@ function_type_hash(Name, ArgType, OutType) when is_binary(Name) ->
|
|||||||
{'ok', typerep()} | {'error', 'bad_type_data' | 'unknown_function'}.
|
{'ok', typerep()} | {'error', 'bad_type_data' | 'unknown_function'}.
|
||||||
arg_typerep_from_function(Function, TypeInfo) ->
|
arg_typerep_from_function(Function, TypeInfo) ->
|
||||||
case lists:keyfind(Function, 2, TypeInfo) of
|
case lists:keyfind(Function, 2, TypeInfo) of
|
||||||
{_TypeHash, Function, ArgTypeBin,_OutTypeBin} ->
|
{_TypeHash, Function, ArgTypeBin, _OutTypeBin} ->
|
||||||
case aeb_heap:from_binary(typerep, ArgTypeBin) of
|
arg_typerep_from_type_binary(ArgTypeBin);
|
||||||
{ok, ArgType} -> {ok, ArgType};
|
{_TypeHash, Function, _Payable, ArgTypeBin, _OutTypeBin} ->
|
||||||
{error,_} -> {error, bad_type_data}
|
arg_typerep_from_type_binary(ArgTypeBin);
|
||||||
end;
|
|
||||||
false ->
|
false ->
|
||||||
{error, unknown_function}
|
{error, unknown_function}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
arg_typerep_from_type_binary(ArgTBin) ->
|
||||||
|
case aeb_heap:from_binary(typerep, ArgTBin) of
|
||||||
|
{ok, ArgT} -> {ok, ArgT};
|
||||||
|
{error,_} -> {error, bad_type_data}
|
||||||
|
end.
|
||||||
|
|
||||||
-spec typereps_from_type_hash(hash(), type_info()) ->
|
-spec typereps_from_type_hash(hash(), type_info()) ->
|
||||||
{'ok', typerep(), typerep()} | {'error', 'bad_type_data' | 'unknown_function'}.
|
{'ok', typerep(), typerep()} | {'error', 'bad_type_data' | 'unknown_function'}.
|
||||||
typereps_from_type_hash(TypeHash, TypeInfo) ->
|
typereps_from_type_hash(TypeHash, TypeInfo) ->
|
||||||
case lists:keyfind(TypeHash, 1, TypeInfo) of
|
case lists:keyfind(TypeHash, 1, TypeInfo) of
|
||||||
{TypeHash,_Function, ArgTypeBin, OutTypeBin} ->
|
{TypeHash, _Function, ArgTypeBin, OutTypeBin} ->
|
||||||
case {aeb_heap:from_binary(typerep, ArgTypeBin),
|
typereps_from_type_binaries(ArgTypeBin, OutTypeBin);
|
||||||
aeb_heap:from_binary(typerep, OutTypeBin)} of
|
{TypeHash, _Function, _Payable, ArgTypeBin, OutTypeBin} ->
|
||||||
{{ok, ArgType}, {ok, OutType}} -> {ok, ArgType, OutType};
|
typereps_from_type_binaries(ArgTypeBin, OutTypeBin);
|
||||||
{_, _} -> {error, bad_type_data}
|
|
||||||
end;
|
|
||||||
false ->
|
false ->
|
||||||
{error, unknown_function}
|
{error, unknown_function}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
typereps_from_type_binaries(ArgTBin, OutTBin) ->
|
||||||
|
case {aeb_heap:from_binary(typerep, ArgTBin), aeb_heap:from_binary(typerep, OutTBin)} of
|
||||||
|
{{ok, ArgT}, {ok, OutT}} -> {ok, ArgT, OutT};
|
||||||
|
{_, _} -> {error, bad_type_data}
|
||||||
|
end.
|
||||||
|
|
||||||
-spec function_name_from_type_hash(hash(), type_info()) ->
|
-spec function_name_from_type_hash(hash(), type_info()) ->
|
||||||
{'ok', function_name()}
|
{'ok', function_name()}
|
||||||
| {'error', 'unknown_function'}.
|
| {'error', 'unknown_function'}.
|
||||||
function_name_from_type_hash(TypeHash, TypeInfo) ->
|
function_name_from_type_hash(TypeHash, TypeInfo) ->
|
||||||
case lists:keyfind(TypeHash, 1, TypeInfo) of
|
case lists:keyfind(TypeHash, 1, TypeInfo) of
|
||||||
{TypeHash, Function,_ArgTypeBin,_OutTypeBin} ->
|
{TypeHash, Function, _ArgTypeBin, _OutTypeBin} ->
|
||||||
|
{ok, Function};
|
||||||
|
{TypeHash, Function, _Payable, _ArgTypeBin, _OutTypeBin} ->
|
||||||
{ok, Function};
|
{ok, Function};
|
||||||
false ->
|
false ->
|
||||||
{error, unknown_function}
|
{error, unknown_function}
|
||||||
@@ -149,8 +173,22 @@ function_name_from_type_hash(TypeHash, TypeInfo) ->
|
|||||||
| {'error', 'unknown_function'}.
|
| {'error', 'unknown_function'}.
|
||||||
type_hash_from_function_name(Name, TypeInfo) ->
|
type_hash_from_function_name(Name, TypeInfo) ->
|
||||||
case lists:keyfind(Name, 2, TypeInfo) of
|
case lists:keyfind(Name, 2, TypeInfo) of
|
||||||
{TypeHash, Name,_ArgTypeBin,_OutTypeBin} ->
|
{TypeHash, Name, _ArgTypeBin, _OutTypeBin} ->
|
||||||
|
{ok, TypeHash};
|
||||||
|
{TypeHash, Name, _Payable, _ArgTypeBin, _OutTypeBin} ->
|
||||||
{ok, TypeHash};
|
{ok, TypeHash};
|
||||||
false ->
|
false ->
|
||||||
{error, unknown_function}
|
{error, unknown_function}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
-spec is_payable(hash(), type_info()) -> {ok, boolean()} | {error, 'unknown_function'}.
|
||||||
|
is_payable(TypeHash, TypeInfo) ->
|
||||||
|
case lists:keyfind(TypeHash, 1, TypeInfo) of
|
||||||
|
{TypeHash, _Function, _ArgTypeBin, _OutTypeBin} ->
|
||||||
|
{ok, true};
|
||||||
|
{TypeHash, _Function, Payable, _ArgTypeBin, _OutTypeBin} ->
|
||||||
|
{ok, Payable};
|
||||||
|
false ->
|
||||||
|
{error, unknown_function}
|
||||||
|
end.
|
||||||
|
|
||||||
|
|||||||
@@ -72,6 +72,6 @@ get_function_type_from_function_hash(SymbolHash, FateCode) ->
|
|||||||
case maps:get(SymbolHash, Functions, undefined) of
|
case maps:get(SymbolHash, Functions, undefined) of
|
||||||
undefined ->
|
undefined ->
|
||||||
{error, no_function_matching_function_hash};
|
{error, no_function_matching_function_hash};
|
||||||
{{ArgTypes, RetType}, _Code} ->
|
{_Attrs, {ArgTypes, RetType}, _Code} ->
|
||||||
{ok, ArgTypes, RetType}
|
{ok, ArgTypes, RetType}
|
||||||
end.
|
end.
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ format_functions(Functions, Symbols) ->
|
|||||||
lists:sort(maps:to_list(CodeMap)),
|
lists:sort(maps:to_list(CodeMap)),
|
||||||
Symbols)
|
Symbols)
|
||||||
||
|
||
|
||||||
{Name, {Sig, CodeMap}} <- maps:to_list(Functions)].
|
{Name, {_Attrs, Sig, CodeMap}} <- maps:to_list(Functions)].
|
||||||
|
|
||||||
|
|
||||||
format(Name, Sig, BBs, Symbols) ->
|
format(Name, Sig, BBs, Symbols) ->
|
||||||
@@ -484,7 +484,7 @@ insert_fun({NameString, ArgType, RetType}, Code, #{ fate_code := FateCode
|
|||||||
{FateCode1, Id} = aeb_fate_code:insert_symbol(Name, FateCode),
|
{FateCode1, Id} = aeb_fate_code:insert_symbol(Name, FateCode),
|
||||||
BodyByteCode = aeb_fate_code:serialize_code(lists:reverse(Code)),
|
BodyByteCode = aeb_fate_code:serialize_code(lists:reverse(Code)),
|
||||||
SigByteCode = aeb_fate_code:serialize_signature({ArgType, RetType}),
|
SigByteCode = aeb_fate_code:serialize_signature({ArgType, RetType}),
|
||||||
FunByteCode = [?FUNCTION, Id, SigByteCode, BodyByteCode],
|
FunByteCode = [?FUNCTION, Id, aeb_fate_encoding:serialize(0), SigByteCode, BodyByteCode],
|
||||||
Env#{ functions => Funs#{ Id => FunByteCode }
|
Env#{ functions => Funs#{ Id => FunByteCode }
|
||||||
, fate_code => FateCode1}.
|
, fate_code => FateCode1}.
|
||||||
|
|
||||||
|
|||||||
+42
-21
@@ -11,7 +11,7 @@
|
|||||||
, deserialize/1
|
, deserialize/1
|
||||||
, functions/1
|
, functions/1
|
||||||
, insert_annotation/4
|
, insert_annotation/4
|
||||||
, insert_fun/4
|
, insert_fun/5
|
||||||
, insert_symbol/2
|
, insert_symbol/2
|
||||||
, new/0
|
, new/0
|
||||||
, serialize/1
|
, serialize/1
|
||||||
@@ -72,9 +72,9 @@ symbol_identifier(Bin) ->
|
|||||||
{ok, <<X:4/binary,_/binary>> } = eblake2:blake2b(?HASH_BYTES, Bin),
|
{ok, <<X:4/binary,_/binary>> } = eblake2:blake2b(?HASH_BYTES, Bin),
|
||||||
X.
|
X.
|
||||||
|
|
||||||
insert_fun(Name, {ArgType, RetType}, #{} = BBs, FCode) ->
|
insert_fun(Name, Attrs, {ArgType, RetType}, #{} = BBs, FCode) ->
|
||||||
{F1, ID} = insert_symbol(Name, FCode),
|
{F1, ID} = insert_symbol(Name, FCode),
|
||||||
update_functions(F1, #{ID => {{ArgType, RetType}, BBs}}).
|
update_functions(F1, #{ID => {Attrs, {ArgType, RetType}, BBs}}).
|
||||||
|
|
||||||
insert_symbol(Name, #fcode{ symbols = Syms } = F) ->
|
insert_symbol(Name, #fcode{ symbols = Syms } = F) ->
|
||||||
ID = symbol_identifier(Name),
|
ID = symbol_identifier(Name),
|
||||||
@@ -128,10 +128,17 @@ to_hexstring(ByteList) ->
|
|||||||
serialize_functions(#fcode{ functions = Functions }) ->
|
serialize_functions(#fcode{ functions = Functions }) ->
|
||||||
%% Sort the functions on name to get a canonical serialisation.
|
%% Sort the functions on name to get a canonical serialisation.
|
||||||
iolist_to_binary(
|
iolist_to_binary(
|
||||||
lists:foldr(fun({Id, {Sig, C}}, Acc) ->
|
lists:foldr(fun({Id, {Attrs, Sig, C}}, Acc) ->
|
||||||
[[?FUNCTION, Id, serialize_signature(Sig), serialize_bbs(C)] | Acc]
|
[[?FUNCTION, Id, serialize_attributes(Attrs), serialize_signature(Sig), serialize_bbs(C)] | Acc]
|
||||||
end, [], lists:sort(maps:to_list(Functions)))).
|
end, [], lists:sort(maps:to_list(Functions)))).
|
||||||
|
|
||||||
|
serialize_attributes(Attrs) ->
|
||||||
|
AttrVal = lists:sum([ attr_value(Attr) || Attr <- Attrs ]),
|
||||||
|
aeb_fate_encoding:serialize(?MAKE_FATE_INTEGER(AttrVal)).
|
||||||
|
|
||||||
|
attr_value(private) -> 1;
|
||||||
|
attr_value(payable) -> 2.
|
||||||
|
|
||||||
serialize_signature({Args, RetType}) ->
|
serialize_signature({Args, RetType}) ->
|
||||||
[aeb_fate_encoding:serialize_type({tuple, Args}) |
|
[aeb_fate_encoding:serialize_type({tuple, Args}) |
|
||||||
aeb_fate_encoding:serialize_type(RetType)].
|
aeb_fate_encoding:serialize_type(RetType)].
|
||||||
@@ -139,7 +146,7 @@ serialize_signature({Args, RetType}) ->
|
|||||||
serialize_symbol_table(#fcode{ symbols = Symbols }) ->
|
serialize_symbol_table(#fcode{ symbols = Symbols }) ->
|
||||||
aeb_fate_encoding:serialize(aeb_fate_data:make_map(Symbols)).
|
aeb_fate_encoding:serialize(aeb_fate_data:make_map(Symbols)).
|
||||||
|
|
||||||
serialize_annotations(#fcode{ annotations = Annotations}) ->
|
serialize_annotations(#fcode{ annotations = Annotations }) ->
|
||||||
aeb_fate_encoding:serialize(aeb_fate_data:make_map(Annotations)).
|
aeb_fate_encoding:serialize(aeb_fate_data:make_map(Annotations)).
|
||||||
|
|
||||||
serialize_bbs(#{} = BBs) ->
|
serialize_bbs(#{} = BBs) ->
|
||||||
@@ -166,8 +173,8 @@ serialize_op(Op) ->
|
|||||||
|
|
||||||
sanity_check(#fcode{ functions = Funs }) ->
|
sanity_check(#fcode{ functions = Funs }) ->
|
||||||
_ = [ case Def of
|
_ = [ case Def of
|
||||||
{_, BBs} when byte_size(Id) == 4 -> sanity_check_bbs(BBs);
|
{_, _, BBs} when byte_size(Id) == 4 -> sanity_check_bbs(BBs);
|
||||||
_ -> error({illegal_function_id, Id})
|
_ -> error({illegal_function_id, Id})
|
||||||
end || {Id, Def} <- maps:to_list(Funs) ],
|
end || {Id, Def} <- maps:to_list(Funs) ],
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
@@ -303,33 +310,35 @@ deserialize_functions(<<?FUNCTION:8, A, B, C, D, Rest/binary>>,
|
|||||||
, bb := 0
|
, bb := 0
|
||||||
, current_bb_code := []
|
, current_bb_code := []
|
||||||
} = Env) ->
|
} = Env) ->
|
||||||
{Sig, Rest2} = deserialize_signature(Rest),
|
{Attrs, Rest2} = deserialize_attributes(Rest),
|
||||||
Env2 = Env#{function => {<<A,B,C,D>>, Sig}},
|
{Sig, Rest3} = deserialize_signature(Rest2),
|
||||||
deserialize_functions(Rest2, Env2);
|
Env2 = Env#{function => {<<A,B,C,D>>, Attrs, Sig}},
|
||||||
|
deserialize_functions(Rest3, Env2);
|
||||||
deserialize_functions(<<?FUNCTION:8, A, B, C, D, Rest/binary>>,
|
deserialize_functions(<<?FUNCTION:8, A, B, C, D, Rest/binary>>,
|
||||||
#{ function := {F, Sig}
|
#{ function := {F, Attrs, Sig}
|
||||||
, bb := BB
|
, bb := BB
|
||||||
, current_bb_code := Code
|
, current_bb_code := Code
|
||||||
, code := Program
|
, code := Program
|
||||||
, functions := Funs} = Env) ->
|
, functions := Funs} = Env) ->
|
||||||
{NewSig, Rest2} = deserialize_signature(Rest),
|
{NewAttrs, Rest2} = deserialize_attributes(Rest),
|
||||||
|
{NewSig, Rest3} = deserialize_signature(Rest2),
|
||||||
case Code of
|
case Code of
|
||||||
[] ->
|
[] ->
|
||||||
Env2 = Env#{ bb => 0
|
Env2 = Env#{ bb => 0
|
||||||
, current_bb_code => []
|
, current_bb_code => []
|
||||||
, function => {<<A,B,C,D>>, NewSig}
|
, function => {<<A,B,C,D>>, NewAttrs, NewSig}
|
||||||
, code => #{}
|
, code => #{}
|
||||||
, functions => Funs#{F => {Sig, Program}}},
|
, functions => Funs#{F => {Attrs, Sig, Program}}},
|
||||||
deserialize_functions(Rest2, Env2);
|
deserialize_functions(Rest3, Env2);
|
||||||
_ ->
|
_ ->
|
||||||
Env2 = Env#{ bb => 0
|
Env2 = Env#{ bb => 0
|
||||||
, current_bb_code => []
|
, current_bb_code => []
|
||||||
, function => {<<A,B,C,D>>, NewSig}
|
, function => {<<A,B,C,D>>, NewAttrs, NewSig}
|
||||||
, code => #{}
|
, code => #{}
|
||||||
, functions =>
|
, functions =>
|
||||||
Funs#{F => {Sig,
|
Funs#{F => {Attrs, Sig,
|
||||||
Program#{ BB => lists:reverse(Code)}}}},
|
Program#{ BB => lists:reverse(Code)}}}},
|
||||||
deserialize_functions(Rest2, Env2)
|
deserialize_functions(Rest3, Env2)
|
||||||
end;
|
end;
|
||||||
deserialize_functions(<<_Op:8, _Rest/binary>>,
|
deserialize_functions(<<_Op:8, _Rest/binary>>,
|
||||||
#{ function := none }) ->
|
#{ function := none }) ->
|
||||||
@@ -351,7 +360,7 @@ deserialize_functions(<<Op:8, Rest/binary>>,
|
|||||||
deserialize_functions(<<>>, #{ function := none
|
deserialize_functions(<<>>, #{ function := none
|
||||||
, functions := Funs}) ->
|
, functions := Funs}) ->
|
||||||
Funs;
|
Funs;
|
||||||
deserialize_functions(<<>>, #{ function := {F, Sig}
|
deserialize_functions(<<>>, #{ function := {F, Attrs, Sig}
|
||||||
, bb := BB
|
, bb := BB
|
||||||
, current_bb_code := Code
|
, current_bb_code := Code
|
||||||
, code := Program
|
, code := Program
|
||||||
@@ -361,7 +370,7 @@ deserialize_functions(<<>>, #{ function := {F, Sig}
|
|||||||
[] -> Program;
|
[] -> Program;
|
||||||
_ -> Program#{ BB => lists:reverse(Code)}
|
_ -> Program#{ BB => lists:reverse(Code)}
|
||||||
end,
|
end,
|
||||||
Funs#{F => {Sig, FunctionCode}}.
|
Funs#{F => {Attrs, Sig, FunctionCode}}.
|
||||||
|
|
||||||
deserialize_op(Op, Rest, Code) ->
|
deserialize_op(Op, Rest, Code) ->
|
||||||
OpName = aeb_fate_opcodes:mnemonic(Op),
|
OpName = aeb_fate_opcodes:mnemonic(Op),
|
||||||
@@ -399,6 +408,18 @@ deserialize_n_args(N, <<M7:2, M6:2, M5:2, M4:2, M3:2, M2:2, M1:2, M0:2,
|
|||||||
end
|
end
|
||||||
end, Rest, ArgMods).
|
end, Rest, ArgMods).
|
||||||
|
|
||||||
|
deserialize_attributes(Binary) ->
|
||||||
|
{AttrVal, Rest} = aeb_fate_encoding:deserialize_one(Binary),
|
||||||
|
Attrs = [ attr(AVal) || AVal <- attr_vals(1, AttrVal) ],
|
||||||
|
{lists:sort(Attrs), Rest}.
|
||||||
|
|
||||||
|
attr_vals(_, 0) -> [];
|
||||||
|
attr_vals(X, N) when N rem 2 == 0 -> attr_vals(X + 1, N div 2);
|
||||||
|
attr_vals(X, N) -> [X | attr_vals(X + 1, N div 2)].
|
||||||
|
|
||||||
|
attr(1) -> private;
|
||||||
|
attr(2) -> payable.
|
||||||
|
|
||||||
deserialize_signature(Binary) ->
|
deserialize_signature(Binary) ->
|
||||||
{{tuple, Args}, Rest} = aeb_fate_encoding:deserialize_type(Binary),
|
{{tuple, Args}, Rest} = aeb_fate_encoding:deserialize_type(Binary),
|
||||||
{RetType, Rest2} = aeb_fate_encoding:deserialize_type(Rest),
|
{RetType, Rest2} = aeb_fate_encoding:deserialize_type(Rest),
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
-type fate_variant() :: ?FATE_VARIANT_T.
|
-type fate_variant() :: ?FATE_VARIANT_T.
|
||||||
-type fate_tuple() :: ?FATE_TUPLE_T.
|
-type fate_tuple() :: ?FATE_TUPLE_T.
|
||||||
-type fate_bits() :: ?FATE_BITS_T.
|
-type fate_bits() :: ?FATE_BITS_T.
|
||||||
|
-type fate_typerep() :: ?FATE_TYPEREP_T.
|
||||||
|
|
||||||
-type fate_type_type() :: integer
|
-type fate_type_type() :: integer
|
||||||
| boolean
|
| boolean
|
||||||
@@ -54,7 +55,8 @@
|
|||||||
| fate_channel()
|
| fate_channel()
|
||||||
| fate_variant()
|
| fate_variant()
|
||||||
| fate_map()
|
| fate_map()
|
||||||
| fate_bits().
|
| fate_bits()
|
||||||
|
| fate_typerep().
|
||||||
|
|
||||||
-export_type([fate_type/0
|
-export_type([fate_type/0
|
||||||
, fate_boolean/0
|
, fate_boolean/0
|
||||||
|
|||||||
@@ -487,5 +487,11 @@ sort(KVList) ->
|
|||||||
|
|
||||||
valid_key_type(K) when ?IS_FATE_MAP(K) ->
|
valid_key_type(K) when ?IS_FATE_MAP(K) ->
|
||||||
error({map_as_key_in_map, K});
|
error({map_as_key_in_map, K});
|
||||||
|
valid_key_type(?FATE_STORE_MAP(_, _) = K) ->
|
||||||
|
error({map_as_key_in_map, K});
|
||||||
|
valid_key_type(K) when is_list(K) ->
|
||||||
|
lists:all(fun(E) -> valid_key_type(E) end, K);
|
||||||
|
valid_key_type(K) when is_tuple(K) ->
|
||||||
|
lists:all(fun(E) -> valid_key_type(E) end, tuple_to_list(K));
|
||||||
valid_key_type(_K) ->
|
valid_key_type(_K) ->
|
||||||
true.
|
true.
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
, generate/0
|
, generate/0
|
||||||
, generate_documentation/1
|
, generate_documentation/1
|
||||||
, get_ops/0
|
, get_ops/0
|
||||||
, test_asm_generator/1]).
|
, test_asm_generator/1 ]).
|
||||||
|
|
||||||
gen_and_halt([SrcDirArg, IncludeDirArg]) ->
|
gen_and_halt([SrcDirArg, IncludeDirArg]) ->
|
||||||
generate(atom_to_list(SrcDirArg),
|
generate(atom_to_list(SrcDirArg),
|
||||||
@@ -46,10 +46,10 @@ ops_defs() ->
|
|||||||
[ { 'RETURN', 16#00, true, true, true, 2, [], return, {}, any, "Return from function call, top of stack is return value . The type of the retun value has to match the return type of the function."}
|
[ { 'RETURN', 16#00, true, true, true, 2, [], return, {}, any, "Return from function call, top of stack is return value . The type of the retun value has to match the return type of the function."}
|
||||||
, { 'RETURNR', 16#01, true, true, true, 2, [a], returnr, {any}, any, "Push Arg0 and return from function. The type of the retun value has to match the return type of the function."}
|
, { 'RETURNR', 16#01, true, true, true, 2, [a], returnr, {any}, any, "Push Arg0 and return from function. The type of the retun value has to match the return type of the function."}
|
||||||
, { 'CALL', 16#02, true, true, true, 4, [a], call, {string}, any, "Call the function Arg0 with args on stack. The types of the arguments has to match the argument typs of the function."}
|
, { 'CALL', 16#02, true, true, true, 4, [a], call, {string}, any, "Call the function Arg0 with args on stack. The types of the arguments has to match the argument typs of the function."}
|
||||||
, { 'CALL_R', 16#03, true, false, true, 8, [a,is,ii,a], call_r, {contract, string, integer, integer}, any, "Remote call to contract Arg0 and Arg2-ary function Arg1 with value Arg3. The types of the arguments has to match the argument typs of the function."}
|
, { 'CALL_R', 16#03, true, false, true, 8, [a,is,a,a,a], call_r, {contract, string, typerep, typerep, integer}, any, "Remote call to contract Arg0 and function Arg1 of type Arg2 => Arg3 with value Arg4. The types of the arguments has to match the argument types of the function."}
|
||||||
, { 'CALL_T', 16#04, true, true, true, 4, [a], call_t, {string}, any, "Tail call to function Arg0. The types of the arguments has to match the argument typs of the function. And the return type of the called function has to match the type of the current function."}
|
, { 'CALL_T', 16#04, true, true, true, 4, [a], call_t, {string}, any, "Tail call to function Arg0. The types of the arguments has to match the argument typs of the function. And the return type of the called function has to match the type of the current function."}
|
||||||
, { 'UNUSED_1', 16#05, false, false, true, 8, [], unused_1, {}, none, "Was CALL_TR."}
|
, { 'UNUSED_1', 16#05, false, false, true, 8, [], unused_1, {}, none, "Was CALL_TR."}
|
||||||
, { 'CALL_GR', 16#06, true, false, true, 8, [a,is,ii,a,a], call_gr, {contract, string, integer, integer, integer}, any, "Remote call with gas cap in Arg3. Otherwise as CALL_R."}
|
, { 'CALL_GR', 16#06, true, false, true, 8, [a,is,a,a,a,a], call_gr, {contract, string, typerep, typerep, integer, integer}, any, "Remote call with gas cap in Arg4. Otherwise as CALL_R."}
|
||||||
, { 'UNUSED_2', 16#07, false, false, true, 8, [], unused_2, {}, none, "Was CALL_GTR."}
|
, { 'UNUSED_2', 16#07, false, false, true, 8, [], unused_2, {}, none, "Was CALL_GTR."}
|
||||||
, { 'JUMP', 16#08, true, true, true, 3, [ii], jump, {integer}, none, "Jump to a basic block. The basic block has to exist in the current function."}
|
, { 'JUMP', 16#08, true, true, true, 3, [ii], jump, {integer}, none, "Jump to a basic block. The basic block has to exist in the current function."}
|
||||||
, { 'JUMPIF', 16#09, true, true, true, 4, [a,ii], jumpif, {boolean, integer}, none, "Conditional jump to a basic block. If Arg0 then jump to Arg1."}
|
, { 'JUMPIF', 16#09, true, true, true, 4, [a,ii], jumpif, {boolean, integer}, none, "Conditional jump to a basic block. If Arg0 then jump to Arg1."}
|
||||||
@@ -161,11 +161,11 @@ ops_defs() ->
|
|||||||
, { 'MAP_TO_LIST', 16#70, false, true, true, 3, [a,a], map_to_list, {map}, list, "Arg0 := The tuple list representation of the map Arg1."}
|
, { 'MAP_TO_LIST', 16#70, false, true, true, 3, [a,a], map_to_list, {map}, list, "Arg0 := The tuple list representation of the map Arg1."}
|
||||||
, { 'STR_LENGTH', 16#71, false, true, true, 3, [a,a], str_length, {string}, integer, "Arg0 := The length of the string Arg1."}
|
, { 'STR_LENGTH', 16#71, false, true, true, 3, [a,a], str_length, {string}, integer, "Arg0 := The length of the string Arg1."}
|
||||||
|
|
||||||
, { 'ECVERIFY', 16#72, false, true, true, 1300, [a,a,a,a], ecverify, {bytes, address, bytes}, boolean, "Arg0 := ecverify(Hash, PubKey, Signature)"}
|
, { 'VERIFY_SIG', 16#72, false, true, true, 1300, [a,a,a,a], verify_sig, {bytes, address, bytes}, boolean, "Arg0 := verify_sig(Hash, PubKey, Signature)"}
|
||||||
, { 'ECVERIFY_SECP256K1', 16#73, false, true, true, 1300, [a,a,a,a], ecverify_secp256k1, {bytes, bytes, bytes}, boolean, "Arg0 := ecverify_secp256k1(Hash, PubKey, Signature)"}
|
, { 'VERIFY_SIG_SECP256K1', 16#73, false, true, true, 1300, [a,a,a,a], verify_sig_secp256k1, {bytes, bytes, bytes}, boolean, "Arg0 := verify_sig_secp256k1(Hash, PubKey, Signature)"}
|
||||||
|
|
||||||
, { 'CONTRACT_TO_ADDRESS', 16#74, false, true, true, 3, [a,a], contract_to_address, {contract}, address, "Arg0 := Arg1 - A no-op type conversion"}
|
, { 'CONTRACT_TO_ADDRESS', 16#74, false, true, true, 3, [a,a], contract_to_address, {contract}, address, "Arg0 := Arg1 - A no-op type conversion"}
|
||||||
, { 'AUTH_TX_HASH', 16#75, false, true, true, 3, [a], auth_tx_hash, {}, variant, "If in GA authentication context return Some(TxHash) otherwise None."}
|
, { 'AUTH_TX_HASH', 16#75, false, true, true, 3, [a], auth_tx_hash, {}, variant, "If in GA authentication context return Some(TxHash) otherwise None."}
|
||||||
|
|
||||||
, { 'BYTES_TO_INT', 16#76, false, true, true, 3, [a,a], bytes_to_int, {bytes}, integer, "Arg0 := bytes_to_int(Arg1)"}
|
, { 'BYTES_TO_INT', 16#76, false, true, true, 3, [a,a], bytes_to_int, {bytes}, integer, "Arg0 := bytes_to_int(Arg1)"}
|
||||||
, { 'BYTES_TO_STR', 16#77, false, true, true, 3, [a,a], bytes_to_str, {bytes}, string, "Arg0 := bytes_to_str(Arg1)"}
|
, { 'BYTES_TO_STR', 16#77, false, true, true, 3, [a,a], bytes_to_str, {bytes}, string, "Arg0 := bytes_to_str(Arg1)"}
|
||||||
@@ -173,10 +173,14 @@ ops_defs() ->
|
|||||||
, { 'ORACLE_CHECK', 16#78, false, false, true, 3, [a,a,a,a], oracle_check, {oracle, typerep, typerep}, bool, "Arg0 := is Arg1 an oracle with the given query (Arg2) and response (Arg3) types"}
|
, { 'ORACLE_CHECK', 16#78, false, false, true, 3, [a,a,a,a], oracle_check, {oracle, typerep, typerep}, bool, "Arg0 := is Arg1 an oracle with the given query (Arg2) and response (Arg3) types"}
|
||||||
, { 'ORACLE_CHECK_QUERY', 16#79, false, false, true, 3, [a,a,a,a,a], oracle_check_query, {oracle, oracle_query, typerep, typerep}, bool, "Arg0 := is Arg2 a query for the oracle Arg1 with the given types (Arg3, Arg4)"}
|
, { 'ORACLE_CHECK_QUERY', 16#79, false, false, true, 3, [a,a,a,a,a], oracle_check_query, {oracle, oracle_query, typerep, typerep}, bool, "Arg0 := is Arg2 a query for the oracle Arg1 with the given types (Arg3, Arg4)"}
|
||||||
|
|
||||||
, { 'IS_ORACLE', 16#7a, false, false, true, 3, [a,a], is_oracle, {address}, bool, "Arg0 := is Arg1 an oracle"}
|
, { 'IS_ORACLE', 16#7a, false, false, true, 3, [a,a], is_oracle, {address}, bool, "Arg0 := is Arg1 an oracle"}
|
||||||
, { 'IS_CONTRACT', 16#7b, false, false, true, 3, [a,a], is_contract, {address}, bool, "Arg0 := is Arg1 a contract"}
|
, { 'IS_CONTRACT', 16#7b, false, false, true, 3, [a,a], is_contract, {address}, bool, "Arg0 := is Arg1 a contract"}
|
||||||
, { 'CREATOR', 16#7c, false, true, true, 3, [a], contract_creator, {}, address, "Arg0 := contract creator"}
|
, { 'IS_PAYABLE', 16#7c, false, false, true, 3, [a,a], is_payable, {address}, bool, "Arg0 := is Arg1 a payable address"}
|
||||||
|
, { 'CREATOR', 16#7d, false, true, true, 3, [a], contract_creator, {}, address, "Arg0 := contract creator"}
|
||||||
|
|
||||||
|
, { 'ECVERIFY_SECP256K1', 16#7e, false, true, true, 1300, [a,a,a,a], ecverify_secp256k1, {bytes, bytes, bytes}, bytes, "Arg0 := ecverify_secp256k1(Hash, Addr, Signature)"}
|
||||||
|
, { 'ECRECOVER_SECP256K1', 16#7f, false, true, true, 1300, [a,a,a], ecrecover_secp256k1, {bytes, bytes}, bytes, "Arg0 := ecrecover_secp256k1(Hash, Signature)"}
|
||||||
|
, { 'AENS_SUBNAME', 16#80, false, false, false, 3, [a,a,a,a], aens_subname, {signature, address, string, map}, none, "Claim subbnames of name in Arg2 from owner Arg1. Arg0 contains delegation signature. Arg3 is map describing subname prefixes to claim and their pointers."}
|
||||||
, { 'DEACTIVATE', 16#fa, false, true, true, 3, [], deactivate, {}, none, "Mark the current contract for deactivation."}
|
, { 'DEACTIVATE', 16#fa, false, true, true, 3, [], deactivate, {}, none, "Mark the current contract for deactivation."}
|
||||||
, { 'ABORT', 16#fb, true, true, true, 3, [a], abort, {string}, none, "Abort execution (dont use all gas) with error message in Arg0."}
|
, { 'ABORT', 16#fb, true, true, true, 3, [a], abort, {string}, none, "Abort execution (dont use all gas) with error message in Arg0."}
|
||||||
, { 'EXIT', 16#fc, true, true, true, 3, [a], exit, {string}, none, "Abort execution (use upp all gas) with error message in Arg0."}
|
, { 'EXIT', 16#fc, true, true, true, 3, [a], exit, {string}, none, "Abort execution (use upp all gas) with error message in Arg0."}
|
||||||
@@ -277,7 +281,7 @@ generate_code_ops(Modulename, SrcDir, Ops) ->
|
|||||||
file:close(File).
|
file:close(File).
|
||||||
|
|
||||||
gen_type(#{type_name := TypeName, type := Type}) ->
|
gen_type(#{type_name := TypeName, type := Type}) ->
|
||||||
lists:flatten(io_lib:format("-type ~-26s :: ~s.\n",
|
lists:flatten(io_lib:format("-type ~-29s :: ~s.\n",
|
||||||
[TypeName, Type])).
|
[TypeName, Type])).
|
||||||
|
|
||||||
gen_fate_code_type(#{type_name := TypeName}) ->
|
gen_fate_code_type(#{type_name := TypeName}) ->
|
||||||
@@ -355,27 +359,27 @@ ops_exports(Module, HrlFile, Exports) ->
|
|||||||
[Module, Exports])).
|
[Module, Exports])).
|
||||||
|
|
||||||
gen_mnemonic(#{opname := Name, macro := Macro}) ->
|
gen_mnemonic(#{opname := Name, macro := Macro}) ->
|
||||||
lists:flatten(io_lib:format("mnemonic(~21s) -> ~21w ;\n",
|
lists:flatten(io_lib:format("mnemonic(~24s) -> ~24w ;\n",
|
||||||
[Macro, Name])).
|
[Macro, Name])).
|
||||||
|
|
||||||
gen_m_to_op(#{opname := Name, macro := Macro}) ->
|
gen_m_to_op(#{opname := Name, macro := Macro}) ->
|
||||||
lists:flatten(io_lib:format("m_to_op(~21w) -> ~21s ;\n",
|
lists:flatten(io_lib:format("m_to_op(~24w) -> ~24s ;\n",
|
||||||
[Name, Macro])).
|
[Name, Macro])).
|
||||||
|
|
||||||
gen_args(#{macro := Macro, arity := Arity}) ->
|
gen_args(#{macro := Macro, arity := Arity}) ->
|
||||||
lists:flatten(io_lib:format("args(~21s) -> ~2w ;\n",
|
lists:flatten(io_lib:format("args(~24s) -> ~2w ;\n",
|
||||||
[Macro, Arity])).
|
[Macro, Arity])).
|
||||||
|
|
||||||
gen_bb(#{macro := Macro, end_bb := EndBB}) ->
|
gen_bb(#{macro := Macro, end_bb := EndBB}) ->
|
||||||
lists:flatten(io_lib:format("end_bb(~21s) -> ~w ;\n",
|
lists:flatten(io_lib:format("end_bb(~24s) -> ~w ;\n",
|
||||||
[Macro, EndBB])).
|
[Macro, EndBB])).
|
||||||
|
|
||||||
gen_in_auth(#{macro := Macro, in_auth := InAuth}) ->
|
gen_in_auth(#{macro := Macro, in_auth := InAuth}) ->
|
||||||
lists:flatten(io_lib:format("in_auth(~21s) -> ~w ;\n",
|
lists:flatten(io_lib:format("in_auth(~24s) -> ~w ;\n",
|
||||||
[Macro, InAuth])).
|
[Macro, InAuth])).
|
||||||
|
|
||||||
gen_allowed_offchain(#{macro := Macro, offchain := Offchain}) ->
|
gen_allowed_offchain(#{macro := Macro, offchain := Offchain}) ->
|
||||||
lists:flatten(io_lib:format("allowed_offchain(~21s) -> ~w ;\n",
|
lists:flatten(io_lib:format("allowed_offchain(~24s) -> ~w ;\n",
|
||||||
[Macro, Offchain])).
|
[Macro, Offchain])).
|
||||||
|
|
||||||
prelude(Doc) ->
|
prelude(Doc) ->
|
||||||
@@ -392,7 +396,7 @@ prelude(Doc) ->
|
|||||||
|
|
||||||
|
|
||||||
gen_defines(#{opname := Name, opcode := OpCode}) ->
|
gen_defines(#{opname := Name, opcode := OpCode}) ->
|
||||||
lists:flatten(io_lib:format("-define(~-26w, 16#~2.16.0b).\n", [Name, OpCode])).
|
lists:flatten(io_lib:format("-define(~-29w, 16#~2.16.0b).\n", [Name, OpCode])).
|
||||||
|
|
||||||
gen([]) ->
|
gen([]) ->
|
||||||
[];
|
[];
|
||||||
@@ -489,28 +493,32 @@ gen_asm_pp(Module, Path, Ops) ->
|
|||||||
file:close(File).
|
file:close(File).
|
||||||
|
|
||||||
gen_format(#{opname := Name}) when (Name =:= 'CALL_R') ->
|
gen_format(#{opname := Name}) when (Name =:= 'CALL_R') ->
|
||||||
io_lib:format("format_op({~w, {immediate, Contract}, {immediate, Function}, Arity, Value}, Symbols) ->\n"
|
io_lib:format("format_op({~w, {immediate, Contract}, {immediate, Function}, ArgType, RetType, Value}, Symbols) ->\n"
|
||||||
" [\"~s \", lookup(Contract, Symbols), \".\", "
|
" [\"~s \", lookup(Contract, Symbols), \".\", "
|
||||||
"lookup(Function, Symbols), \" \", "
|
"lookup(Function, Symbols), \" \", "
|
||||||
"format_arg(a, Arity), \" \", "
|
"format_arg(a, ArgType), \" \", "
|
||||||
|
"format_arg(a, RetType), \" \", "
|
||||||
"format_arg(a, Value)];\n"
|
"format_arg(a, Value)];\n"
|
||||||
"format_op({~w, Contract, {immediate, Function}, Arity, Value}, Symbols) ->\n"
|
"format_op({~w, Contract, {immediate, Function}, ArgType, RetType, Value}, Symbols) ->\n"
|
||||||
"[\"~s \", format_arg(a, Contract), \".\", "
|
"[\"~s \", format_arg(a, Contract), \".\", "
|
||||||
"lookup(Function, Symbols), \" \", "
|
"lookup(Function, Symbols), \" \", "
|
||||||
"format_arg(a, Arity), \" \", "
|
"format_arg(a, ArgType), \" \", "
|
||||||
|
"format_arg(a, RetType), \" \", "
|
||||||
"format_arg(a, Value)];\n",
|
"format_arg(a, Value)];\n",
|
||||||
[Name, atom_to_list(Name), Name, atom_to_list(Name)]);
|
[Name, atom_to_list(Name), Name, atom_to_list(Name)]);
|
||||||
gen_format(#{opname := Name}) when (Name =:= 'CALL_GR') ->
|
gen_format(#{opname := Name}) when (Name =:= 'CALL_GR') ->
|
||||||
io_lib:format("format_op({~w, {immediate, Contract}, {immediate, Function}, Arity, Value, Gas}, Symbols) ->\n"
|
io_lib:format("format_op({~w, {immediate, Contract}, {immediate, Function}, ArgType, RetType, Value, Gas}, Symbols) ->\n"
|
||||||
" [\"~s \", lookup(Contract, Symbols), \".\", "
|
" [\"~s \", lookup(Contract, Symbols), \".\", "
|
||||||
"lookup(Function, Symbols), \" \", "
|
"lookup(Function, Symbols), \" \", "
|
||||||
"format_arg(a, Arity), \" \", "
|
"format_arg(a, ArgType), \" \", "
|
||||||
|
"format_arg(a, RetType), \" \", "
|
||||||
"format_arg(a, Value), \" \", "
|
"format_arg(a, Value), \" \", "
|
||||||
"format_arg(a, Gas)];\n"
|
"format_arg(a, Gas)];\n"
|
||||||
"format_op({~w, Contract, {immediate, Function}, Arity, Value, Gas}, Symbols) ->\n"
|
"format_op({~w, Contract, {immediate, Function}, ArgType, RetType, Value, Gas}, Symbols) ->\n"
|
||||||
"[\"~s \", format_arg(a, Contract), \".\", "
|
"[\"~s \", format_arg(a, Contract), \".\", "
|
||||||
"lookup(Function, Symbols), \" \", "
|
"lookup(Function, Symbols), \" \", "
|
||||||
"format_arg(a, Arity), \" \", "
|
"format_arg(a, ArgType), \" \", "
|
||||||
|
"format_arg(a, RetType), \" \", "
|
||||||
"format_arg(a, Value), \" \", "
|
"format_arg(a, Value), \" \", "
|
||||||
"format_arg(a, Gas)];\n",
|
"format_arg(a, Gas)];\n",
|
||||||
[Name, atom_to_list(Name), Name, atom_to_list(Name)]);
|
[Name, atom_to_list(Name), Name, atom_to_list(Name)]);
|
||||||
@@ -756,4 +764,3 @@ format_arg_doc({is,_N}) -> "Identifier";
|
|||||||
format_arg_doc({ii,_N}) -> "Integer";
|
format_arg_doc({ii,_N}) -> "Integer";
|
||||||
format_arg_doc({li,_N}) -> "[Integers]";
|
format_arg_doc({li,_N}) -> "[Integers]";
|
||||||
format_arg_doc({t,_N}) -> "Type".
|
format_arg_doc({t,_N}) -> "Type".
|
||||||
|
|
||||||
|
|||||||
+11
-7
@@ -28,17 +28,19 @@
|
|||||||
-define(STORE_MAP_THRESHOLD, 500).
|
-define(STORE_MAP_THRESHOLD, 500).
|
||||||
|
|
||||||
-type fate_value() :: aeb_fate_data:fate_type().
|
-type fate_value() :: aeb_fate_data:fate_type().
|
||||||
|
-type fate_value_or_tombstone() :: fate_value() | ?FATE_MAP_TOMBSTONE.
|
||||||
-type id() :: integer().
|
-type id() :: integer().
|
||||||
-type used_ids() :: list(id()).
|
-type used_ids() :: list(id()).
|
||||||
-type maps() :: #{ id() => aeb_fate_data:fate_map() | aeb_fate_data:fate_store_map() }.
|
-type maps() :: #{ id() => aeb_fate_data:fate_map() | aeb_fate_data:fate_store_map() }.
|
||||||
|
|
||||||
%% -- Allocating store maps --------------------------------------------------
|
%% -- Allocating store maps --------------------------------------------------
|
||||||
|
|
||||||
-spec allocate_store_maps(used_ids(), [fate_value()]) -> {[fate_value()], maps()}.
|
-spec allocate_store_maps(used_ids(), [fate_value_or_tombstone()]) -> {[fate_value_or_tombstone()], maps()}.
|
||||||
allocate_store_maps(Used, Vals) ->
|
allocate_store_maps(Used, Vals) ->
|
||||||
{_Used, Vals1, Maps} = allocate_store_maps_l(Used, Vals, #{}),
|
{_Used, Vals1, Maps} = allocate_store_maps_l(Used, Vals, #{}),
|
||||||
{Vals1, Maps}.
|
{Vals1, Maps}.
|
||||||
|
|
||||||
|
allocate_store_maps(Used, ?FATE_MAP_TOMBSTONE = Val, Maps) -> {Used, Val, Maps};
|
||||||
allocate_store_maps(Used, ?FATE_TRUE = Val, Maps) -> {Used, Val, Maps};
|
allocate_store_maps(Used, ?FATE_TRUE = Val, Maps) -> {Used, Val, Maps};
|
||||||
allocate_store_maps(Used, ?FATE_FALSE = Val, Maps) -> {Used, Val, Maps};
|
allocate_store_maps(Used, ?FATE_FALSE = Val, Maps) -> {Used, Val, Maps};
|
||||||
allocate_store_maps(Used, ?FATE_UNIT = Val, Maps) -> {Used, Val, Maps};
|
allocate_store_maps(Used, ?FATE_UNIT = Val, Maps) -> {Used, Val, Maps};
|
||||||
@@ -74,8 +76,8 @@ allocate_store_maps(Used, ?FATE_STORE_MAP(Cache, _Id) = Val, Maps) when Cache =:
|
|||||||
{Used, Val, Maps};
|
{Used, Val, Maps};
|
||||||
allocate_store_maps(Used, ?FATE_STORE_MAP(Cache, Id), Maps) ->
|
allocate_store_maps(Used, ?FATE_STORE_MAP(Cache, Id), Maps) ->
|
||||||
{NewId, Used1} = next_id(Used),
|
{NewId, Used1} = next_id(Used),
|
||||||
{Used1, Cache1, Maps1} = allocate_store_maps_m(Used1, Cache, Maps),
|
{Used2, Cache1, Maps1} = allocate_store_maps_m(Used1, Cache, Maps),
|
||||||
{Used1, ?FATE_STORE_MAP(#{}, NewId), Maps1#{NewId => ?FATE_STORE_MAP(Cache1, Id)}}.
|
{Used2, ?FATE_STORE_MAP(#{}, NewId), Maps1#{NewId => ?FATE_STORE_MAP(Cache1, Id)}}.
|
||||||
|
|
||||||
allocate_store_maps_l(Used, [], Maps) -> {Used, [], Maps};
|
allocate_store_maps_l(Used, [], Maps) -> {Used, [], Maps};
|
||||||
allocate_store_maps_l(Used, [H | T], Maps) ->
|
allocate_store_maps_l(Used, [H | T], Maps) ->
|
||||||
@@ -93,7 +95,8 @@ allocate_store_maps_m(Used, Val, Maps) ->
|
|||||||
|
|
||||||
-type unfold_fun() :: fun((id()) -> aeb_fate_data:fate_map()).
|
-type unfold_fun() :: fun((id()) -> aeb_fate_data:fate_map()).
|
||||||
|
|
||||||
-spec unfold_store_maps(unfold_fun(), fate_value()) -> fate_value().
|
-spec unfold_store_maps(unfold_fun(), fate_value_or_tombstone()) -> fate_value_or_tombstone().
|
||||||
|
unfold_store_maps(_Unfold, ?FATE_MAP_TOMBSTONE = Val) -> Val;
|
||||||
unfold_store_maps(_Unfold, ?FATE_TRUE = Val) -> Val;
|
unfold_store_maps(_Unfold, ?FATE_TRUE = Val) -> Val;
|
||||||
unfold_store_maps(_Unfold, ?FATE_FALSE = Val) -> Val;
|
unfold_store_maps(_Unfold, ?FATE_FALSE = Val) -> Val;
|
||||||
unfold_store_maps(_Unfold, ?FATE_UNIT = Val) -> Val;
|
unfold_store_maps(_Unfold, ?FATE_UNIT = Val) -> Val;
|
||||||
@@ -119,7 +122,8 @@ unfold_store_maps(Unfold, Val) when ?IS_FATE_MAP(Val) ->
|
|||||||
?MAKE_FATE_MAP(unfold_store_maps_m(Unfold, ?FATE_MAP_VALUE(Val)));
|
?MAKE_FATE_MAP(unfold_store_maps_m(Unfold, ?FATE_MAP_VALUE(Val)));
|
||||||
unfold_store_maps(Unfold, ?FATE_STORE_MAP(Cache, Id)) ->
|
unfold_store_maps(Unfold, ?FATE_STORE_MAP(Cache, Id)) ->
|
||||||
StoreMap = Unfold(Id),
|
StoreMap = Unfold(Id),
|
||||||
maps:fold(fun write_cache/3, unfold_store_maps(Unfold, StoreMap), Cache).
|
maps:fold(fun write_cache/3, unfold_store_maps(Unfold, StoreMap),
|
||||||
|
unfold_store_maps_m(Unfold, Cache)).
|
||||||
|
|
||||||
unfold_store_maps_l(Unfold, Vals) ->
|
unfold_store_maps_l(Unfold, Vals) ->
|
||||||
[ unfold_store_maps(Unfold, Val) || Val <- Vals ].
|
[ unfold_store_maps(Unfold, Val) || Val <- Vals ].
|
||||||
@@ -134,7 +138,7 @@ write_cache(Key, Val, Map) ->
|
|||||||
|
|
||||||
%% -- Reference counting -----------------------------------------------------
|
%% -- Reference counting -----------------------------------------------------
|
||||||
|
|
||||||
-type refcount() :: #{id() => pos_integer()}.
|
-type refcount() :: #{id() => integer()}.
|
||||||
|
|
||||||
-spec refcount_zero() -> refcount().
|
-spec refcount_zero() -> refcount().
|
||||||
refcount_zero() -> #{}.
|
refcount_zero() -> #{}.
|
||||||
@@ -159,7 +163,7 @@ has_store_maps(Val) ->
|
|||||||
-spec refcount(fate_value()) -> refcount().
|
-spec refcount(fate_value()) -> refcount().
|
||||||
refcount(Val) -> refcount(Val, #{}).
|
refcount(Val) -> refcount(Val, #{}).
|
||||||
|
|
||||||
-spec refcount(fate_value(), refcount()) -> refcount().
|
-spec refcount(fate_value_or_tombstone(), refcount()) -> refcount().
|
||||||
refcount(?FATE_MAP_TOMBSTONE, Count) -> Count;
|
refcount(?FATE_MAP_TOMBSTONE, Count) -> Count;
|
||||||
refcount(?FATE_TRUE, Count) -> Count;
|
refcount(?FATE_TRUE, Count) -> Count;
|
||||||
refcount(?FATE_FALSE, Count) -> Count;
|
refcount(?FATE_FALSE, Count) -> Count;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
;; CONTRACT all_instructions
|
;; CONTRACT all_instructions
|
||||||
|
|
||||||
;; Dont expect this contract to typecheck or run.
|
;; Dont expect this contract to typecheck or run.
|
||||||
;; Just used to check assembler rountrip of all instructions.
|
;; Just used to check assembler roundtrip of all instructions.
|
||||||
|
|
||||||
FUNCTION foo () : {tuple, []}
|
FUNCTION foo () : {tuple, []}
|
||||||
RETURN
|
RETURN
|
||||||
@@ -224,7 +224,13 @@ FUNCTION foo () : {tuple, []}
|
|||||||
|
|
||||||
AENS_REVOKE
|
AENS_REVOKE
|
||||||
|
|
||||||
ECVERIFY
|
ECRECOVER_SECP256K1
|
||||||
|
|
||||||
|
VERIFY_SIG
|
||||||
|
|
||||||
|
VERIFY_SIG_SECP256K1
|
||||||
|
|
||||||
|
ECVERIFY_SECP256K1
|
||||||
|
|
||||||
SHA3 a
|
SHA3 a
|
||||||
|
|
||||||
@@ -247,3 +253,9 @@ FUNCTION foo () : {tuple, []}
|
|||||||
AUTH_TX_HASH
|
AUTH_TX_HASH
|
||||||
|
|
||||||
CONTRACT_TO_ADDRESS @ct_nv5B93FPzRHrGNmMdTDfGdd5xGZvep3MVSpJqzcQmMp59bBCv
|
CONTRACT_TO_ADDRESS @ct_nv5B93FPzRHrGNmMdTDfGdd5xGZvep3MVSpJqzcQmMp59bBCv
|
||||||
|
|
||||||
|
IS_ORACLE @ak_nv5B93FPzRHrGNmMdTDfGdd5xGZvep3MVSpJqzcQmMp59bBCv
|
||||||
|
|
||||||
|
IS_CONTRACT @ak_nv5B93FPzRHrGNmMdTDfGdd5xGZvep3MVSpJqzcQmMp59bBCv
|
||||||
|
|
||||||
|
IS_PAYABLE @ak_nv5B93FPzRHrGNmMdTDfGdd5xGZvep3MVSpJqzcQmMp59bBCv
|
||||||
|
|||||||
@@ -28,11 +28,11 @@ FUNCTION tailcall(integer) -> integer
|
|||||||
INCA
|
INCA
|
||||||
CALL_T "inc"
|
CALL_T "inc"
|
||||||
|
|
||||||
FUNCTION remote_call(integer) : integer
|
;; FUNCTION remote_call(integer) : integer
|
||||||
PUSH arg0
|
;; PUSH arg0
|
||||||
CALL_R remote.add_five 1 0
|
;; CALL_R remote.add_five {tuple, [integer]} integer 0 ;; typereps don't parse
|
||||||
INCA
|
;; INCA
|
||||||
RETURN
|
;; RETURN
|
||||||
|
|
||||||
;; Test the code from the shell
|
;; Test the code from the shell
|
||||||
;; _build/default/rel/aessembler/bin/aessembler console
|
;; _build/default/rel/aessembler/bin/aessembler console
|
||||||
|
|||||||
Reference in New Issue
Block a user