Compare commits

..

1 Commits

Author SHA1 Message Date
sennui adf3664dd0 Add argument to claim tx to enable bidding 2019-08-14 12:08:04 +02:00
16 changed files with 117 additions and 491 deletions
-10
View File
@@ -5,7 +5,6 @@
-define(FATE_LIST_T, list()). -define(FATE_LIST_T, list()).
-define(FATE_UNIT_T, {tuple, {}}). -define(FATE_UNIT_T, {tuple, {}}).
-define(FATE_MAP_T, #{ fate_type() => fate_type() }). -define(FATE_MAP_T, #{ fate_type() => fate_type() }).
-define(FATE_STORE_MAP_T, {store_map, #{ fate_type() => fate_type() | ?FATE_MAP_TOMBSTONE }, integer()}).
-define(FATE_STRING_T, binary()). -define(FATE_STRING_T, binary()).
-define(FATE_ADDRESS_T, {address, <<_:256>>}). -define(FATE_ADDRESS_T, {address, <<_:256>>}).
-define(FATE_BYTES_T(N), {bytes, binary()}). -define(FATE_BYTES_T(N), {bytes, binary()}).
@@ -17,15 +16,10 @@
-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))).
-define(IS_FATE_STRING(X), (is_binary(X))). -define(IS_FATE_STRING(X), (is_binary(X))).
-define(IS_FATE_STORE_MAP(X), (is_tuple(X) andalso tuple_size(X) == 3
andalso store_map == element(1, X)
andalso is_map(element(2, X))
andalso is_integer(element(3, X)))).
-define(IS_FATE_MAP(X), (is_map(X))). -define(IS_FATE_MAP(X), (is_map(X))).
-define(IS_FATE_TUPLE(X), (is_tuple(X) andalso (tuple == element(1, X) andalso is_tuple(element(2, X))))). -define(IS_FATE_TUPLE(X), (is_tuple(X) andalso (tuple == element(1, X) andalso is_tuple(element(2, X))))).
-define(IS_FATE_ADDRESS(X), (is_tuple(X) andalso (address == element(1, X) andalso is_binary(element(2, X))))). -define(IS_FATE_ADDRESS(X), (is_tuple(X) andalso (address == element(1, X) andalso is_binary(element(2, X))))).
@@ -56,8 +50,6 @@
-define(FATE_CHANNEL(X), {channel, X}). -define(FATE_CHANNEL(X), {channel, X}).
-define(FATE_BITS(B), {bits, B}). -define(FATE_BITS(B), {bits, B}).
-define(FATE_TYPEREP(T), {typerep, T}). -define(FATE_TYPEREP(T), {typerep, T}).
-define(FATE_STORE_MAP(Cache, Id), {store_map, Cache, Id}).
-define(FATE_MAP_TOMBSTONE, '__DELETED__').
-define(FATE_INTEGER_VALUE(X), (X)). -define(FATE_INTEGER_VALUE(X), (X)).
-define(FATE_BOOLEAN_VALUE(X), (X)). -define(FATE_BOOLEAN_VALUE(X), (X)).
@@ -71,8 +63,6 @@
-define(FATE_CHANNEL_VALUE(X), (element(2, X))). -define(FATE_CHANNEL_VALUE(X), (element(2, X))).
-define(FATE_BITS_VALUE(X), (element(2, X))). -define(FATE_BITS_VALUE(X), (element(2, X))).
-define(FATE_MAP_VALUE(X), (X)). -define(FATE_MAP_VALUE(X), (X)).
-define(FATE_STORE_MAP_CACHE(X), (element(2, X))).
-define(FATE_STORE_MAP_ID(X), (element(3, X))).
-define(FATE_MAP_SIZE(X), (map_size(X))). -define(FATE_MAP_SIZE(X), (map_size(X))).
-define(FATE_STRING_SIZE(X), (byte_size(X))). -define(FATE_STRING_SIZE(X), (byte_size(X))).
-define(FATE_TRUE, true). -define(FATE_TRUE, true).
+2 -6
View File
@@ -176,7 +176,6 @@
-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).
@@ -187,15 +186,13 @@
-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_VERIFY_SIG, 400). -define(PRIM_CALL_CRYPTO_ECVERIFY, 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_VERIFY_SIG_SECP256K1, 410). -define(PRIM_CALL_CRYPTO_ECVERIFY_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).
@@ -203,4 +200,3 @@
-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).
-1
View File
@@ -22,6 +22,5 @@ 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)
]}. ]}.
+2 -3
View File
@@ -77,7 +77,7 @@ prop_opcodes() ->
valid_opcodes() -> valid_opcodes() ->
lists:seq(0, 16#7f) ++ lists:seq(16#fa, 16#fd). lists:seq(0, 16#7c) ++ lists:seq(16#fa, 16#fd).
fate_code(Failure) -> fate_code(Failure) ->
@@ -85,8 +85,7 @@ 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,
{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)})),
{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(
+10 -52
View File
@@ -10,7 +10,6 @@
-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]).
@@ -24,7 +23,7 @@ prop_roundtrip() ->
end)). end)).
prop_format_scan() -> prop_format_scan() ->
?FORALL(FateData, fate_data([variant, map]), ?FORALL(FateData, fate_data(),
?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),
@@ -44,18 +43,6 @@ 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)),
@@ -72,14 +59,13 @@ prop_fuzz() ->
prop_order() -> prop_order() ->
?FORALL(Items, vector(3, fate_data([variant, map])), ?FORALL(Items, vector(3, fate_data()),
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]) ->
@@ -102,24 +88,18 @@ 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() ->
fate_data([map, variant, store_map]). ?SIZED(Size, ?LET(Data, fate_data(Size, [map, variant]), eqc_symbolic:eval(Data))).
%% keys may contain variants but no maps
fate_data_key() -> fate_data_key() ->
fate_data([variant]). ?SIZED(Size, ?LET(Data, fate_data(Size div 4, [variant]), eqc_symbolic:eval(Data))).
fate_data(0, Options) -> fate_data(0, _Options) ->
?LAZY( ?LAZY(
frequency( frequency(
[{50, oneof([fate_integer(), fate_boolean(), fate_nil(), fate_unit()])}, [{5, oneof([fate_integer(), fate_boolean(), fate_nil(), fate_unit()])},
{10, oneof([fate_string(), fate_address(), fate_bytes(), fate_contract(), {1, 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),
@@ -168,18 +148,7 @@ 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, store_map])), ?LET(Keys, vector(length(Values), fate_data(Size div max(1, N * 2), Options -- [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))))))). return(aeb_fate_data:make_map(maps:from_list(lists:zip(Keys, Values))))))).
non_quote_string() -> non_quote_string() ->
@@ -198,14 +167,3 @@ 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.
+22 -60
View File
@@ -11,15 +11,14 @@
-define(HASH_SIZE, 32). -define(HASH_SIZE, 32).
-export([ create_calldata/4 -export([ create_calldata/4
, check_calldata/3 , check_calldata/2
, function_type_info/4 , function_type_info/3
, 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
]). ]).
@@ -28,7 +27,6 @@
-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
}. }.
@@ -53,24 +51,12 @@ 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(), boolean()) -> -spec check_calldata(binary(), type_info()) ->
{'ok', typerep(), typerep()} | {'error', atom()}. {'ok', typerep(), typerep()} | {'error', atom()}.
check_calldata(CallData, TypeInfo, CheckPayable) -> check_calldata(CallData, TypeInfo) ->
%% 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} ->
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 case typereps_from_type_hash(Hash, TypeInfo) of
{ok, ArgType, OutType} -> {ok, ArgType, OutType} ->
try aeb_heap:from_binary({tuple, [word, ArgType]}, CallData) of try aeb_heap:from_binary({tuple, [word, ArgType]}, CallData) of
@@ -84,9 +70,11 @@ check_calldata(Hash, CallData, TypeInfo, false) ->
end; end;
{error, _} -> {error, _} ->
{error, unknown_function} {error, unknown_function}
end;
{error, _What} ->
{error, bad_call_data}
end. 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) ->
@@ -98,13 +86,12 @@ 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(), boolean(), [typerep()], typerep()) -> -spec function_type_info(function_name(), [typerep()], typerep()) ->
function_type_info(). function_type_info().
function_type_info(Name, Payable, ArgTypes, OutType) -> function_type_info(Name, 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)
}. }.
@@ -123,46 +110,35 @@ 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} ->
arg_typerep_from_type_binary(ArgTypeBin); case aeb_heap:from_binary(typerep, ArgTypeBin) of
{_TypeHash, Function, _Payable, ArgTypeBin, _OutTypeBin} -> {ok, ArgType} -> {ok, ArgType};
arg_typerep_from_type_binary(ArgTypeBin); {error,_} -> {error, bad_type_data}
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} ->
typereps_from_type_binaries(ArgTypeBin, OutTypeBin); case {aeb_heap:from_binary(typerep, ArgTypeBin),
{TypeHash, _Function, _Payable, ArgTypeBin, OutTypeBin} -> aeb_heap:from_binary(typerep, OutTypeBin)} of
typereps_from_type_binaries(ArgTypeBin, OutTypeBin); {{ok, ArgType}, {ok, OutType}} -> {ok, ArgType, OutType};
{_, _} -> {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}
@@ -173,22 +149,8 @@ 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.
+1 -1
View File
@@ -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};
{_Attrs, {ArgTypes, RetType}, _Code} -> {{ArgTypes, RetType}, _Code} ->
{ok, ArgTypes, RetType} {ok, ArgTypes, RetType}
end. end.
+2 -2
View File
@@ -153,7 +153,7 @@ format_functions(Functions, Symbols) ->
lists:sort(maps:to_list(CodeMap)), lists:sort(maps:to_list(CodeMap)),
Symbols) Symbols)
|| ||
{Name, {_Attrs, Sig, CodeMap}} <- maps:to_list(Functions)]. {Name, {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, aeb_fate_encoding:serialize(0), SigByteCode, BodyByteCode], FunByteCode = [?FUNCTION, Id, SigByteCode, BodyByteCode],
Env#{ functions => Funs#{ Id => FunByteCode } Env#{ functions => Funs#{ Id => FunByteCode }
, fate_code => FateCode1}. , fate_code => FateCode1}.
+20 -41
View File
@@ -11,7 +11,7 @@
, deserialize/1 , deserialize/1
, functions/1 , functions/1
, insert_annotation/4 , insert_annotation/4
, insert_fun/5 , insert_fun/4
, 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, Attrs, {ArgType, RetType}, #{} = BBs, FCode) -> insert_fun(Name, {ArgType, RetType}, #{} = BBs, FCode) ->
{F1, ID} = insert_symbol(Name, FCode), {F1, ID} = insert_symbol(Name, FCode),
update_functions(F1, #{ID => {Attrs, {ArgType, RetType}, BBs}}). update_functions(F1, #{ID => {{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,17 +128,10 @@ 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, {Attrs, Sig, C}}, Acc) -> lists:foldr(fun({Id, {Sig, C}}, Acc) ->
[[?FUNCTION, Id, serialize_attributes(Attrs), serialize_signature(Sig), serialize_bbs(C)] | Acc] [[?FUNCTION, Id, 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)].
@@ -146,7 +139,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) ->
@@ -173,7 +166,7 @@ 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.
@@ -310,35 +303,33 @@ deserialize_functions(<<?FUNCTION:8, A, B, C, D, Rest/binary>>,
, bb := 0 , bb := 0
, current_bb_code := [] , current_bb_code := []
} = Env) -> } = Env) ->
{Attrs, Rest2} = deserialize_attributes(Rest), {Sig, Rest2} = deserialize_signature(Rest),
{Sig, Rest3} = deserialize_signature(Rest2), Env2 = Env#{function => {<<A,B,C,D>>, Sig}},
Env2 = Env#{function => {<<A,B,C,D>>, Attrs, Sig}}, deserialize_functions(Rest2, Env2);
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, Attrs, Sig} #{ function := {F, Sig}
, bb := BB , bb := BB
, current_bb_code := Code , current_bb_code := Code
, code := Program , code := Program
, functions := Funs} = Env) -> , functions := Funs} = Env) ->
{NewAttrs, Rest2} = deserialize_attributes(Rest), {NewSig, Rest2} = deserialize_signature(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>>, NewAttrs, NewSig} , function => {<<A,B,C,D>>, NewSig}
, code => #{} , code => #{}
, functions => Funs#{F => {Attrs, Sig, Program}}}, , functions => Funs#{F => {Sig, Program}}},
deserialize_functions(Rest3, Env2); deserialize_functions(Rest2, Env2);
_ -> _ ->
Env2 = Env#{ bb => 0 Env2 = Env#{ bb => 0
, current_bb_code => [] , current_bb_code => []
, function => {<<A,B,C,D>>, NewAttrs, NewSig} , function => {<<A,B,C,D>>, NewSig}
, code => #{} , code => #{}
, functions => , functions =>
Funs#{F => {Attrs, Sig, Funs#{F => {Sig,
Program#{ BB => lists:reverse(Code)}}}}, Program#{ BB => lists:reverse(Code)}}}},
deserialize_functions(Rest3, Env2) deserialize_functions(Rest2, Env2)
end; end;
deserialize_functions(<<_Op:8, _Rest/binary>>, deserialize_functions(<<_Op:8, _Rest/binary>>,
#{ function := none }) -> #{ function := none }) ->
@@ -360,7 +351,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, Attrs, Sig} deserialize_functions(<<>>, #{ function := {F, Sig}
, bb := BB , bb := BB
, current_bb_code := Code , current_bb_code := Code
, code := Program , code := Program
@@ -370,7 +361,7 @@ deserialize_functions(<<>>, #{ function := {F, Attrs, Sig}
[] -> Program; [] -> Program;
_ -> Program#{ BB => lists:reverse(Code)} _ -> Program#{ BB => lists:reverse(Code)}
end, end,
Funs#{F => {Attrs, Sig, FunctionCode}}. Funs#{F => {Sig, FunctionCode}}.
deserialize_op(Op, Rest, Code) -> deserialize_op(Op, Rest, Code) ->
OpName = aeb_fate_opcodes:mnemonic(Op), OpName = aeb_fate_opcodes:mnemonic(Op),
@@ -408,18 +399,6 @@ 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),
+1 -9
View File
@@ -10,7 +10,6 @@
-type fate_list() :: ?FATE_LIST_T. -type fate_list() :: ?FATE_LIST_T.
-type fate_unit() :: ?FATE_UNIT_T. -type fate_unit() :: ?FATE_UNIT_T.
-type fate_map() :: ?FATE_MAP_T. -type fate_map() :: ?FATE_MAP_T.
-type fate_store_map() :: ?FATE_STORE_MAP_T.
-type fate_string() :: ?FATE_STRING_T. -type fate_string() :: ?FATE_STRING_T.
-type fate_address() :: ?FATE_ADDRESS_T. -type fate_address() :: ?FATE_ADDRESS_T.
-type fate_hash() :: ?FATE_BYTES_T(32). -type fate_hash() :: ?FATE_BYTES_T(32).
@@ -21,7 +20,6 @@
-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
@@ -55,8 +53,7 @@
| 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
@@ -74,7 +71,6 @@
, fate_channel/0 , fate_channel/0
, fate_variant/0 , fate_variant/0
, fate_map/0 , fate_map/0
, fate_store_map/0
, fate_bits/0 , fate_bits/0
, fate_type_type/0 , fate_type_type/0
]). ]).
@@ -86,8 +82,6 @@
, make_tuple/1 , make_tuple/1
, make_string/1 , make_string/1
, make_map/1 , make_map/1
, make_store_map/1
, make_store_map/2
, make_address/1 , make_address/1
, make_bytes/1 , make_bytes/1
, make_hash/1 , make_hash/1
@@ -114,8 +108,6 @@ make_list(L) -> ?MAKE_FATE_LIST(L).
make_unit() -> ?FATE_UNIT. make_unit() -> ?FATE_UNIT.
make_tuple(T) -> ?FATE_TUPLE(T). make_tuple(T) -> ?FATE_TUPLE(T).
make_map(M) -> ?MAKE_FATE_MAP(M). make_map(M) -> ?MAKE_FATE_MAP(M).
make_store_map(Id) -> make_store_map(#{}, Id).
make_store_map(Cache, Id) -> ?FATE_STORE_MAP(Cache, Id).
make_address(X) -> ?FATE_ADDRESS(X). make_address(X) -> ?FATE_ADDRESS(X).
make_bytes(X) -> ?FATE_BYTES(X). make_bytes(X) -> ?FATE_BYTES(X).
make_hash(X) -> make_bytes(X). make_hash(X) -> make_bytes(X).
-13
View File
@@ -93,7 +93,6 @@
%% %% 1000 1111 - FREE (Possibly for bytecode in the future.) %% %% 1000 1111 - FREE (Possibly for bytecode in the future.)
-define(OBJECT , 2#10011111). %% 1001 1111 | ObjectType | RLP encoded Array -define(OBJECT , 2#10011111). %% 1001 1111 | ObjectType | RLP encoded Array
-define(VARIANT , 2#10101111). %% 1010 1111 | [encoded arities] | encoded tag | [encoded values] -define(VARIANT , 2#10101111). %% 1010 1111 | [encoded arities] | encoded tag | [encoded values]
-define(MAP_ID , 2#10111111). %% 1011 1111 | RLP encoded integer (store map id)
-define(NEG_BITS , 2#11001111). %% 1100 1111 | RLP encoded integer (infinite 1:s bitfield) -define(NEG_BITS , 2#11001111). %% 1100 1111 | RLP encoded integer (infinite 1:s bitfield)
-define(EMPTY_MAP , 2#11011111). %% 1101 1111 -define(EMPTY_MAP , 2#11011111). %% 1101 1111
-define(NEG_BIG_INT , 2#11101111). %% 1110 1111 | RLP encoded (integer - 64) -define(NEG_BIG_INT , 2#11101111). %% 1110 1111 | RLP encoded (integer - 64)
@@ -194,9 +193,6 @@ serialize(Map) when ?IS_FATE_MAP(Map) ->
<<?MAP, <<?MAP,
(rlp_encode_int(Size))/binary, (rlp_encode_int(Size))/binary,
(Elements)/binary>>; (Elements)/binary>>;
serialize(?FATE_STORE_MAP(Cache, Id)) when Cache =:= #{} ->
%% We should never get to serialization without having flushed the caches.
<<?MAP_ID, (rlp_encode_int(Id))/binary>>;
serialize(?FATE_VARIANT(Arities, Tag, Values)) -> serialize(?FATE_VARIANT(Arities, Tag, Values)) ->
Arities = [A || A <- Arities, is_integer(A), A < 256], Arities = [A || A <- Arities, is_integer(A), A < 256],
Size = length(Arities), Size = length(Arities),
@@ -430,9 +426,6 @@ deserialize2(<<?MAP, Rest/binary>>) ->
false -> false ->
error({unknown_map_serialization_format, KVList}) error({unknown_map_serialization_format, KVList})
end; end;
deserialize2(<<?MAP_ID, Rest/binary>>) ->
{Id, Rest1} = rlp_decode_int(Rest),
{?FATE_STORE_MAP(#{}, Id), Rest1};
deserialize2(<<?VARIANT, Rest/binary>>) -> deserialize2(<<?VARIANT, Rest/binary>>) ->
{AritiesBin, <<Tag:8, Rest2/binary>>} = aeser_rlp:decode_one(Rest), {AritiesBin, <<Tag:8, Rest2/binary>>} = aeser_rlp:decode_one(Rest),
Arities = binary_to_list(AritiesBin), Arities = binary_to_list(AritiesBin),
@@ -487,11 +480,5 @@ 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.
+23 -35
View File
@@ -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,11 +46,11 @@ 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,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_R', 16#03, true, false, true, 8, [a,is,a], call_r, {contract, string, integer}, any, "Remote call to contract Arg0 and function Arg1 with value Arg2. The types of the arguments has to match the argument typs 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."} , { 'CALL_TR', 16#05, true, false, true, 8, [a,is,a], call_tr, {contract, string, integer}, any, "Remote tail call to contract Arg0 and function Arg1 with value Arg2. 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_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."} , { 'CALL_GR', 16#06, true, false, true, 8, [a,is,a,a], call_gr, {contract, string, integer, integer}, any, "Remote call with gas cap in Arg3. Otherwise as CALL_R."}
, { 'UNUSED_2', 16#07, false, false, true, 8, [], unused_2, {}, none, "Was CALL_GTR."} , { 'CALL_GTR', 16#07, true, false, true, 8, [a,is,a,a], call_gtr, {contract, string, integer, integer}, any, "Remote tail call with gas cap in Arg3. Otherwise as CALL_TR."}
, { '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."}
, { 'SWITCH_V2', 16#0a, true, true, true, 4, [a,ii,ii], switch, {variant, integer, ingeger}, none, "Conditional jump to a basic block on variant tag."} , { 'SWITCH_V2', 16#0a, true, true, true, 4, [a,ii,ii], switch, {variant, integer, ingeger}, none, "Conditional jump to a basic block on variant tag."}
@@ -151,7 +151,7 @@ ops_defs() ->
, { 'ORACLE_QUERY_FEE', 16#67, false, false, true, 3, [a,a], oracle_query_fee, {oracle}, integer, "Arg0 := query fee for oracle Arg1"} , { 'ORACLE_QUERY_FEE', 16#67, false, false, true, 3, [a,a], oracle_query_fee, {oracle}, integer, "Arg0 := query fee for oracle Arg1"}
, { 'AENS_RESOLVE', 16#68, false, false, true, 3, [a,a,a,a], aens_resolve, {string, string, typerep}, variant, "Resolve name in Arg0 with tag Arg1. Arg2 describes the type parameter of the resolved name."} , { 'AENS_RESOLVE', 16#68, false, false, true, 3, [a,a,a,a], aens_resolve, {string, string, typerep}, variant, "Resolve name in Arg0 with tag Arg1. Arg2 describes the type parameter of the resolved name."}
, { 'AENS_PRECLAIM', 16#69, false, false, false, 3, [a,a,a], aens_preclaim, {signature, address, hash}, none, "Preclaim the hash in Arg2 for address in Arg1. Arg0 contains delegation signature."} , { 'AENS_PRECLAIM', 16#69, false, false, false, 3, [a,a,a], aens_preclaim, {signature, address, hash}, none, "Preclaim the hash in Arg2 for address in Arg1. Arg0 contains delegation signature."}
, { 'AENS_CLAIM', 16#6a, false, false, false, 3, [a,a,a,a], aens_claim, {signature, address, string, integer}, none, "Claim the name in Arg2 for address in Arg1. Arg3 contains the salt used to hash the preclaim. Arg0 contains delegation signature."} , { 'AENS_CLAIM', 16#6a, false, false, false, 3, [a,a,a,a,a], aens_claim, {signature, address, string, integer, integer}, none, "Attempt to claim the name in Arg2 for address in Arg1 at a price in Arg4. Arg3 contains the salt used to hash the preclaim. Arg0 contains delegation signature."}
, { 'AENS_UPDATE', 16#6b, false, false, false, 3, [], aens_update, {}, none, "NYI"} , { 'AENS_UPDATE', 16#6b, false, false, false, 3, [], aens_update, {}, none, "NYI"}
, { 'AENS_TRANSFER', 16#6c, false, false, false, 3, [a,a,a,a], aens_transfer,{signature, address, address, string}, none, "Transfer ownership of name Arg3 from account Arg1 to Arg2. Arg0 contains delegation signature."} , { 'AENS_TRANSFER', 16#6c, false, false, false, 3, [a,a,a,a], aens_transfer,{signature, address, address, string}, none, "Transfer ownership of name Arg3 from account Arg1 to Arg2. Arg0 contains delegation signature."}
, { 'AENS_REVOKE', 16#6d, false, false, false, 3, [a,a,a], aens_revoke, {signature, address, string}, none, "Revoke the name in Arg2 from owner Arg1. Arg0 contains delegation signature."} , { 'AENS_REVOKE', 16#6d, false, false, false, 3, [a,a,a], aens_revoke, {signature, address, string}, none, "Revoke the name in Arg2 from owner Arg1. Arg0 contains delegation signature."}
@@ -161,8 +161,8 @@ 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."}
, { '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', 16#72, false, true, true, 1300, [a,a,a,a], ecverify, {bytes, address, bytes}, boolean, "Arg0 := ecverify(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)"} , { 'ECVERIFY_SECP256K1', 16#73, false, true, true, 1300, [a,a,a,a], ecverify_secp256k1, {bytes, bytes, bytes}, boolean, "Arg0 := ecverify_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."}
@@ -175,12 +175,8 @@ ops_defs() ->
, { '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"}
, { 'IS_PAYABLE', 16#7c, false, false, true, 3, [a,a], is_payable, {address}, bool, "Arg0 := is Arg1 a payable address"} , { 'CREATOR', 16#7c, false, true, true, 3, [a], contract_creator, {}, address, "Arg0 := contract creator"}
, { '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."}
@@ -281,7 +277,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 ~-29s :: ~s.\n", lists:flatten(io_lib:format("-type ~-26s :: ~s.\n",
[TypeName, Type])). [TypeName, Type])).
gen_fate_code_type(#{type_name := TypeName}) -> gen_fate_code_type(#{type_name := TypeName}) ->
@@ -359,27 +355,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(~24s) -> ~24w ;\n", lists:flatten(io_lib:format("mnemonic(~21s) -> ~21w ;\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(~24w) -> ~24s ;\n", lists:flatten(io_lib:format("m_to_op(~21w) -> ~21s ;\n",
[Name, Macro])). [Name, Macro])).
gen_args(#{macro := Macro, arity := Arity}) -> gen_args(#{macro := Macro, arity := Arity}) ->
lists:flatten(io_lib:format("args(~24s) -> ~2w ;\n", lists:flatten(io_lib:format("args(~21s) -> ~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(~24s) -> ~w ;\n", lists:flatten(io_lib:format("end_bb(~21s) -> ~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(~24s) -> ~w ;\n", lists:flatten(io_lib:format("in_auth(~21s) -> ~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(~24s) -> ~w ;\n", lists:flatten(io_lib:format("allowed_offchain(~21s) -> ~w ;\n",
[Macro, Offchain])). [Macro, Offchain])).
prelude(Doc) -> prelude(Doc) ->
@@ -396,7 +392,7 @@ prelude(Doc) ->
gen_defines(#{opname := Name, opcode := OpCode}) -> gen_defines(#{opname := Name, opcode := OpCode}) ->
lists:flatten(io_lib:format("-define(~-29w, 16#~2.16.0b).\n", [Name, OpCode])). lists:flatten(io_lib:format("-define(~-26w, 16#~2.16.0b).\n", [Name, OpCode])).
gen([]) -> gen([]) ->
[]; [];
@@ -492,33 +488,25 @@ gen_asm_pp(Module, Path, Ops) ->
io:format(File, "format_op(Op, _Symbols) -> io_lib:format(\";; Bad Op: ~~w\\n\", [Op]).\n", []), io:format(File, "format_op(Op, _Symbols) -> io_lib:format(\";; Bad Op: ~~w\\n\", [Op]).\n", []),
file:close(File). file:close(File).
gen_format(#{opname := Name}) when (Name =:= 'CALL_R') -> gen_format(#{opname := Name}) when (Name =:= 'CALL_R') or (Name =:= 'CALL_TR') ->
io_lib:format("format_op({~w, {immediate, Contract}, {immediate, Function}, ArgType, RetType, Value}, Symbols) ->\n" io_lib:format("format_op({~w, {immediate, Contract}, {immediate, Function}, Value}, Symbols) ->\n"
" [\"~s \", lookup(Contract, Symbols), \".\", " " [\"~s \", lookup(Contract, Symbols), \".\", "
"lookup(Function, Symbols), \" \", " "lookup(Function, Symbols), \" \", "
"format_arg(a, ArgType), \" \", "
"format_arg(a, RetType), \" \", "
"format_arg(a, Value)];\n" "format_arg(a, Value)];\n"
"format_op({~w, Contract, {immediate, Function}, ArgType, RetType, Value}, Symbols) ->\n" "format_op({~w, Contract, {immediate, Function}, Value}, Symbols) ->\n"
"[\"~s \", format_arg(a, Contract), \".\", " "[\"~s \", format_arg(a, Contract), \".\", "
"lookup(Function, Symbols), \" \", " "lookup(Function, Symbols), \" \", "
"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') or (Name =:= 'CALL_GTR') ->
io_lib:format("format_op({~w, {immediate, Contract}, {immediate, Function}, ArgType, RetType, Value, Gas}, Symbols) ->\n" io_lib:format("format_op({~w, {immediate, Contract}, {immediate, Function}, Value, Gas}, Symbols) ->\n"
" [\"~s \", lookup(Contract, Symbols), \".\", " " [\"~s \", lookup(Contract, Symbols), \".\", "
"lookup(Function, Symbols), \" \", " "lookup(Function, Symbols), \" \", "
"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}, ArgType, RetType, Value, Gas}, Symbols) ->\n" "format_op({~w, Contract, {immediate, Function}, Value, Gas}, Symbols) ->\n"
"[\"~s \", format_arg(a, Contract), \".\", " "[\"~s \", format_arg(a, Contract), \".\", "
"lookup(Function, Symbols), \" \", " "lookup(Function, Symbols), \" \", "
"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)]);
-214
View File
@@ -1,214 +0,0 @@
%%%-------------------------------------------------------------------
%%% @copyright (C) 2019, Aeternity Anstalt
%%% @doc
%%% Functions for manipulating FATE maps. In particular for mediating
%%% between plain map values (represented by Erlang maps) and maps that are
%%% fully or partially saved in the contract store.
%%% @end
%%% -------------------------------------------------------------------
-module(aeb_fate_maps).
-include("aeb_fate_data.hrl").
-export([ allocate_store_maps/2
, has_store_maps/1
, unfold_store_maps/2
, refcount/1
, refcount_zero/0
, refcount_diff/2
, refcount_union/1
, refcount_union/2
, no_used_ids/0 ]).
-export_type([used_ids/0, maps/0, refcount/0]).
%% Size in bytes of serialization of a map for which we turn it into a store
%% map. It's not worth turning small maps into store maps.
%% Under consensus!
-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_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};
allocate_store_maps(Used, ?FATE_BITS(_) = Val, Maps) -> {Used, Val, Maps};
allocate_store_maps(Used, ?FATE_BYTES(_) = Val, Maps) -> {Used, Val, Maps};
allocate_store_maps(Used, ?FATE_ADDRESS(_) = Val, Maps) -> {Used, Val, Maps};
allocate_store_maps(Used, ?FATE_CONTRACT(_) = Val, Maps) -> {Used, Val, Maps};
allocate_store_maps(Used, ?FATE_ORACLE(_) = Val, Maps) -> {Used, Val, Maps};
allocate_store_maps(Used, ?FATE_ORACLE_Q(_) = Val, Maps) -> {Used, Val, Maps};
allocate_store_maps(Used, ?FATE_CHANNEL(_) = Val, Maps) -> {Used, Val, Maps};
allocate_store_maps(Used, ?FATE_TYPEREP(_) = Val, Maps) -> {Used, Val, Maps};
allocate_store_maps(Used, Val, Maps) when ?IS_FATE_INTEGER(Val) -> {Used, Val, Maps};
allocate_store_maps(Used, Val, Maps) when ?IS_FATE_STRING(Val) -> {Used, Val, Maps};
allocate_store_maps(Used, ?FATE_TUPLE(Val), Maps) ->
{Used1, Vals, Maps1} = allocate_store_maps_l(Used, tuple_to_list(Val), Maps),
{Used1, ?FATE_TUPLE(list_to_tuple(Vals)), Maps1};
allocate_store_maps(Used, Val, Maps) when ?IS_FATE_LIST(Val) ->
{Used1, Vals, Maps1} = allocate_store_maps_l(Used, ?FATE_LIST_VALUE(Val), Maps),
{Used1, ?MAKE_FATE_LIST(Vals), Maps1};
allocate_store_maps(Used, ?FATE_VARIANT(Arities, Tag, Vals), Maps) ->
{Used1, Vals1, Maps1} = allocate_store_maps_l(Used, tuple_to_list(Vals), Maps),
{Used1, ?FATE_VARIANT(Arities, Tag, list_to_tuple(Vals1)), Maps1};
allocate_store_maps(Used, Val, Maps) when ?IS_FATE_MAP(Val) ->
{Used1, KVs, Maps1} = allocate_store_maps_m(Used, ?FATE_MAP_VALUE(Val), Maps),
Val1 = ?MAKE_FATE_MAP(KVs),
case byte_size(aeb_fate_encoding:serialize(Val1)) < ?STORE_MAP_THRESHOLD of
true -> {Used1, Val1, Maps1};
false ->
{Id, Used2} = next_id(Used1),
{Used2, ?FATE_STORE_MAP(#{}, Id), Maps1#{Id => Val1}}
end;
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),
{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) ->
{Used1, H1, Maps1} = allocate_store_maps(Used, H, Maps),
{Used2, T1, Maps2} = allocate_store_maps(Used1, T, Maps1),
{Used2, [H1 | T1], Maps2}.
allocate_store_maps_m(Used, Val, Maps) ->
maps:fold(fun(K, V, {Us, M, Ms}) ->
{Us1, V1, Ms1} = allocate_store_maps(Us, V, Ms),
{Us1, M#{ K => V1 }, Ms1}
end, {Used, #{}, Maps}, Val).
%% -- Unfolding store maps ---------------------------------------------------
-type unfold_fun() :: fun((id()) -> aeb_fate_data:fate_map()).
-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;
unfold_store_maps(_Unfold, ?FATE_BITS(_) = Val) -> Val;
unfold_store_maps(_Unfold, ?FATE_BYTES(_) = Val) -> Val;
unfold_store_maps(_Unfold, ?FATE_ADDRESS(_) = Val) -> Val;
unfold_store_maps(_Unfold, ?FATE_CONTRACT(_) = Val) -> Val;
unfold_store_maps(_Unfold, ?FATE_ORACLE(_) = Val) -> Val;
unfold_store_maps(_Unfold, ?FATE_ORACLE_Q(_) = Val) -> Val;
unfold_store_maps(_Unfold, ?FATE_CHANNEL(_) = Val) -> Val;
unfold_store_maps(_Unfold, ?FATE_TYPEREP(_) = Val) -> Val;
unfold_store_maps(_Unfold, Val) when ?IS_FATE_INTEGER(Val) -> Val;
unfold_store_maps(_Unfold, Val) when ?IS_FATE_STRING(Val) -> Val;
unfold_store_maps(Unfold, ?FATE_TUPLE(Val)) ->
Vals = unfold_store_maps_l(Unfold, tuple_to_list(Val)),
?FATE_TUPLE(list_to_tuple(Vals));
unfold_store_maps(Unfold, Val) when ?IS_FATE_LIST(Val) ->
?MAKE_FATE_LIST(unfold_store_maps_l(Unfold, ?FATE_LIST_VALUE(Val)));
unfold_store_maps(Unfold, ?FATE_VARIANT(Arities, Tag, Vals)) ->
Vals1 = unfold_store_maps_l(Unfold, tuple_to_list(Vals)),
?FATE_VARIANT(Arities, Tag, list_to_tuple(Vals1));
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),
unfold_store_maps_m(Unfold, Cache)).
unfold_store_maps_l(Unfold, Vals) ->
[ unfold_store_maps(Unfold, Val) || Val <- Vals ].
unfold_store_maps_m(Unfold, Val) ->
maps:map(fun(_, V) -> unfold_store_maps(Unfold, V) end, Val).
write_cache(Key, ?FATE_MAP_TOMBSTONE, Map) ->
maps:remove(Key, Map);
write_cache(Key, Val, Map) ->
Map#{ Key => Val }.
%% -- Reference counting -----------------------------------------------------
-type refcount() :: #{id() => integer()}.
-spec refcount_zero() -> refcount().
refcount_zero() -> #{}.
-spec refcount_diff(refcount(), refcount()) -> refcount().
refcount_diff(New, Old) ->
maps:fold(fun(K, N, C) -> maps:update_with(K, fun(M) -> M - N end, -N, C) end,
New, Old).
-spec refcount_union([refcount()]) -> refcount().
refcount_union(Counts) -> lists:foldl(fun refcount_union/2, #{}, Counts).
-spec refcount_union(refcount(), refcount()) -> refcount().
refcount_union(A, B) ->
maps:fold(fun(K, N, C) -> maps:update_with(K, fun(M) -> M + N end, N, C) end,
B, A).
-spec has_store_maps(fate_value()) -> boolean().
has_store_maps(Val) ->
refcount_zero() /= refcount(Val).
-spec refcount(fate_value()) -> refcount().
refcount(Val) -> refcount(Val, #{}).
-spec refcount(fate_value_or_tombstone(), refcount()) -> refcount().
refcount(?FATE_MAP_TOMBSTONE, Count) -> Count;
refcount(?FATE_TRUE, Count) -> Count;
refcount(?FATE_FALSE, Count) -> Count;
refcount(?FATE_UNIT, Count) -> Count;
refcount(?FATE_BITS(_), Count) -> Count;
refcount(?FATE_BYTES(_), Count) -> Count;
refcount(?FATE_ADDRESS(_), Count) -> Count;
refcount(?FATE_CONTRACT(_), Count) -> Count;
refcount(?FATE_ORACLE(_), Count) -> Count;
refcount(?FATE_ORACLE_Q(_), Count) -> Count;
refcount(?FATE_CHANNEL(_), Count) -> Count;
refcount(?FATE_TYPEREP(_), Count) -> Count;
refcount(Val, Count) when ?IS_FATE_INTEGER(Val) -> Count;
refcount(Val, Count) when ?IS_FATE_STRING(Val) -> Count;
refcount(?FATE_TUPLE(Val), Count) ->
refcount_l(tuple_to_list(Val), Count);
refcount(Val, Count) when ?IS_FATE_LIST(Val) ->
refcount_l(?FATE_LIST_VALUE(Val), Count);
refcount(?FATE_VARIANT(_Arities, _Tag, Vals), Count) ->
refcount_l(tuple_to_list(Vals), Count);
refcount(Val, Count) when ?IS_FATE_MAP(Val) ->
refcount_m(?FATE_MAP_VALUE(Val), Count);
refcount(?FATE_STORE_MAP(Cache, Id), Count) ->
refcount_m(Cache, maps:update_with(Id, fun(N) -> N + 1 end, 1, Count)).
refcount_l(Vals, Count) ->
lists:foldl(fun refcount/2, Count, Vals).
refcount_m(Val, Count) ->
%% No maps in map keys
maps:fold(fun(_, ?FATE_MAP_TOMBSTONE, C) -> C;
(_, V, C) -> refcount(V, C) end, Count, Val).
%% -- Map id allocation ------------------------------------------------------
-spec no_used_ids() -> used_ids().
no_used_ids() -> [].
-spec next_id(used_ids()) -> {id(), used_ids()}.
next_id(UsedIds) ->
next_id(UsedIds, 0, []).
next_id(Used, J, Acc) when Used == []; J < hd(Used) ->
{J, lists:reverse(Acc) ++ [J | Used]};
next_id([I | Used], I, Acc) ->
next_id(Used, I + 1, [I | Acc]);
next_id([I | Used], J, Acc) when J > I ->
next_id(Used, J, [I | Acc]).
+2 -14
View File
@@ -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 roundtrip of all instructions. ;; Just used to check assembler rountrip of all instructions.
FUNCTION foo () : {tuple, []} FUNCTION foo () : {tuple, []}
RETURN RETURN
@@ -224,13 +224,7 @@ FUNCTION foo () : {tuple, []}
AENS_REVOKE AENS_REVOKE
ECRECOVER_SECP256K1 ECVERIFY
VERIFY_SIG
VERIFY_SIG_SECP256K1
ECVERIFY_SECP256K1
SHA3 a SHA3 a
@@ -253,9 +247,3 @@ 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
+2 -4
View File
@@ -4,8 +4,8 @@ FUNCTION preclaim(address, {bytes, 32}) : {tuple, []}
AENS_PRECLAIM #AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== arg0 arg1 AENS_PRECLAIM #AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== arg0 arg1
RETURNR {} RETURNR {}
FUNCTION claim(address, string, integer) : {tuple, []} FUNCTION claim(address, string, integer, integer) : {tuple, []}
AENS_CLAIM #AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== arg0 arg1 arg2 AENS_CLAIM #AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== arg0 arg1 arg2 arg3
RETURNR {} RETURNR {}
FUNCTION transfer(address, address, {bytes, 32}) : {tuple, []} FUNCTION transfer(address, address, {bytes, 32}) : {tuple, []}
@@ -19,5 +19,3 @@ FUNCTION revoke(address, {bytes, 32}) : {tuple, []}
FUNCTION resolve(string, string) : {variant, [{tuple, []}, {tuple, [address]}]} FUNCTION resolve(string, string) : {variant, [{tuple, []}, {tuple, [address]}]}
AENS_RESOLVE a arg0 arg1 'address AENS_RESOLVE a arg0 arg1 'address
RETURN RETURN
+9 -5
View File
@@ -28,11 +28,15 @@ 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 {tuple, [integer]} integer 0 ;; typereps don't parse CALL_R remote.add_five 0
;; INCA INCA
;; RETURN RETURN
FUNCTION remote_tailcall(integer) : integer
PUSH arg0
CALL_TR remote add_five 0
;; 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