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_TUPLE_T, {tuple, tuple()}).
|
||||
-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_LIST(X), (is_list(X))).
|
||||
|
||||
+11
-7
@@ -176,6 +176,7 @@
|
||||
-define(PRIM_CALL_AENS_UPDATE, 203).
|
||||
-define(PRIM_CALL_AENS_TRANSFER, 204).
|
||||
-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_MAP_EMPTY, 300).
|
||||
@@ -186,13 +187,15 @@
|
||||
-define(PRIM_CALL_MAP_TOLIST, 305).
|
||||
|
||||
-define(PRIM_CALL_IN_CRYPTO_RANGE(__TTYPE__), (((__TTYPE__) > 399) andalso ((__TTYPE__) < 500))).
|
||||
-define(PRIM_CALL_CRYPTO_ECVERIFY, 400).
|
||||
-define(PRIM_CALL_CRYPTO_SHA3, 401).
|
||||
-define(PRIM_CALL_CRYPTO_SHA256, 402).
|
||||
-define(PRIM_CALL_CRYPTO_BLAKE2B, 403).
|
||||
-define(PRIM_CALL_CRYPTO_SHA256_STRING, 404).
|
||||
-define(PRIM_CALL_CRYPTO_BLAKE2B_STRING, 405).
|
||||
-define(PRIM_CALL_CRYPTO_ECVERIFY_SECP256K1, 410).
|
||||
-define(PRIM_CALL_CRYPTO_VERIFY_SIG, 400).
|
||||
-define(PRIM_CALL_CRYPTO_SHA3, 401).
|
||||
-define(PRIM_CALL_CRYPTO_SHA256, 402).
|
||||
-define(PRIM_CALL_CRYPTO_BLAKE2B, 403).
|
||||
-define(PRIM_CALL_CRYPTO_SHA256_STRING, 404).
|
||||
-define(PRIM_CALL_CRYPTO_BLAKE2B_STRING, 405).
|
||||
-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_AUTH_TX_HASH, 500).
|
||||
@@ -200,3 +203,4 @@
|
||||
-define(PRIM_CALL_IN_ADDRESS_RANGE(__TTYPE__), (((__TTYPE__) > 599) andalso ((__TTYPE__) < 700))).
|
||||
-define(PRIM_CALL_ADDR_IS_ORACLE, 600).
|
||||
-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,
|
||||
[ ?EQC_EUNIT(aefate_type_eqc, prop_roundtrip, 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)
|
||||
]}.
|
||||
|
||||
@@ -77,7 +77,7 @@ prop_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) ->
|
||||
@@ -85,7 +85,8 @@ fate_code(Failure) ->
|
||||
?LET({FMap, SMap, AMap},
|
||||
{non_empty(map(if Failure == 1 -> binary(1);
|
||||
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))},
|
||||
aeb_fate_code:update_annotations(
|
||||
|
||||
+52
-10
@@ -10,6 +10,7 @@
|
||||
-module(aefate_eqc).
|
||||
|
||||
-include_lib("eqc/include/eqc.hrl").
|
||||
-include("../include/aeb_fate_data.hrl").
|
||||
|
||||
-compile([export_all, nowarn_export_all]).
|
||||
|
||||
@@ -23,7 +24,7 @@ prop_roundtrip() ->
|
||||
end)).
|
||||
|
||||
prop_format_scan() ->
|
||||
?FORALL(FateData, fate_data(),
|
||||
?FORALL(FateData, fate_data([variant, map]),
|
||||
?WHENFAIL(eqc:format("Trying to format ~p failed~n", [FateData]),
|
||||
begin
|
||||
String = aeb_fate_data:format(FateData),
|
||||
@@ -43,6 +44,18 @@ prop_serializes() ->
|
||||
{size, size(Binary) < 500000}]))
|
||||
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() ->
|
||||
in_parallel(
|
||||
?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() ->
|
||||
?FORALL(Items, vector(3, fate_data()),
|
||||
?FORALL(Items, vector(3, fate_data([variant, map])),
|
||||
begin
|
||||
%% Use lt to take minimum
|
||||
Min = lt_min(Items),
|
||||
Max = lt_max(Items),
|
||||
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).
|
||||
|
||||
lt_min([X, Y | Rest]) ->
|
||||
@@ -88,18 +102,24 @@ prop_idempotent() ->
|
||||
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() ->
|
||||
?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() ->
|
||||
?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(
|
||||
frequency(
|
||||
[{5, oneof([fate_integer(), fate_boolean(), fate_nil(), fate_unit()])},
|
||||
{1, oneof([fate_string(), fate_address(), fate_bytes(), fate_contract(),
|
||||
fate_oracle(), fate_oracle_q(), fate_bits(), fate_channel()])}]));
|
||||
[{50, oneof([fate_integer(), fate_boolean(), fate_nil(), fate_unit()])},
|
||||
{10, oneof([fate_string(), fate_address(), fate_bytes(), fate_contract(),
|
||||
fate_oracle(), fate_oracle_q(), fate_bits(), fate_channel()])}] ++
|
||||
[{1, fate_store_map()} || lists:member(store_map, Options)]));
|
||||
fate_data(Size, Options) ->
|
||||
?LAZY(
|
||||
oneof([fate_data(0, Options),
|
||||
@@ -148,9 +168,20 @@ fate_list(Size, Options) ->
|
||||
fate_map(Size, Options) ->
|
||||
?LET(N, choose(0, 6),
|
||||
?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))))))).
|
||||
|
||||
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() ->
|
||||
?SUCHTHAT(S, utf8(), [ quote || <<34>> <= S ] == []).
|
||||
|
||||
@@ -167,3 +198,14 @@ injection(Binary) ->
|
||||
|
||||
is_empty(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).
|
||||
|
||||
-export([ create_calldata/4
|
||||
, check_calldata/2
|
||||
, function_type_info/3
|
||||
, check_calldata/3
|
||||
, function_type_info/4
|
||||
, function_type_hash/3
|
||||
, arg_typerep_from_function/2
|
||||
, type_hash_from_function_name/2
|
||||
, typereps_from_type_hash/2
|
||||
, function_name_from_type_hash/2
|
||||
, get_function_hash_from_calldata/1
|
||||
, is_payable/2
|
||||
, abi_version/0
|
||||
]).
|
||||
|
||||
@@ -27,6 +28,7 @@
|
||||
-type typerep() :: aeb_aevm_data:type().
|
||||
-type function_type_info() :: { FunctionHash :: hash()
|
||||
, FunctionName :: function_name()
|
||||
, Payable :: boolean()
|
||||
, ArgType :: 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)}),
|
||||
{ok, Data}.
|
||||
|
||||
-spec check_calldata(binary(), type_info()) ->
|
||||
-spec check_calldata(binary(), type_info(), boolean()) ->
|
||||
{'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
|
||||
case get_function_hash_from_calldata(CallData) of
|
||||
{ok, Hash} ->
|
||||
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;
|
||||
check_calldata(Hash, CallData, TypeInfo, CheckPayable);
|
||||
{error, _What} ->
|
||||
{error, bad_call_data}
|
||||
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()) ->
|
||||
{ok, binary()} | {error, term()}.
|
||||
get_function_hash_from_calldata(CallData) ->
|
||||
@@ -86,12 +98,13 @@ get_function_hash_from_calldata(CallData) ->
|
||||
%%%===================================================================
|
||||
%%% 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(Name, ArgTypes, OutType) ->
|
||||
function_type_info(Name, Payable, ArgTypes, OutType) ->
|
||||
ArgType = {tuple, ArgTypes},
|
||||
{ function_type_hash(Name, ArgType, OutType)
|
||||
, Name
|
||||
, Payable
|
||||
, aeb_heap:to_binary(ArgType)
|
||||
, 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'}.
|
||||
arg_typerep_from_function(Function, TypeInfo) ->
|
||||
case lists:keyfind(Function, 2, TypeInfo) of
|
||||
{_TypeHash, Function, ArgTypeBin,_OutTypeBin} ->
|
||||
case aeb_heap:from_binary(typerep, ArgTypeBin) of
|
||||
{ok, ArgType} -> {ok, ArgType};
|
||||
{error,_} -> {error, bad_type_data}
|
||||
end;
|
||||
{_TypeHash, Function, ArgTypeBin, _OutTypeBin} ->
|
||||
arg_typerep_from_type_binary(ArgTypeBin);
|
||||
{_TypeHash, Function, _Payable, ArgTypeBin, _OutTypeBin} ->
|
||||
arg_typerep_from_type_binary(ArgTypeBin);
|
||||
false ->
|
||||
{error, unknown_function}
|
||||
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()) ->
|
||||
{'ok', typerep(), typerep()} | {'error', 'bad_type_data' | 'unknown_function'}.
|
||||
typereps_from_type_hash(TypeHash, TypeInfo) ->
|
||||
case lists:keyfind(TypeHash, 1, TypeInfo) of
|
||||
{TypeHash,_Function, ArgTypeBin, OutTypeBin} ->
|
||||
case {aeb_heap:from_binary(typerep, ArgTypeBin),
|
||||
aeb_heap:from_binary(typerep, OutTypeBin)} of
|
||||
{{ok, ArgType}, {ok, OutType}} -> {ok, ArgType, OutType};
|
||||
{_, _} -> {error, bad_type_data}
|
||||
end;
|
||||
{TypeHash, _Function, ArgTypeBin, OutTypeBin} ->
|
||||
typereps_from_type_binaries(ArgTypeBin, OutTypeBin);
|
||||
{TypeHash, _Function, _Payable, ArgTypeBin, OutTypeBin} ->
|
||||
typereps_from_type_binaries(ArgTypeBin, OutTypeBin);
|
||||
false ->
|
||||
{error, unknown_function}
|
||||
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()) ->
|
||||
{'ok', function_name()}
|
||||
| {'error', 'unknown_function'}.
|
||||
function_name_from_type_hash(TypeHash, TypeInfo) ->
|
||||
case lists:keyfind(TypeHash, 1, TypeInfo) of
|
||||
{TypeHash, Function,_ArgTypeBin,_OutTypeBin} ->
|
||||
{TypeHash, Function, _ArgTypeBin, _OutTypeBin} ->
|
||||
{ok, Function};
|
||||
{TypeHash, Function, _Payable, _ArgTypeBin, _OutTypeBin} ->
|
||||
{ok, Function};
|
||||
false ->
|
||||
{error, unknown_function}
|
||||
@@ -149,8 +173,22 @@ function_name_from_type_hash(TypeHash, TypeInfo) ->
|
||||
| {'error', 'unknown_function'}.
|
||||
type_hash_from_function_name(Name, TypeInfo) ->
|
||||
case lists:keyfind(Name, 2, TypeInfo) of
|
||||
{TypeHash, Name,_ArgTypeBin,_OutTypeBin} ->
|
||||
{TypeHash, Name, _ArgTypeBin, _OutTypeBin} ->
|
||||
{ok, TypeHash};
|
||||
{TypeHash, Name, _Payable, _ArgTypeBin, _OutTypeBin} ->
|
||||
{ok, TypeHash};
|
||||
false ->
|
||||
{error, unknown_function}
|
||||
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
|
||||
undefined ->
|
||||
{error, no_function_matching_function_hash};
|
||||
{{ArgTypes, RetType}, _Code} ->
|
||||
{_Attrs, {ArgTypes, RetType}, _Code} ->
|
||||
{ok, ArgTypes, RetType}
|
||||
end.
|
||||
|
||||
@@ -153,7 +153,7 @@ format_functions(Functions, Symbols) ->
|
||||
lists:sort(maps:to_list(CodeMap)),
|
||||
Symbols)
|
||||
||
|
||||
{Name, {Sig, CodeMap}} <- maps:to_list(Functions)].
|
||||
{Name, {_Attrs, Sig, CodeMap}} <- maps:to_list(Functions)].
|
||||
|
||||
|
||||
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),
|
||||
BodyByteCode = aeb_fate_code:serialize_code(lists:reverse(Code)),
|
||||
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 }
|
||||
, fate_code => FateCode1}.
|
||||
|
||||
|
||||
+42
-21
@@ -11,7 +11,7 @@
|
||||
, deserialize/1
|
||||
, functions/1
|
||||
, insert_annotation/4
|
||||
, insert_fun/4
|
||||
, insert_fun/5
|
||||
, insert_symbol/2
|
||||
, new/0
|
||||
, serialize/1
|
||||
@@ -72,9 +72,9 @@ symbol_identifier(Bin) ->
|
||||
{ok, <<X:4/binary,_/binary>> } = eblake2:blake2b(?HASH_BYTES, Bin),
|
||||
X.
|
||||
|
||||
insert_fun(Name, {ArgType, RetType}, #{} = BBs, FCode) ->
|
||||
insert_fun(Name, Attrs, {ArgType, RetType}, #{} = BBs, 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) ->
|
||||
ID = symbol_identifier(Name),
|
||||
@@ -128,10 +128,17 @@ to_hexstring(ByteList) ->
|
||||
serialize_functions(#fcode{ functions = Functions }) ->
|
||||
%% Sort the functions on name to get a canonical serialisation.
|
||||
iolist_to_binary(
|
||||
lists:foldr(fun({Id, {Sig, C}}, Acc) ->
|
||||
[[?FUNCTION, Id, serialize_signature(Sig), serialize_bbs(C)] | Acc]
|
||||
lists:foldr(fun({Id, {Attrs, Sig, C}}, Acc) ->
|
||||
[[?FUNCTION, Id, serialize_attributes(Attrs), serialize_signature(Sig), serialize_bbs(C)] | Acc]
|
||||
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}) ->
|
||||
[aeb_fate_encoding:serialize_type({tuple, Args}) |
|
||||
aeb_fate_encoding:serialize_type(RetType)].
|
||||
@@ -139,7 +146,7 @@ serialize_signature({Args, RetType}) ->
|
||||
serialize_symbol_table(#fcode{ symbols = 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)).
|
||||
|
||||
serialize_bbs(#{} = BBs) ->
|
||||
@@ -166,8 +173,8 @@ serialize_op(Op) ->
|
||||
|
||||
sanity_check(#fcode{ functions = Funs }) ->
|
||||
_ = [ case Def of
|
||||
{_, BBs} when byte_size(Id) == 4 -> sanity_check_bbs(BBs);
|
||||
_ -> error({illegal_function_id, Id})
|
||||
{_, _, BBs} when byte_size(Id) == 4 -> sanity_check_bbs(BBs);
|
||||
_ -> error({illegal_function_id, Id})
|
||||
end || {Id, Def} <- maps:to_list(Funs) ],
|
||||
ok.
|
||||
|
||||
@@ -303,33 +310,35 @@ deserialize_functions(<<?FUNCTION:8, A, B, C, D, Rest/binary>>,
|
||||
, bb := 0
|
||||
, current_bb_code := []
|
||||
} = Env) ->
|
||||
{Sig, Rest2} = deserialize_signature(Rest),
|
||||
Env2 = Env#{function => {<<A,B,C,D>>, Sig}},
|
||||
deserialize_functions(Rest2, Env2);
|
||||
{Attrs, Rest2} = deserialize_attributes(Rest),
|
||||
{Sig, Rest3} = deserialize_signature(Rest2),
|
||||
Env2 = Env#{function => {<<A,B,C,D>>, Attrs, Sig}},
|
||||
deserialize_functions(Rest3, Env2);
|
||||
deserialize_functions(<<?FUNCTION:8, A, B, C, D, Rest/binary>>,
|
||||
#{ function := {F, Sig}
|
||||
#{ function := {F, Attrs, Sig}
|
||||
, bb := BB
|
||||
, current_bb_code := Code
|
||||
, code := Program
|
||||
, functions := Funs} = Env) ->
|
||||
{NewSig, Rest2} = deserialize_signature(Rest),
|
||||
{NewAttrs, Rest2} = deserialize_attributes(Rest),
|
||||
{NewSig, Rest3} = deserialize_signature(Rest2),
|
||||
case Code of
|
||||
[] ->
|
||||
Env2 = Env#{ bb => 0
|
||||
, current_bb_code => []
|
||||
, function => {<<A,B,C,D>>, NewSig}
|
||||
, function => {<<A,B,C,D>>, NewAttrs, NewSig}
|
||||
, code => #{}
|
||||
, functions => Funs#{F => {Sig, Program}}},
|
||||
deserialize_functions(Rest2, Env2);
|
||||
, functions => Funs#{F => {Attrs, Sig, Program}}},
|
||||
deserialize_functions(Rest3, Env2);
|
||||
_ ->
|
||||
Env2 = Env#{ bb => 0
|
||||
, current_bb_code => []
|
||||
, function => {<<A,B,C,D>>, NewSig}
|
||||
, function => {<<A,B,C,D>>, NewAttrs, NewSig}
|
||||
, code => #{}
|
||||
, functions =>
|
||||
Funs#{F => {Sig,
|
||||
Funs#{F => {Attrs, Sig,
|
||||
Program#{ BB => lists:reverse(Code)}}}},
|
||||
deserialize_functions(Rest2, Env2)
|
||||
deserialize_functions(Rest3, Env2)
|
||||
end;
|
||||
deserialize_functions(<<_Op:8, _Rest/binary>>,
|
||||
#{ function := none }) ->
|
||||
@@ -351,7 +360,7 @@ deserialize_functions(<<Op:8, Rest/binary>>,
|
||||
deserialize_functions(<<>>, #{ function := none
|
||||
, functions := Funs}) ->
|
||||
Funs;
|
||||
deserialize_functions(<<>>, #{ function := {F, Sig}
|
||||
deserialize_functions(<<>>, #{ function := {F, Attrs, Sig}
|
||||
, bb := BB
|
||||
, current_bb_code := Code
|
||||
, code := Program
|
||||
@@ -361,7 +370,7 @@ deserialize_functions(<<>>, #{ function := {F, Sig}
|
||||
[] -> Program;
|
||||
_ -> Program#{ BB => lists:reverse(Code)}
|
||||
end,
|
||||
Funs#{F => {Sig, FunctionCode}}.
|
||||
Funs#{F => {Attrs, Sig, FunctionCode}}.
|
||||
|
||||
deserialize_op(Op, Rest, Code) ->
|
||||
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, 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) ->
|
||||
{{tuple, Args}, Rest} = aeb_fate_encoding:deserialize_type(Binary),
|
||||
{RetType, Rest2} = aeb_fate_encoding:deserialize_type(Rest),
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
-type fate_variant() :: ?FATE_VARIANT_T.
|
||||
-type fate_tuple() :: ?FATE_TUPLE_T.
|
||||
-type fate_bits() :: ?FATE_BITS_T.
|
||||
-type fate_typerep() :: ?FATE_TYPEREP_T.
|
||||
|
||||
-type fate_type_type() :: integer
|
||||
| boolean
|
||||
@@ -54,7 +55,8 @@
|
||||
| fate_channel()
|
||||
| fate_variant()
|
||||
| fate_map()
|
||||
| fate_bits().
|
||||
| fate_bits()
|
||||
| fate_typerep().
|
||||
|
||||
-export_type([fate_type/0
|
||||
, fate_boolean/0
|
||||
|
||||
@@ -487,5 +487,11 @@ sort(KVList) ->
|
||||
|
||||
valid_key_type(K) when ?IS_FATE_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) ->
|
||||
true.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
, generate/0
|
||||
, generate_documentation/1
|
||||
, get_ops/0
|
||||
, test_asm_generator/1]).
|
||||
, test_asm_generator/1 ]).
|
||||
|
||||
gen_and_halt([SrcDirArg, IncludeDirArg]) ->
|
||||
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."}
|
||||
, { '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_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."}
|
||||
, { '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."}
|
||||
, { '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."}
|
||||
@@ -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."}
|
||||
, { '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)"}
|
||||
, { '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', 16#72, false, true, true, 1300, [a,a,a,a], verify_sig, {bytes, address, bytes}, boolean, "Arg0 := verify_sig(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"}
|
||||
, { 'AUTH_TX_HASH', 16#75, false, true, true, 3, [a], auth_tx_hash, {}, variant, "If in GA authentication context return Some(TxHash) otherwise None."}
|
||||
, { '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."}
|
||||
|
||||
, { '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)"}
|
||||
@@ -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_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_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_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_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."}
|
||||
, { '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."}
|
||||
@@ -277,7 +281,7 @@ generate_code_ops(Modulename, SrcDir, Ops) ->
|
||||
file:close(File).
|
||||
|
||||
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])).
|
||||
|
||||
gen_fate_code_type(#{type_name := TypeName}) ->
|
||||
@@ -355,27 +359,27 @@ ops_exports(Module, HrlFile, Exports) ->
|
||||
[Module, Exports])).
|
||||
|
||||
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])).
|
||||
|
||||
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])).
|
||||
|
||||
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])).
|
||||
|
||||
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])).
|
||||
|
||||
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])).
|
||||
|
||||
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])).
|
||||
|
||||
prelude(Doc) ->
|
||||
@@ -392,7 +396,7 @@ prelude(Doc) ->
|
||||
|
||||
|
||||
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([]) ->
|
||||
[];
|
||||
@@ -489,28 +493,32 @@ gen_asm_pp(Module, Path, Ops) ->
|
||||
file:close(File).
|
||||
|
||||
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), \".\", "
|
||||
"lookup(Function, Symbols), \" \", "
|
||||
"format_arg(a, Arity), \" \", "
|
||||
"format_arg(a, ArgType), \" \", "
|
||||
"format_arg(a, RetType), \" \", "
|
||||
"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), \".\", "
|
||||
"lookup(Function, Symbols), \" \", "
|
||||
"format_arg(a, Arity), \" \", "
|
||||
"format_arg(a, ArgType), \" \", "
|
||||
"format_arg(a, RetType), \" \", "
|
||||
"format_arg(a, Value)];\n",
|
||||
[Name, atom_to_list(Name), Name, atom_to_list(Name)]);
|
||||
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), \".\", "
|
||||
"lookup(Function, Symbols), \" \", "
|
||||
"format_arg(a, Arity), \" \", "
|
||||
"format_arg(a, ArgType), \" \", "
|
||||
"format_arg(a, RetType), \" \", "
|
||||
"format_arg(a, Value), \" \", "
|
||||
"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), \".\", "
|
||||
"lookup(Function, Symbols), \" \", "
|
||||
"format_arg(a, Arity), \" \", "
|
||||
"format_arg(a, ArgType), \" \", "
|
||||
"format_arg(a, RetType), \" \", "
|
||||
"format_arg(a, Value), \" \", "
|
||||
"format_arg(a, Gas)];\n",
|
||||
[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({li,_N}) -> "[Integers]";
|
||||
format_arg_doc({t,_N}) -> "Type".
|
||||
|
||||
|
||||
+11
-7
@@ -28,17 +28,19 @@
|
||||
-define(STORE_MAP_THRESHOLD, 500).
|
||||
|
||||
-type fate_value() :: aeb_fate_data:fate_type().
|
||||
-type fate_value_or_tombstone() :: fate_value() | ?FATE_MAP_TOMBSTONE.
|
||||
-type id() :: integer().
|
||||
-type used_ids() :: list(id()).
|
||||
-type maps() :: #{ id() => aeb_fate_data:fate_map() | aeb_fate_data:fate_store_map() }.
|
||||
|
||||
%% -- 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) ->
|
||||
{_Used, Vals1, Maps} = allocate_store_maps_l(Used, Vals, #{}),
|
||||
{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_FALSE = 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};
|
||||
allocate_store_maps(Used, ?FATE_STORE_MAP(Cache, Id), Maps) ->
|
||||
{NewId, Used1} = next_id(Used),
|
||||
{Used1, Cache1, Maps1} = allocate_store_maps_m(Used1, Cache, Maps),
|
||||
{Used1, ?FATE_STORE_MAP(#{}, NewId), Maps1#{NewId => ?FATE_STORE_MAP(Cache1, Id)}}.
|
||||
{Used2, Cache1, Maps1} = allocate_store_maps_m(Used1, Cache, Maps),
|
||||
{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, [H | T], Maps) ->
|
||||
@@ -93,7 +95,8 @@ allocate_store_maps_m(Used, Val, Maps) ->
|
||||
|
||||
-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_FALSE = 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)));
|
||||
unfold_store_maps(Unfold, ?FATE_STORE_MAP(Cache, 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(Unfold, Val) || Val <- Vals ].
|
||||
@@ -134,7 +138,7 @@ write_cache(Key, Val, Map) ->
|
||||
|
||||
%% -- Reference counting -----------------------------------------------------
|
||||
|
||||
-type refcount() :: #{id() => pos_integer()}.
|
||||
-type refcount() :: #{id() => integer()}.
|
||||
|
||||
-spec refcount_zero() -> refcount().
|
||||
refcount_zero() -> #{}.
|
||||
@@ -159,7 +163,7 @@ has_store_maps(Val) ->
|
||||
-spec refcount(fate_value()) -> refcount().
|
||||
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_TRUE, Count) -> Count;
|
||||
refcount(?FATE_FALSE, Count) -> Count;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
;; CONTRACT all_instructions
|
||||
|
||||
;; 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, []}
|
||||
RETURN
|
||||
@@ -224,7 +224,13 @@ FUNCTION foo () : {tuple, []}
|
||||
|
||||
AENS_REVOKE
|
||||
|
||||
ECVERIFY
|
||||
ECRECOVER_SECP256K1
|
||||
|
||||
VERIFY_SIG
|
||||
|
||||
VERIFY_SIG_SECP256K1
|
||||
|
||||
ECVERIFY_SECP256K1
|
||||
|
||||
SHA3 a
|
||||
|
||||
@@ -247,3 +253,9 @@ FUNCTION foo () : {tuple, []}
|
||||
AUTH_TX_HASH
|
||||
|
||||
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
|
||||
CALL_T "inc"
|
||||
|
||||
FUNCTION remote_call(integer) : integer
|
||||
PUSH arg0
|
||||
CALL_R remote.add_five 1 0
|
||||
INCA
|
||||
RETURN
|
||||
;; FUNCTION remote_call(integer) : integer
|
||||
;; PUSH arg0
|
||||
;; CALL_R remote.add_five {tuple, [integer]} integer 0 ;; typereps don't parse
|
||||
;; INCA
|
||||
;; RETURN
|
||||
|
||||
;; Test the code from the shell
|
||||
;; _build/default/rel/aessembler/bin/aessembler console
|
||||
|
||||
Reference in New Issue
Block a user