Compare commits
58 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4228605470 | |||
| 059d114a06 | |||
| e4b09d7c5c | |||
| b040dccdef | |||
| 211ee74df2 | |||
| 38f4f0ecd7 | |||
| 281e9b210c | |||
| 3e7a8e4a69 | |||
| ea5548be6c | |||
| 48cfbd03b0 | |||
| 04878c5ed9 | |||
| 4f4d6d30cd | |||
| 176df87bb0 | |||
| 2239bfb6f6 | |||
| 872766260b | |||
| f184abeb87 | |||
| a66dc0a97f | |||
| 17c9656f5c | |||
| 3106ca1306 | |||
| 3565719c7a | |||
| b036531dc2 | |||
| 7f0593fbf2 | |||
| a533fd5fcb | |||
| 02a3462cf4 | |||
| 69912db2b6 | |||
| 5e16b85ae2 | |||
| d272e821b2 | |||
| 72b2a581d5 | |||
| 72d61471e0 | |||
| e21abb875e | |||
| e7f2be7ce8 | |||
| c6475fe1c2 | |||
| 4e4c20c387 | |||
| 1d5e5be252 | |||
| 6efa4a0cb8 | |||
| 59b7b786ac | |||
| f31887c2ed | |||
| d794566363 | |||
| 850a5e2c35 | |||
| c270c794c3 | |||
| 10cc127883 | |||
| 50df849709 | |||
| dfa9b80a3c | |||
| befa1e3ff9 | |||
| efb4afeafa | |||
| e75336486e | |||
| fdd660a219 | |||
| 3954bd22da | |||
| 13211887a3 | |||
| 834ab298d1 | |||
| 52781060b2 | |||
| 3721fde7e8 | |||
| 23ee7e0ca4 | |||
| 197dfd5da1 | |||
| 44ec31d958 | |||
| 8fde1e5e24 | |||
| 7c6a80fef7 | |||
| c0bc71b0b7 |
@@ -17,6 +17,7 @@
|
|||||||
-define(FATE_VOID_T, void).
|
-define(FATE_VOID_T, void).
|
||||||
-define(FATE_TUPLE_T, {tuple, tuple()}).
|
-define(FATE_TUPLE_T, {tuple, tuple()}).
|
||||||
-define(FATE_BITS_T, {bits, integer()}).
|
-define(FATE_BITS_T, {bits, integer()}).
|
||||||
|
-define(FATE_TYPEREP_T, {typerep, fate_type_type()}).
|
||||||
|
|
||||||
-define(IS_FATE_INTEGER(X), (is_integer(X))).
|
-define(IS_FATE_INTEGER(X), (is_integer(X))).
|
||||||
-define(IS_FATE_LIST(X), (is_list(X))).
|
-define(IS_FATE_LIST(X), (is_list(X))).
|
||||||
|
|||||||
+10
-7
@@ -186,13 +186,15 @@
|
|||||||
-define(PRIM_CALL_MAP_TOLIST, 305).
|
-define(PRIM_CALL_MAP_TOLIST, 305).
|
||||||
|
|
||||||
-define(PRIM_CALL_IN_CRYPTO_RANGE(__TTYPE__), (((__TTYPE__) > 399) andalso ((__TTYPE__) < 500))).
|
-define(PRIM_CALL_IN_CRYPTO_RANGE(__TTYPE__), (((__TTYPE__) > 399) andalso ((__TTYPE__) < 500))).
|
||||||
-define(PRIM_CALL_CRYPTO_ECVERIFY, 400).
|
-define(PRIM_CALL_CRYPTO_VERIFY_SIG, 400).
|
||||||
-define(PRIM_CALL_CRYPTO_SHA3, 401).
|
-define(PRIM_CALL_CRYPTO_SHA3, 401).
|
||||||
-define(PRIM_CALL_CRYPTO_SHA256, 402).
|
-define(PRIM_CALL_CRYPTO_SHA256, 402).
|
||||||
-define(PRIM_CALL_CRYPTO_BLAKE2B, 403).
|
-define(PRIM_CALL_CRYPTO_BLAKE2B, 403).
|
||||||
-define(PRIM_CALL_CRYPTO_SHA256_STRING, 404).
|
-define(PRIM_CALL_CRYPTO_SHA256_STRING, 404).
|
||||||
-define(PRIM_CALL_CRYPTO_BLAKE2B_STRING, 405).
|
-define(PRIM_CALL_CRYPTO_BLAKE2B_STRING, 405).
|
||||||
-define(PRIM_CALL_CRYPTO_ECVERIFY_SECP256K1, 410).
|
-define(PRIM_CALL_CRYPTO_VERIFY_SIG_SECP256K1, 410).
|
||||||
|
-define(PRIM_CALL_CRYPTO_ECVERIFY_SECP256K1, 420).
|
||||||
|
-define(PRIM_CALL_CRYPTO_ECRECOVER_SECP256K1, 421).
|
||||||
|
|
||||||
-define(PRIM_CALL_IN_AUTH_RANGE(__TTYPE__), (((__TTYPE__) > 499) andalso ((__TTYPE__) < 600))).
|
-define(PRIM_CALL_IN_AUTH_RANGE(__TTYPE__), (((__TTYPE__) > 499) andalso ((__TTYPE__) < 600))).
|
||||||
-define(PRIM_CALL_AUTH_TX_HASH, 500).
|
-define(PRIM_CALL_AUTH_TX_HASH, 500).
|
||||||
@@ -200,3 +202,4 @@
|
|||||||
-define(PRIM_CALL_IN_ADDRESS_RANGE(__TTYPE__), (((__TTYPE__) > 599) andalso ((__TTYPE__) < 700))).
|
-define(PRIM_CALL_IN_ADDRESS_RANGE(__TTYPE__), (((__TTYPE__) > 599) andalso ((__TTYPE__) < 700))).
|
||||||
-define(PRIM_CALL_ADDR_IS_ORACLE, 600).
|
-define(PRIM_CALL_ADDR_IS_ORACLE, 600).
|
||||||
-define(PRIM_CALL_ADDR_IS_CONTRACT, 601).
|
-define(PRIM_CALL_ADDR_IS_CONTRACT, 601).
|
||||||
|
-define(PRIM_CALL_ADDR_IS_PAYABLE, 610).
|
||||||
|
|||||||
@@ -22,5 +22,6 @@ quickcheck_test_() ->
|
|||||||
{setup, fun() -> eqc:start() end,
|
{setup, fun() -> eqc:start() end,
|
||||||
[ ?EQC_EUNIT(aefate_type_eqc, prop_roundtrip, 1000),
|
[ ?EQC_EUNIT(aefate_type_eqc, prop_roundtrip, 1000),
|
||||||
?EQC_EUNIT(aefate_eqc, prop_serializes, 1000),
|
?EQC_EUNIT(aefate_eqc, prop_serializes, 1000),
|
||||||
|
?EQC_EUNIT(aefate_eqc, prop_no_maps_in_keys, 1000),
|
||||||
?EQC_EUNIT(aefate_eqc, prop_idempotent, 1000)
|
?EQC_EUNIT(aefate_eqc, prop_idempotent, 1000)
|
||||||
]}.
|
]}.
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ prop_opcodes() ->
|
|||||||
|
|
||||||
|
|
||||||
valid_opcodes() ->
|
valid_opcodes() ->
|
||||||
lists:seq(0, 16#7c) ++ lists:seq(16#fa, 16#fd).
|
lists:seq(0, 16#80) ++ lists:seq(16#fa, 16#fd).
|
||||||
|
|
||||||
|
|
||||||
fate_code(Failure) ->
|
fate_code(Failure) ->
|
||||||
@@ -85,7 +85,8 @@ fate_code(Failure) ->
|
|||||||
?LET({FMap, SMap, AMap},
|
?LET({FMap, SMap, AMap},
|
||||||
{non_empty(map(if Failure == 1 -> binary(1);
|
{non_empty(map(if Failure == 1 -> binary(1);
|
||||||
true -> binary(4) end,
|
true -> binary(4) end,
|
||||||
{{list(aefate_type_eqc:fate_type(Size div 3)), aefate_type_eqc:fate_type(Size div 3)}, bbs_code(Failure)})),
|
{sublist(lists:sort([private, payable])), %% deserialize sorts them
|
||||||
|
{list(aefate_type_eqc:fate_type(Size div 3)), aefate_type_eqc:fate_type(Size div 3)}, bbs_code(Failure)})),
|
||||||
small_map(small_fate_data_key(5), small_fate_data(4)),
|
small_map(small_fate_data_key(5), small_fate_data(4)),
|
||||||
small_map(small_fate_data_key(5), small_fate_data(4))},
|
small_map(small_fate_data_key(5), small_fate_data(4))},
|
||||||
aeb_fate_code:update_annotations(
|
aeb_fate_code:update_annotations(
|
||||||
|
|||||||
+52
-10
@@ -10,6 +10,7 @@
|
|||||||
-module(aefate_eqc).
|
-module(aefate_eqc).
|
||||||
|
|
||||||
-include_lib("eqc/include/eqc.hrl").
|
-include_lib("eqc/include/eqc.hrl").
|
||||||
|
-include("../include/aeb_fate_data.hrl").
|
||||||
|
|
||||||
-compile([export_all, nowarn_export_all]).
|
-compile([export_all, nowarn_export_all]).
|
||||||
|
|
||||||
@@ -23,7 +24,7 @@ prop_roundtrip() ->
|
|||||||
end)).
|
end)).
|
||||||
|
|
||||||
prop_format_scan() ->
|
prop_format_scan() ->
|
||||||
?FORALL(FateData, fate_data(),
|
?FORALL(FateData, fate_data([variant, map]),
|
||||||
?WHENFAIL(eqc:format("Trying to format ~p failed~n", [FateData]),
|
?WHENFAIL(eqc:format("Trying to format ~p failed~n", [FateData]),
|
||||||
begin
|
begin
|
||||||
String = aeb_fate_data:format(FateData),
|
String = aeb_fate_data:format(FateData),
|
||||||
@@ -43,6 +44,18 @@ prop_serializes() ->
|
|||||||
{size, size(Binary) < 500000}]))
|
{size, size(Binary) < 500000}]))
|
||||||
end)).
|
end)).
|
||||||
|
|
||||||
|
prop_no_maps_in_keys() ->
|
||||||
|
?FORALL(FateData, fate_bad_map(), %% may contain a map in its keys
|
||||||
|
begin
|
||||||
|
HasMapInKeys = lists:any(fun(K) -> has_map(K) end, maps:keys(FateData)),
|
||||||
|
try aeb_fate_encoding:serialize(FateData),
|
||||||
|
?WHENFAIL(eqc:format("Should not serialize, contains a map in key\n", []),
|
||||||
|
not HasMapInKeys)
|
||||||
|
catch error:Reason ->
|
||||||
|
?WHENFAIL(eqc:format("(~p) Should serialize\n", [Reason]), HasMapInKeys)
|
||||||
|
end
|
||||||
|
end).
|
||||||
|
|
||||||
prop_fuzz() ->
|
prop_fuzz() ->
|
||||||
in_parallel(
|
in_parallel(
|
||||||
?FORALL(Binary, ?LET(FateData, ?SIZED(Size, resize(Size div 4, fate_data())), aeb_fate_encoding:serialize(FateData)),
|
?FORALL(Binary, ?LET(FateData, ?SIZED(Size, resize(Size div 4, fate_data())), aeb_fate_encoding:serialize(FateData)),
|
||||||
@@ -59,13 +72,14 @@ prop_fuzz() ->
|
|||||||
|
|
||||||
|
|
||||||
prop_order() ->
|
prop_order() ->
|
||||||
?FORALL(Items, vector(3, fate_data()),
|
?FORALL(Items, vector(3, fate_data([variant, map])),
|
||||||
begin
|
begin
|
||||||
%% Use lt to take minimum
|
%% Use lt to take minimum
|
||||||
Min = lt_min(Items),
|
Min = lt_min(Items),
|
||||||
Max = lt_max(Items),
|
Max = lt_max(Items),
|
||||||
conjunction([ {minimum, is_empty([ {Min, '>', I} || I<-Items, aeb_fate_data:lt(I, Min)])},
|
conjunction([ {minimum, is_empty([ {Min, '>', I} || I<-Items, aeb_fate_data:lt(I, Min)])},
|
||||||
{maximum, is_empty([ {Max, '<', I} || I<-Items, aeb_fate_data:lt(Max, I)])}])
|
{maximum, is_empty([ {Max, '<', I} || I<-Items, aeb_fate_data:lt(Max, I)])},
|
||||||
|
{asym, aeb_fate_data:lt(Min, Max) orelse Min == Max}])
|
||||||
end).
|
end).
|
||||||
|
|
||||||
lt_min([X, Y | Rest]) ->
|
lt_min([X, Y | Rest]) ->
|
||||||
@@ -88,18 +102,24 @@ prop_idempotent() ->
|
|||||||
aeb_fate_encoding:sort(aeb_fate_encoding:sort(Items)))).
|
aeb_fate_encoding:sort(aeb_fate_encoding:sort(Items)))).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
fate_data(Kind) ->
|
||||||
|
?SIZED(Size, ?LET(Data, fate_data(Size, Kind), eqc_symbolic:eval(Data))).
|
||||||
|
|
||||||
fate_data() ->
|
fate_data() ->
|
||||||
?SIZED(Size, ?LET(Data, fate_data(Size, [map, variant]), eqc_symbolic:eval(Data))).
|
fate_data([map, variant, store_map]).
|
||||||
|
|
||||||
|
%% keys may contain variants but no maps
|
||||||
fate_data_key() ->
|
fate_data_key() ->
|
||||||
?SIZED(Size, ?LET(Data, fate_data(Size div 4, [variant]), eqc_symbolic:eval(Data))).
|
fate_data([variant]).
|
||||||
|
|
||||||
fate_data(0, _Options) ->
|
fate_data(0, Options) ->
|
||||||
?LAZY(
|
?LAZY(
|
||||||
frequency(
|
frequency(
|
||||||
[{5, oneof([fate_integer(), fate_boolean(), fate_nil(), fate_unit()])},
|
[{50, oneof([fate_integer(), fate_boolean(), fate_nil(), fate_unit()])},
|
||||||
{1, oneof([fate_string(), fate_address(), fate_bytes(), fate_contract(),
|
{10, oneof([fate_string(), fate_address(), fate_bytes(), fate_contract(),
|
||||||
fate_oracle(), fate_oracle_q(), fate_bits(), fate_channel()])}]));
|
fate_oracle(), fate_oracle_q(), fate_bits(), fate_channel()])}] ++
|
||||||
|
[{1, fate_store_map()} || lists:member(store_map, Options)]));
|
||||||
fate_data(Size, Options) ->
|
fate_data(Size, Options) ->
|
||||||
?LAZY(
|
?LAZY(
|
||||||
oneof([fate_data(0, Options),
|
oneof([fate_data(0, Options),
|
||||||
@@ -148,9 +168,20 @@ fate_list(Size, Options) ->
|
|||||||
fate_map(Size, Options) ->
|
fate_map(Size, Options) ->
|
||||||
?LET(N, choose(0, 6),
|
?LET(N, choose(0, 6),
|
||||||
?LETSHRINK(Values, fate_values(Size, N, Options),
|
?LETSHRINK(Values, fate_values(Size, N, Options),
|
||||||
?LET(Keys, vector(length(Values), fate_data(Size div max(1, N * 2), Options -- [map])),
|
?LET(Keys, vector(length(Values), fate_data(Size div max(1, N * 2), Options -- [map, store_map])),
|
||||||
return(aeb_fate_data:make_map(maps:from_list(lists:zip(Keys, Values))))))).
|
return(aeb_fate_data:make_map(maps:from_list(lists:zip(Keys, Values))))))).
|
||||||
|
|
||||||
|
fate_store_map() ->
|
||||||
|
%% only #{} is allowed as cache in serialization
|
||||||
|
?LET(X, oneof([int(), largeint()]),
|
||||||
|
return(aeb_fate_data:make_store_map(abs(X)))).
|
||||||
|
|
||||||
|
fate_bad_map() ->
|
||||||
|
?LET(N, choose(0, 6),
|
||||||
|
?LET(Values, vector(N, ?SIZED(Size, resize(Size div 8, fate_data()))),
|
||||||
|
?LET(Keys, vector(N, ?SIZED(Size, resize(Size div 4, fate_data()))),
|
||||||
|
return(aeb_fate_data:make_map(maps:from_list(lists:zip(Keys, Values))))))).
|
||||||
|
|
||||||
non_quote_string() ->
|
non_quote_string() ->
|
||||||
?SUCHTHAT(S, utf8(), [ quote || <<34>> <= S ] == []).
|
?SUCHTHAT(S, utf8(), [ quote || <<34>> <= S ] == []).
|
||||||
|
|
||||||
@@ -167,3 +198,14 @@ injection(Binary) ->
|
|||||||
|
|
||||||
is_empty(L) ->
|
is_empty(L) ->
|
||||||
?WHENFAIL(eqc:format("~p\n", [L]), L == []).
|
?WHENFAIL(eqc:format("~p\n", [L]), L == []).
|
||||||
|
|
||||||
|
has_map(L) when is_list(L) ->
|
||||||
|
lists:any(fun(V) -> has_map(V) end, L);
|
||||||
|
has_map(T) when is_tuple(T) ->
|
||||||
|
has_map(tuple_to_list(T));
|
||||||
|
has_map(M) when is_map(M) ->
|
||||||
|
true;
|
||||||
|
has_map(?FATE_STORE_MAP(_, _)) ->
|
||||||
|
true;
|
||||||
|
has_map(_) ->
|
||||||
|
false.
|
||||||
|
|||||||
+2
-2
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
{deps, [ {eblake2, "1.0.0"}
|
{deps, [ {eblake2, "1.0.0"}
|
||||||
, {aeserialization, {git, "https://github.com/aeternity/aeserialization.git",
|
, {aeserialization, {git, "https://github.com/aeternity/aeserialization.git",
|
||||||
{ref, "816bf99"}}}
|
{ref, "47aaa8f"}}}
|
||||||
, {getopt, "1.0.1"}
|
, {getopt, "1.0.1"}
|
||||||
]}.
|
]}.
|
||||||
|
|
||||||
@@ -40,7 +40,7 @@
|
|||||||
{profiles, [{binary, [
|
{profiles, [{binary, [
|
||||||
{deps, [ {eblake2, "1.0.0"}
|
{deps, [ {eblake2, "1.0.0"}
|
||||||
, {aeserialization, {git, "https://github.com/aeternity/aeserialization.git",
|
, {aeserialization, {git, "https://github.com/aeternity/aeserialization.git",
|
||||||
{ref, "b55c372"}}}
|
{ref, "47aaa8f"}}}
|
||||||
, {getopt, "1.0.1"}
|
, {getopt, "1.0.1"}
|
||||||
]},
|
]},
|
||||||
|
|
||||||
|
|||||||
+5
-1
@@ -1,13 +1,17 @@
|
|||||||
{"1.1.0",
|
{"1.1.0",
|
||||||
[{<<"aeserialization">>,
|
[{<<"aeserialization">>,
|
||||||
{git,"https://github.com/aeternity/aeserialization.git",
|
{git,"https://github.com/aeternity/aeserialization.git",
|
||||||
{ref,"816bf994ffb5cee218c3f22dc5fea296c9e0882e"}},
|
{ref,"47aaa8f5434b365c50a35bfd1490340b19241991"}},
|
||||||
0},
|
0},
|
||||||
{<<"base58">>,
|
{<<"base58">>,
|
||||||
{git,"https://github.com/aeternity/erl-base58.git",
|
{git,"https://github.com/aeternity/erl-base58.git",
|
||||||
{ref,"60a335668a60328a29f9731b67c4a0e9e3d50ab6"}},
|
{ref,"60a335668a60328a29f9731b67c4a0e9e3d50ab6"}},
|
||||||
1},
|
1},
|
||||||
{<<"eblake2">>,{pkg,<<"eblake2">>,<<"1.0.0">>},0},
|
{<<"eblake2">>,{pkg,<<"eblake2">>,<<"1.0.0">>},0},
|
||||||
|
{<<"enacl">>,
|
||||||
|
{git,"https://github.com/aeternity/enacl.git",
|
||||||
|
{ref,"26180f42c0b3a450905d2efd8bc7fd5fd9cece75"}},
|
||||||
|
1},
|
||||||
{<<"getopt">>,{pkg,<<"getopt">>,<<"1.0.1">>},0}]}.
|
{<<"getopt">>,{pkg,<<"getopt">>,<<"1.0.1">>},0}]}.
|
||||||
[
|
[
|
||||||
{pkg_hash,[
|
{pkg_hash,[
|
||||||
|
|||||||
+71
-33
@@ -11,14 +11,15 @@
|
|||||||
-define(HASH_SIZE, 32).
|
-define(HASH_SIZE, 32).
|
||||||
|
|
||||||
-export([ create_calldata/4
|
-export([ create_calldata/4
|
||||||
, check_calldata/2
|
, check_calldata/3
|
||||||
, function_type_info/3
|
, function_type_info/4
|
||||||
, function_type_hash/3
|
, function_type_hash/3
|
||||||
, arg_typerep_from_function/2
|
, arg_typerep_from_function/2
|
||||||
, type_hash_from_function_name/2
|
, type_hash_from_function_name/2
|
||||||
, typereps_from_type_hash/2
|
, typereps_from_type_hash/2
|
||||||
, function_name_from_type_hash/2
|
, function_name_from_type_hash/2
|
||||||
, get_function_hash_from_calldata/1
|
, get_function_hash_from_calldata/1
|
||||||
|
, is_payable/2
|
||||||
, abi_version/0
|
, abi_version/0
|
||||||
]).
|
]).
|
||||||
|
|
||||||
@@ -27,6 +28,7 @@
|
|||||||
-type typerep() :: aeb_aevm_data:type().
|
-type typerep() :: aeb_aevm_data:type().
|
||||||
-type function_type_info() :: { FunctionHash :: hash()
|
-type function_type_info() :: { FunctionHash :: hash()
|
||||||
, FunctionName :: function_name()
|
, FunctionName :: function_name()
|
||||||
|
, Payable :: boolean()
|
||||||
, ArgType :: binary() %% binary typerep
|
, ArgType :: binary() %% binary typerep
|
||||||
, OutType :: binary() %% binary typerep
|
, OutType :: binary() %% binary typerep
|
||||||
}.
|
}.
|
||||||
@@ -51,30 +53,40 @@ create_calldata(FunName, Args, ArgTypes0, RetType) ->
|
|||||||
Data = aeb_heap:to_binary({TypeHashInt, list_to_tuple(Args)}),
|
Data = aeb_heap:to_binary({TypeHashInt, list_to_tuple(Args)}),
|
||||||
{ok, Data}.
|
{ok, Data}.
|
||||||
|
|
||||||
-spec check_calldata(binary(), type_info()) ->
|
-spec check_calldata(binary(), type_info(), boolean()) ->
|
||||||
{'ok', typerep(), typerep()} | {'error', atom()}.
|
{'ok', typerep(), typerep()} | {'error', atom()}.
|
||||||
check_calldata(CallData, TypeInfo) ->
|
check_calldata(CallData, TypeInfo, CheckPayable) ->
|
||||||
%% The first element of the CallData should be the function name
|
%% The first element of the CallData should be the function name
|
||||||
case get_function_hash_from_calldata(CallData) of
|
case get_function_hash_from_calldata(CallData) of
|
||||||
{ok, Hash} ->
|
{ok, Hash} ->
|
||||||
case typereps_from_type_hash(Hash, TypeInfo) of
|
check_calldata(Hash, CallData, TypeInfo, CheckPayable);
|
||||||
{ok, ArgType, OutType} ->
|
|
||||||
try aeb_heap:from_binary({tuple, [word, ArgType]}, CallData) of
|
|
||||||
{ok, _Something} ->
|
|
||||||
{ok, {tuple, [word, ArgType]}, OutType};
|
|
||||||
{error, _} ->
|
|
||||||
{error, bad_call_data}
|
|
||||||
catch
|
|
||||||
_T:_E ->
|
|
||||||
{error, bad_call_data}
|
|
||||||
end;
|
|
||||||
{error, _} ->
|
|
||||||
{error, unknown_function}
|
|
||||||
end;
|
|
||||||
{error, _What} ->
|
{error, _What} ->
|
||||||
{error, bad_call_data}
|
{error, bad_call_data}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
check_calldata(Hash, CallData, TypeInfo, true) ->
|
||||||
|
case is_payable(Hash, TypeInfo) of
|
||||||
|
{ok, true} -> check_calldata(Hash, CallData, TypeInfo, false);
|
||||||
|
{ok, false} -> {error, function_is_not_payable};
|
||||||
|
Err = {error, _} -> Err
|
||||||
|
end;
|
||||||
|
check_calldata(Hash, CallData, TypeInfo, false) ->
|
||||||
|
case typereps_from_type_hash(Hash, TypeInfo) of
|
||||||
|
{ok, ArgType, OutType} ->
|
||||||
|
try aeb_heap:from_binary({tuple, [word, ArgType]}, CallData) of
|
||||||
|
{ok, _Something} ->
|
||||||
|
{ok, {tuple, [word, ArgType]}, OutType};
|
||||||
|
{error, _} ->
|
||||||
|
{error, bad_call_data}
|
||||||
|
catch
|
||||||
|
_T:_E ->
|
||||||
|
{error, bad_call_data}
|
||||||
|
end;
|
||||||
|
{error, _} ->
|
||||||
|
{error, unknown_function}
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
-spec get_function_hash_from_calldata(CallData::binary()) ->
|
-spec get_function_hash_from_calldata(CallData::binary()) ->
|
||||||
{ok, binary()} | {error, term()}.
|
{ok, binary()} | {error, term()}.
|
||||||
get_function_hash_from_calldata(CallData) ->
|
get_function_hash_from_calldata(CallData) ->
|
||||||
@@ -86,12 +98,13 @@ get_function_hash_from_calldata(CallData) ->
|
|||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
%%% Handle type info from contract meta data
|
%%% Handle type info from contract meta data
|
||||||
|
|
||||||
-spec function_type_info(function_name(), [typerep()], typerep()) ->
|
-spec function_type_info(function_name(), boolean(), [typerep()], typerep()) ->
|
||||||
function_type_info().
|
function_type_info().
|
||||||
function_type_info(Name, ArgTypes, OutType) ->
|
function_type_info(Name, Payable, ArgTypes, OutType) ->
|
||||||
ArgType = {tuple, ArgTypes},
|
ArgType = {tuple, ArgTypes},
|
||||||
{ function_type_hash(Name, ArgType, OutType)
|
{ function_type_hash(Name, ArgType, OutType)
|
||||||
, Name
|
, Name
|
||||||
|
, Payable
|
||||||
, aeb_heap:to_binary(ArgType)
|
, aeb_heap:to_binary(ArgType)
|
||||||
, aeb_heap:to_binary(OutType)
|
, aeb_heap:to_binary(OutType)
|
||||||
}.
|
}.
|
||||||
@@ -110,35 +123,46 @@ function_type_hash(Name, ArgType, OutType) when is_binary(Name) ->
|
|||||||
{'ok', typerep()} | {'error', 'bad_type_data' | 'unknown_function'}.
|
{'ok', typerep()} | {'error', 'bad_type_data' | 'unknown_function'}.
|
||||||
arg_typerep_from_function(Function, TypeInfo) ->
|
arg_typerep_from_function(Function, TypeInfo) ->
|
||||||
case lists:keyfind(Function, 2, TypeInfo) of
|
case lists:keyfind(Function, 2, TypeInfo) of
|
||||||
{_TypeHash, Function, ArgTypeBin,_OutTypeBin} ->
|
{_TypeHash, Function, ArgTypeBin, _OutTypeBin} ->
|
||||||
case aeb_heap:from_binary(typerep, ArgTypeBin) of
|
arg_typerep_from_type_binary(ArgTypeBin);
|
||||||
{ok, ArgType} -> {ok, ArgType};
|
{_TypeHash, Function, _Payable, ArgTypeBin, _OutTypeBin} ->
|
||||||
{error,_} -> {error, bad_type_data}
|
arg_typerep_from_type_binary(ArgTypeBin);
|
||||||
end;
|
|
||||||
false ->
|
false ->
|
||||||
{error, unknown_function}
|
{error, unknown_function}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
arg_typerep_from_type_binary(ArgTBin) ->
|
||||||
|
case aeb_heap:from_binary(typerep, ArgTBin) of
|
||||||
|
{ok, ArgT} -> {ok, ArgT};
|
||||||
|
{error,_} -> {error, bad_type_data}
|
||||||
|
end.
|
||||||
|
|
||||||
-spec typereps_from_type_hash(hash(), type_info()) ->
|
-spec typereps_from_type_hash(hash(), type_info()) ->
|
||||||
{'ok', typerep(), typerep()} | {'error', 'bad_type_data' | 'unknown_function'}.
|
{'ok', typerep(), typerep()} | {'error', 'bad_type_data' | 'unknown_function'}.
|
||||||
typereps_from_type_hash(TypeHash, TypeInfo) ->
|
typereps_from_type_hash(TypeHash, TypeInfo) ->
|
||||||
case lists:keyfind(TypeHash, 1, TypeInfo) of
|
case lists:keyfind(TypeHash, 1, TypeInfo) of
|
||||||
{TypeHash,_Function, ArgTypeBin, OutTypeBin} ->
|
{TypeHash, _Function, ArgTypeBin, OutTypeBin} ->
|
||||||
case {aeb_heap:from_binary(typerep, ArgTypeBin),
|
typereps_from_type_binaries(ArgTypeBin, OutTypeBin);
|
||||||
aeb_heap:from_binary(typerep, OutTypeBin)} of
|
{TypeHash, _Function, _Payable, ArgTypeBin, OutTypeBin} ->
|
||||||
{{ok, ArgType}, {ok, OutType}} -> {ok, ArgType, OutType};
|
typereps_from_type_binaries(ArgTypeBin, OutTypeBin);
|
||||||
{_, _} -> {error, bad_type_data}
|
|
||||||
end;
|
|
||||||
false ->
|
false ->
|
||||||
{error, unknown_function}
|
{error, unknown_function}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
typereps_from_type_binaries(ArgTBin, OutTBin) ->
|
||||||
|
case {aeb_heap:from_binary(typerep, ArgTBin), aeb_heap:from_binary(typerep, OutTBin)} of
|
||||||
|
{{ok, ArgT}, {ok, OutT}} -> {ok, ArgT, OutT};
|
||||||
|
{_, _} -> {error, bad_type_data}
|
||||||
|
end.
|
||||||
|
|
||||||
-spec function_name_from_type_hash(hash(), type_info()) ->
|
-spec function_name_from_type_hash(hash(), type_info()) ->
|
||||||
{'ok', function_name()}
|
{'ok', function_name()}
|
||||||
| {'error', 'unknown_function'}.
|
| {'error', 'unknown_function'}.
|
||||||
function_name_from_type_hash(TypeHash, TypeInfo) ->
|
function_name_from_type_hash(TypeHash, TypeInfo) ->
|
||||||
case lists:keyfind(TypeHash, 1, TypeInfo) of
|
case lists:keyfind(TypeHash, 1, TypeInfo) of
|
||||||
{TypeHash, Function,_ArgTypeBin,_OutTypeBin} ->
|
{TypeHash, Function, _ArgTypeBin, _OutTypeBin} ->
|
||||||
|
{ok, Function};
|
||||||
|
{TypeHash, Function, _Payable, _ArgTypeBin, _OutTypeBin} ->
|
||||||
{ok, Function};
|
{ok, Function};
|
||||||
false ->
|
false ->
|
||||||
{error, unknown_function}
|
{error, unknown_function}
|
||||||
@@ -149,8 +173,22 @@ function_name_from_type_hash(TypeHash, TypeInfo) ->
|
|||||||
| {'error', 'unknown_function'}.
|
| {'error', 'unknown_function'}.
|
||||||
type_hash_from_function_name(Name, TypeInfo) ->
|
type_hash_from_function_name(Name, TypeInfo) ->
|
||||||
case lists:keyfind(Name, 2, TypeInfo) of
|
case lists:keyfind(Name, 2, TypeInfo) of
|
||||||
{TypeHash, Name,_ArgTypeBin,_OutTypeBin} ->
|
{TypeHash, Name, _ArgTypeBin, _OutTypeBin} ->
|
||||||
|
{ok, TypeHash};
|
||||||
|
{TypeHash, Name, _Payable, _ArgTypeBin, _OutTypeBin} ->
|
||||||
{ok, TypeHash};
|
{ok, TypeHash};
|
||||||
false ->
|
false ->
|
||||||
{error, unknown_function}
|
{error, unknown_function}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
-spec is_payable(hash(), type_info()) -> {ok, boolean()} | {error, 'unknown_function'}.
|
||||||
|
is_payable(TypeHash, TypeInfo) ->
|
||||||
|
case lists:keyfind(TypeHash, 1, TypeInfo) of
|
||||||
|
{TypeHash, _Function, _ArgTypeBin, _OutTypeBin} ->
|
||||||
|
{ok, true};
|
||||||
|
{TypeHash, _Function, Payable, _ArgTypeBin, _OutTypeBin} ->
|
||||||
|
{ok, Payable};
|
||||||
|
false ->
|
||||||
|
{error, unknown_function}
|
||||||
|
end.
|
||||||
|
|
||||||
|
|||||||
@@ -37,9 +37,11 @@ create_calldata(FunName, Args) ->
|
|||||||
-spec decode_calldata(list(), binary()) -> {ok, term()} | {error, term()}.
|
-spec decode_calldata(list(), binary()) -> {ok, term()} | {error, term()}.
|
||||||
decode_calldata(FunName, Calldata) ->
|
decode_calldata(FunName, Calldata) ->
|
||||||
FunctionId = aeb_fate_code:symbol_identifier(list_to_binary(FunName)),
|
FunctionId = aeb_fate_code:symbol_identifier(list_to_binary(FunName)),
|
||||||
case ?FATE_TUPLE_ELEMENTS(aeb_fate_encoding:deserialize(Calldata)) of
|
try ?FATE_TUPLE_ELEMENTS(aeb_fate_encoding:deserialize(Calldata)) of
|
||||||
[FunctionId, FateArgs] -> {ok, ?FATE_TUPLE_ELEMENTS(FateArgs)};
|
[FunctionId, FateArgs] -> {ok, ?FATE_TUPLE_ELEMENTS(FateArgs)};
|
||||||
_ -> {error, decode_error}
|
_ -> {error, decode_error}
|
||||||
|
catch _:_ ->
|
||||||
|
{error, decode_error}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec get_function_name_from_function_hash(binary(), aeb_fate_code:fcode()) ->
|
-spec get_function_name_from_function_hash(binary(), aeb_fate_code:fcode()) ->
|
||||||
@@ -72,6 +74,6 @@ get_function_type_from_function_hash(SymbolHash, FateCode) ->
|
|||||||
case maps:get(SymbolHash, Functions, undefined) of
|
case maps:get(SymbolHash, Functions, undefined) of
|
||||||
undefined ->
|
undefined ->
|
||||||
{error, no_function_matching_function_hash};
|
{error, no_function_matching_function_hash};
|
||||||
{{ArgTypes, RetType}, _Code} ->
|
{_Attrs, {ArgTypes, RetType}, _Code} ->
|
||||||
{ok, ArgTypes, RetType}
|
{ok, ArgTypes, RetType}
|
||||||
end.
|
end.
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ format_functions(Functions, Symbols) ->
|
|||||||
lists:sort(maps:to_list(CodeMap)),
|
lists:sort(maps:to_list(CodeMap)),
|
||||||
Symbols)
|
Symbols)
|
||||||
||
|
||
|
||||||
{Name, {Sig, CodeMap}} <- maps:to_list(Functions)].
|
{Name, {_Attrs, Sig, CodeMap}} <- maps:to_list(Functions)].
|
||||||
|
|
||||||
|
|
||||||
format(Name, Sig, BBs, Symbols) ->
|
format(Name, Sig, BBs, Symbols) ->
|
||||||
@@ -484,7 +484,7 @@ insert_fun({NameString, ArgType, RetType}, Code, #{ fate_code := FateCode
|
|||||||
{FateCode1, Id} = aeb_fate_code:insert_symbol(Name, FateCode),
|
{FateCode1, Id} = aeb_fate_code:insert_symbol(Name, FateCode),
|
||||||
BodyByteCode = aeb_fate_code:serialize_code(lists:reverse(Code)),
|
BodyByteCode = aeb_fate_code:serialize_code(lists:reverse(Code)),
|
||||||
SigByteCode = aeb_fate_code:serialize_signature({ArgType, RetType}),
|
SigByteCode = aeb_fate_code:serialize_signature({ArgType, RetType}),
|
||||||
FunByteCode = [?FUNCTION, Id, SigByteCode, BodyByteCode],
|
FunByteCode = [?FUNCTION, Id, aeb_fate_encoding:serialize(0), SigByteCode, BodyByteCode],
|
||||||
Env#{ functions => Funs#{ Id => FunByteCode }
|
Env#{ functions => Funs#{ Id => FunByteCode }
|
||||||
, fate_code => FateCode1}.
|
, fate_code => FateCode1}.
|
||||||
|
|
||||||
|
|||||||
+50
-21
@@ -11,7 +11,7 @@
|
|||||||
, deserialize/1
|
, deserialize/1
|
||||||
, functions/1
|
, functions/1
|
||||||
, insert_annotation/4
|
, insert_annotation/4
|
||||||
, insert_fun/4
|
, insert_fun/5
|
||||||
, insert_symbol/2
|
, insert_symbol/2
|
||||||
, new/0
|
, new/0
|
||||||
, serialize/1
|
, serialize/1
|
||||||
@@ -19,6 +19,7 @@
|
|||||||
, serialize/3
|
, serialize/3
|
||||||
, serialize_code/1
|
, serialize_code/1
|
||||||
, serialize_signature/1
|
, serialize_signature/1
|
||||||
|
, strip_init_function/1
|
||||||
, symbol_identifier/1
|
, symbol_identifier/1
|
||||||
, symbols/1
|
, symbols/1
|
||||||
]).
|
]).
|
||||||
@@ -72,9 +73,9 @@ symbol_identifier(Bin) ->
|
|||||||
{ok, <<X:4/binary,_/binary>> } = eblake2:blake2b(?HASH_BYTES, Bin),
|
{ok, <<X:4/binary,_/binary>> } = eblake2:blake2b(?HASH_BYTES, Bin),
|
||||||
X.
|
X.
|
||||||
|
|
||||||
insert_fun(Name, {ArgType, RetType}, #{} = BBs, FCode) ->
|
insert_fun(Name, Attrs, {ArgType, RetType}, #{} = BBs, FCode) ->
|
||||||
{F1, ID} = insert_symbol(Name, FCode),
|
{F1, ID} = insert_symbol(Name, FCode),
|
||||||
update_functions(F1, #{ID => {{ArgType, RetType}, BBs}}).
|
update_functions(F1, #{ID => {Attrs, {ArgType, RetType}, BBs}}).
|
||||||
|
|
||||||
insert_symbol(Name, #fcode{ symbols = Syms } = F) ->
|
insert_symbol(Name, #fcode{ symbols = Syms } = F) ->
|
||||||
ID = symbol_identifier(Name),
|
ID = symbol_identifier(Name),
|
||||||
@@ -92,6 +93,13 @@ insert_annotation(comment =_Type, Line, Comment, FCode) ->
|
|||||||
Value = aeb_fate_data:make_string(Comment),
|
Value = aeb_fate_data:make_string(Comment),
|
||||||
update_annotations(FCode, #{ Key => Value }).
|
update_annotations(FCode, #{ Key => Value }).
|
||||||
|
|
||||||
|
strip_init_function(#fcode{ functions = Funs,
|
||||||
|
symbols = Syms } = FCode) ->
|
||||||
|
Id = symbol_identifier(<<"init">>),
|
||||||
|
Funs1 = maps:remove(Id, Funs),
|
||||||
|
Syms1 = maps:remove(Id, Syms),
|
||||||
|
FCode#fcode{ functions = Funs1, symbols = Syms1 }.
|
||||||
|
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
%%% Serialization
|
%%% Serialization
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
@@ -128,10 +136,17 @@ to_hexstring(ByteList) ->
|
|||||||
serialize_functions(#fcode{ functions = Functions }) ->
|
serialize_functions(#fcode{ functions = Functions }) ->
|
||||||
%% Sort the functions on name to get a canonical serialisation.
|
%% Sort the functions on name to get a canonical serialisation.
|
||||||
iolist_to_binary(
|
iolist_to_binary(
|
||||||
lists:foldr(fun({Id, {Sig, C}}, Acc) ->
|
lists:foldr(fun({Id, {Attrs, Sig, C}}, Acc) ->
|
||||||
[[?FUNCTION, Id, serialize_signature(Sig), serialize_bbs(C)] | Acc]
|
[[?FUNCTION, Id, serialize_attributes(Attrs), serialize_signature(Sig), serialize_bbs(C)] | Acc]
|
||||||
end, [], lists:sort(maps:to_list(Functions)))).
|
end, [], lists:sort(maps:to_list(Functions)))).
|
||||||
|
|
||||||
|
serialize_attributes(Attrs) ->
|
||||||
|
AttrVal = lists:sum([ attr_value(Attr) || Attr <- Attrs ]),
|
||||||
|
aeb_fate_encoding:serialize(?MAKE_FATE_INTEGER(AttrVal)).
|
||||||
|
|
||||||
|
attr_value(private) -> 1;
|
||||||
|
attr_value(payable) -> 2.
|
||||||
|
|
||||||
serialize_signature({Args, RetType}) ->
|
serialize_signature({Args, RetType}) ->
|
||||||
[aeb_fate_encoding:serialize_type({tuple, Args}) |
|
[aeb_fate_encoding:serialize_type({tuple, Args}) |
|
||||||
aeb_fate_encoding:serialize_type(RetType)].
|
aeb_fate_encoding:serialize_type(RetType)].
|
||||||
@@ -139,7 +154,7 @@ serialize_signature({Args, RetType}) ->
|
|||||||
serialize_symbol_table(#fcode{ symbols = Symbols }) ->
|
serialize_symbol_table(#fcode{ symbols = Symbols }) ->
|
||||||
aeb_fate_encoding:serialize(aeb_fate_data:make_map(Symbols)).
|
aeb_fate_encoding:serialize(aeb_fate_data:make_map(Symbols)).
|
||||||
|
|
||||||
serialize_annotations(#fcode{ annotations = Annotations}) ->
|
serialize_annotations(#fcode{ annotations = Annotations }) ->
|
||||||
aeb_fate_encoding:serialize(aeb_fate_data:make_map(Annotations)).
|
aeb_fate_encoding:serialize(aeb_fate_data:make_map(Annotations)).
|
||||||
|
|
||||||
serialize_bbs(#{} = BBs) ->
|
serialize_bbs(#{} = BBs) ->
|
||||||
@@ -166,8 +181,8 @@ serialize_op(Op) ->
|
|||||||
|
|
||||||
sanity_check(#fcode{ functions = Funs }) ->
|
sanity_check(#fcode{ functions = Funs }) ->
|
||||||
_ = [ case Def of
|
_ = [ case Def of
|
||||||
{_, BBs} when byte_size(Id) == 4 -> sanity_check_bbs(BBs);
|
{_, _, BBs} when byte_size(Id) == 4 -> sanity_check_bbs(BBs);
|
||||||
_ -> error({illegal_function_id, Id})
|
_ -> error({illegal_function_id, Id})
|
||||||
end || {Id, Def} <- maps:to_list(Funs) ],
|
end || {Id, Def} <- maps:to_list(Funs) ],
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
@@ -303,33 +318,35 @@ deserialize_functions(<<?FUNCTION:8, A, B, C, D, Rest/binary>>,
|
|||||||
, bb := 0
|
, bb := 0
|
||||||
, current_bb_code := []
|
, current_bb_code := []
|
||||||
} = Env) ->
|
} = Env) ->
|
||||||
{Sig, Rest2} = deserialize_signature(Rest),
|
{Attrs, Rest2} = deserialize_attributes(Rest),
|
||||||
Env2 = Env#{function => {<<A,B,C,D>>, Sig}},
|
{Sig, Rest3} = deserialize_signature(Rest2),
|
||||||
deserialize_functions(Rest2, Env2);
|
Env2 = Env#{function => {<<A,B,C,D>>, Attrs, Sig}},
|
||||||
|
deserialize_functions(Rest3, Env2);
|
||||||
deserialize_functions(<<?FUNCTION:8, A, B, C, D, Rest/binary>>,
|
deserialize_functions(<<?FUNCTION:8, A, B, C, D, Rest/binary>>,
|
||||||
#{ function := {F, Sig}
|
#{ function := {F, Attrs, Sig}
|
||||||
, bb := BB
|
, bb := BB
|
||||||
, current_bb_code := Code
|
, current_bb_code := Code
|
||||||
, code := Program
|
, code := Program
|
||||||
, functions := Funs} = Env) ->
|
, functions := Funs} = Env) ->
|
||||||
{NewSig, Rest2} = deserialize_signature(Rest),
|
{NewAttrs, Rest2} = deserialize_attributes(Rest),
|
||||||
|
{NewSig, Rest3} = deserialize_signature(Rest2),
|
||||||
case Code of
|
case Code of
|
||||||
[] ->
|
[] ->
|
||||||
Env2 = Env#{ bb => 0
|
Env2 = Env#{ bb => 0
|
||||||
, current_bb_code => []
|
, current_bb_code => []
|
||||||
, function => {<<A,B,C,D>>, NewSig}
|
, function => {<<A,B,C,D>>, NewAttrs, NewSig}
|
||||||
, code => #{}
|
, code => #{}
|
||||||
, functions => Funs#{F => {Sig, Program}}},
|
, functions => Funs#{F => {Attrs, Sig, Program}}},
|
||||||
deserialize_functions(Rest2, Env2);
|
deserialize_functions(Rest3, Env2);
|
||||||
_ ->
|
_ ->
|
||||||
Env2 = Env#{ bb => 0
|
Env2 = Env#{ bb => 0
|
||||||
, current_bb_code => []
|
, current_bb_code => []
|
||||||
, function => {<<A,B,C,D>>, NewSig}
|
, function => {<<A,B,C,D>>, NewAttrs, NewSig}
|
||||||
, code => #{}
|
, code => #{}
|
||||||
, functions =>
|
, functions =>
|
||||||
Funs#{F => {Sig,
|
Funs#{F => {Attrs, Sig,
|
||||||
Program#{ BB => lists:reverse(Code)}}}},
|
Program#{ BB => lists:reverse(Code)}}}},
|
||||||
deserialize_functions(Rest2, Env2)
|
deserialize_functions(Rest3, Env2)
|
||||||
end;
|
end;
|
||||||
deserialize_functions(<<_Op:8, _Rest/binary>>,
|
deserialize_functions(<<_Op:8, _Rest/binary>>,
|
||||||
#{ function := none }) ->
|
#{ function := none }) ->
|
||||||
@@ -351,7 +368,7 @@ deserialize_functions(<<Op:8, Rest/binary>>,
|
|||||||
deserialize_functions(<<>>, #{ function := none
|
deserialize_functions(<<>>, #{ function := none
|
||||||
, functions := Funs}) ->
|
, functions := Funs}) ->
|
||||||
Funs;
|
Funs;
|
||||||
deserialize_functions(<<>>, #{ function := {F, Sig}
|
deserialize_functions(<<>>, #{ function := {F, Attrs, Sig}
|
||||||
, bb := BB
|
, bb := BB
|
||||||
, current_bb_code := Code
|
, current_bb_code := Code
|
||||||
, code := Program
|
, code := Program
|
||||||
@@ -361,7 +378,7 @@ deserialize_functions(<<>>, #{ function := {F, Sig}
|
|||||||
[] -> Program;
|
[] -> Program;
|
||||||
_ -> Program#{ BB => lists:reverse(Code)}
|
_ -> Program#{ BB => lists:reverse(Code)}
|
||||||
end,
|
end,
|
||||||
Funs#{F => {Sig, FunctionCode}}.
|
Funs#{F => {Attrs, Sig, FunctionCode}}.
|
||||||
|
|
||||||
deserialize_op(Op, Rest, Code) ->
|
deserialize_op(Op, Rest, Code) ->
|
||||||
OpName = aeb_fate_opcodes:mnemonic(Op),
|
OpName = aeb_fate_opcodes:mnemonic(Op),
|
||||||
@@ -399,6 +416,18 @@ deserialize_n_args(N, <<M7:2, M6:2, M5:2, M4:2, M3:2, M2:2, M1:2, M0:2,
|
|||||||
end
|
end
|
||||||
end, Rest, ArgMods).
|
end, Rest, ArgMods).
|
||||||
|
|
||||||
|
deserialize_attributes(Binary) ->
|
||||||
|
{AttrVal, Rest} = aeb_fate_encoding:deserialize_one(Binary),
|
||||||
|
Attrs = [ attr(AVal) || AVal <- attr_vals(1, AttrVal) ],
|
||||||
|
{lists:sort(Attrs), Rest}.
|
||||||
|
|
||||||
|
attr_vals(_, 0) -> [];
|
||||||
|
attr_vals(X, N) when N rem 2 == 0 -> attr_vals(X + 1, N div 2);
|
||||||
|
attr_vals(X, N) -> [X | attr_vals(X + 1, N div 2)].
|
||||||
|
|
||||||
|
attr(1) -> private;
|
||||||
|
attr(2) -> payable.
|
||||||
|
|
||||||
deserialize_signature(Binary) ->
|
deserialize_signature(Binary) ->
|
||||||
{{tuple, Args}, Rest} = aeb_fate_encoding:deserialize_type(Binary),
|
{{tuple, Args}, Rest} = aeb_fate_encoding:deserialize_type(Binary),
|
||||||
{RetType, Rest2} = aeb_fate_encoding:deserialize_type(Rest),
|
{RetType, Rest2} = aeb_fate_encoding:deserialize_type(Rest),
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
-type fate_variant() :: ?FATE_VARIANT_T.
|
-type fate_variant() :: ?FATE_VARIANT_T.
|
||||||
-type fate_tuple() :: ?FATE_TUPLE_T.
|
-type fate_tuple() :: ?FATE_TUPLE_T.
|
||||||
-type fate_bits() :: ?FATE_BITS_T.
|
-type fate_bits() :: ?FATE_BITS_T.
|
||||||
|
-type fate_typerep() :: ?FATE_TYPEREP_T.
|
||||||
|
|
||||||
-type fate_type_type() :: integer
|
-type fate_type_type() :: integer
|
||||||
| boolean
|
| boolean
|
||||||
@@ -54,7 +55,8 @@
|
|||||||
| fate_channel()
|
| fate_channel()
|
||||||
| fate_variant()
|
| fate_variant()
|
||||||
| fate_map()
|
| fate_map()
|
||||||
| fate_bits().
|
| fate_bits()
|
||||||
|
| fate_typerep().
|
||||||
|
|
||||||
-export_type([fate_type/0
|
-export_type([fate_type/0
|
||||||
, fate_boolean/0
|
, fate_boolean/0
|
||||||
|
|||||||
@@ -123,6 +123,7 @@
|
|||||||
X =:= ?TYPE_TUPLE orelse
|
X =:= ?TYPE_TUPLE orelse
|
||||||
X =:= ?TYPE_OBJECT orelse
|
X =:= ?TYPE_OBJECT orelse
|
||||||
X =:= ?TYPE_BITS orelse
|
X =:= ?TYPE_BITS orelse
|
||||||
|
X =:= ?TYPE_BYTES orelse
|
||||||
X =:= ?TYPE_MAP orelse
|
X =:= ?TYPE_MAP orelse
|
||||||
X =:= ?TYPE_STRING orelse
|
X =:= ?TYPE_STRING orelse
|
||||||
X =:= ?TYPE_VARIANT)).
|
X =:= ?TYPE_VARIANT)).
|
||||||
@@ -487,5 +488,11 @@ sort(KVList) ->
|
|||||||
|
|
||||||
valid_key_type(K) when ?IS_FATE_MAP(K) ->
|
valid_key_type(K) when ?IS_FATE_MAP(K) ->
|
||||||
error({map_as_key_in_map, K});
|
error({map_as_key_in_map, K});
|
||||||
|
valid_key_type(?FATE_STORE_MAP(_, _) = K) ->
|
||||||
|
error({map_as_key_in_map, K});
|
||||||
|
valid_key_type(K) when is_list(K) ->
|
||||||
|
lists:all(fun(E) -> valid_key_type(E) end, K);
|
||||||
|
valid_key_type(K) when is_tuple(K) ->
|
||||||
|
lists:all(fun(E) -> valid_key_type(E) end, tuple_to_list(K));
|
||||||
valid_key_type(_K) ->
|
valid_key_type(_K) ->
|
||||||
true.
|
true.
|
||||||
|
|||||||
+192
-148
@@ -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),
|
||||||
@@ -43,144 +43,176 @@ check_numbering(_, []) -> true.
|
|||||||
%% TODO: Some real gas numbers...
|
%% TODO: Some real gas numbers...
|
||||||
ops_defs() ->
|
ops_defs() ->
|
||||||
%% Opname, Opcode, end_bb, in_auth offchain, gas, format, Constructor, ArgType, ResType, Documentation
|
%% Opname, Opcode, end_bb, in_auth offchain, gas, format, Constructor, ArgType, ResType, Documentation
|
||||||
[ { '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, 10, [], 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, 10, [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, 10, [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, 100, [a,is,a,a,a], call_r, {contract, string, typerep, typerep, integer}, any, "Remote call to contract Arg0 and function Arg1 of type Arg2 => Arg3 with value Arg4. The types of the arguments has to match the argument types of the function."}
|
||||||
, { 'CALL_T', 16#04, true, true, true, 4, [a], call_t, {string}, any, "Tail call to function Arg0. The types of the arguments has to match the argument typs of the function. And the return type of the called function has to match the type of the current function."}
|
, { 'CALL_T', 16#04, true, true, true, 10, [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#05, true, false, true, 100, [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,ii,a,a], call_gr, {contract, string, integer, integer, integer}, any, "Remote call with gas cap in Arg3. Otherwise as CALL_R."}
|
, { 'JUMP', 16#06, true, true, true, 10, [ii], jump, {integer}, none, "Jump to a basic block. The basic block has to exist in the current function."}
|
||||||
, { 'UNUSED_2', 16#07, false, false, true, 8, [], unused_2, {}, none, "Was CALL_GTR."}
|
, { 'JUMPIF', 16#07, true, true, true, 10, [a,ii], jumpif, {boolean, integer}, none, "Conditional jump to a basic block. If Arg0 then jump to Arg1."}
|
||||||
, { '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."}
|
, { 'SWITCH_V2', 16#08, true, true, true, 10, [a,ii,ii], switch, {variant, integer, ingeger}, none, "Conditional jump to a basic block on variant tag."}
|
||||||
, { '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_V3', 16#09, true, true, true, 10, [a,ii,ii,ii], switch, {variant, integer, 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."}
|
, { 'SWITCH_VN', 16#0a, true, true, true, 10, [a, li], switch, {variant, {list, integer}}, none, "Conditional jump to a basic block on variant tag."}
|
||||||
, { 'SWITCH_V3', 16#0b, true, true, true, 4, [a,ii,ii,ii], switch, {variant, integer, integer, ingeger}, none, "Conditional jump to a basic block on variant tag."}
|
, { 'CALL_VALUE', 16#0b, false, true, true, 10, [a], call_value, {}, integer, "The value sent in the current remote call."}
|
||||||
, { 'SWITCH_VN', 16#0c, true, true, true, 4, [a, li], switch, {variant, {list, integer}}, none, "Conditional jump to a basic block on variant tag."}
|
, { 'PUSH', 16#0c, false, true, true, 10, [a], push, {any}, any, "Push argument to stack."}
|
||||||
, { 'CALL_VALUE', 16#0d, false, true, true, 3, [a], call_value, {}, integer, "The value sent in the current remote call."}
|
, { 'DUPA', 16#0d, false, true, true, 10, [], dup, {any}, any, "Duplicate top of stack."}
|
||||||
, { 'PUSH', 16#0e, false, true, true, 2, [a], push, {any}, any, "Push argument to stack."}
|
, { 'DUP', 16#0e, false, true, true, 10, [a], dup, {any}, any, "push Arg0 stack pos on top of stack."}
|
||||||
, { 'DUPA', 16#0f, false, true, true, 3, [], dup, {any}, any, "Duplicate top of stack."}
|
, { 'POP', 16#0f, false, true, true, 10, [a], pop, {integer}, integer, "Arg0 := top of stack."}
|
||||||
, { 'DUP', 16#10, false, true, true, 3, [a], dup, {any}, any, "push Arg0 stack pos on top of stack."}
|
, { 'INCA', 16#10, false, true, true, 10, [], inc, {integer}, integer, "Increment accumulator."}
|
||||||
, { 'POP', 16#11, false, true, true, 3, [a], pop, {integer}, integer, "Arg0 := top of stack."}
|
, { 'INC', 16#11, false, true, true, 10, [a], inc, {integer}, integer, "Increment argument."}
|
||||||
, { 'INCA', 16#12, false, true, true, 2, [], inc, {integer}, integer, "Increment accumulator."}
|
, { 'DECA', 16#12, false, true, true, 10, [], dec, {integer}, integer, "Decrement accumulator."}
|
||||||
, { 'INC', 16#13, false, true, true, 2, [a], inc, {integer}, integer, "Increment argument."}
|
, { 'DEC', 16#13, false, true, true, 10, [a], dec, {integer}, integer, "Decrement argument."}
|
||||||
, { 'DECA', 16#14, false, true, true, 2, [], dec, {integer}, integer, "Decrement accumulator."}
|
, { 'ADD', 16#14, false, true, true, 10, [a,a,a], add, {integer, integer}, integer, "Arg0 := Arg1 + Arg2."}
|
||||||
, { 'DEC', 16#15, false, true, true, 2, [a], dec, {integer}, integer, "Decrement argument."}
|
, { 'SUB', 16#15, false, true, true, 10, [a,a,a], sub, {integer, integer}, integer, "Arg0 := Arg1 - Arg2."}
|
||||||
, { 'ADD', 16#16, false, true, true, 3, [a,a,a], add, {integer, integer}, integer, "Arg0 := Arg1 + Arg2."}
|
, { 'MUL', 16#16, false, true, true, 10, [a,a,a], mul, {integer, integer}, integer, "Arg0 := Arg1 * Arg2."}
|
||||||
, { 'SUB', 16#17, false, true, true, 3, [a,a,a], sub, {integer, integer}, integer, "Arg0 := Arg1 - Arg2."}
|
, { 'DIV', 16#17, false, true, true, 10, [a,a,a], divide, {integer, integer}, integer, "Arg0 := Arg1 / Arg2."}
|
||||||
, { 'MUL', 16#18, false, true, true, 3, [a,a,a], mul, {integer, integer}, integer, "Arg0 := Arg1 * Arg2."}
|
, { 'MOD', 16#18, false, true, true, 10, [a,a,a], modulo, {integer, integer}, integer, "Arg0 := Arg1 mod Arg2."}
|
||||||
, { 'DIV', 16#19, false, true, true, 3, [a,a,a], divide, {integer, integer}, integer, "Arg0 := Arg1 / Arg2."}
|
, { 'POW', 16#19, false, true, true, 10, [a,a,a], pow, {integer, integer}, integer, "Arg0 := Arg1 ^ Arg2."}
|
||||||
, { 'MOD', 16#1a, false, true, true, 3, [a,a,a], modulo, {integer, integer}, integer, "Arg0 := Arg1 mod Arg2."}
|
, { 'STORE', 16#1a, false, true, true, 10, [a,a], store, {any}, any, "Arg0 := Arg1."}
|
||||||
, { 'POW', 16#1b, false, true, true, 3, [a,a,a], pow, {integer, integer}, integer, "Arg0 := Arg1 ^ Arg2."}
|
, { 'SHA3', 16#1b, false, true, true, 100, [a,a], sha3, {any}, hash, "Arg0 := sha3(Arg1)."}
|
||||||
, { 'STORE', 16#1c, false, true, true, 3, [a,a], store, {any}, any, "Arg0 := Arg1."}
|
, { 'SHA256', 16#1c, false, true, true, 100, [a,a], sha256, {any}, hash, "Arg0 := sha256(Arg1)."}
|
||||||
, { 'SHA3', 16#1d, false, true, true, 30, [a,a], sha3, {any}, hash, "Arg0 := sha3(Arg1)."}
|
, { 'BLAKE2B', 16#1d, false, true, true, 100, [a,a], blake2b, {any}, hash, "Arg0 := blake2b(Arg1)."}
|
||||||
, { 'SHA256', 16#1e, false, true, true, 30, [a,a], sha256, {any}, hash, "Arg0 := sha256(Arg1)."}
|
, { 'LT', 16#1e, false, true, true, 10, [a,a,a], lt, {integer, integer}, boolean, "Arg0 := Arg1 < Arg2."}
|
||||||
, { 'BLAKE2B', 16#1f, false, true, true, 30, [a,a], blake2b, {any}, hash, "Arg0 := blake2b(Arg1)."}
|
, { 'GT', 16#1f, false, true, true, 10, [a,a,a], gt, {integer, integer}, boolean, "Arg0 := Arg1 > Arg2."}
|
||||||
, { 'LT', 16#20, false, true, true, 3, [a,a,a], lt, {integer, integer}, boolean, "Arg0 := Arg1 < Arg2."}
|
, { 'EQ', 16#20, false, true, true, 10, [a,a,a], eq, {integer, integer}, boolean, "Arg0 := Arg1 = Arg2."}
|
||||||
, { 'GT', 16#21, false, true, true, 3, [a,a,a], gt, {integer, integer}, boolean, "Arg0 := Arg1 > Arg2."}
|
, { 'ELT', 16#21, false, true, true, 10, [a,a,a], elt, {integer, integer}, boolean, "Arg0 := Arg1 =< Arg2."}
|
||||||
, { 'EQ', 16#22, false, true, true, 3, [a,a,a], eq, {integer, integer}, boolean, "Arg0 := Arg1 = Arg2."}
|
, { 'EGT', 16#22, false, true, true, 10, [a,a,a], egt, {integer, integer}, boolean, "Arg0 := Arg1 >= Arg2."}
|
||||||
, { 'ELT', 16#23, false, true, true, 3, [a,a,a], elt, {integer, integer}, boolean, "Arg0 := Arg1 =< Arg2."}
|
, { 'NEQ', 16#23, false, true, true, 10, [a,a,a], neq, {integer, integer}, boolean, "Arg0 := Arg1 /= Arg2."}
|
||||||
, { 'EGT', 16#24, false, true, true, 3, [a,a,a], egt, {integer, integer}, boolean, "Arg0 := Arg1 >= Arg2."}
|
, { 'AND', 16#24, false, true, true, 10, [a,a,a], and_op, {boolean, boolean}, boolean, "Arg0 := Arg1 and Arg2."}
|
||||||
, { 'NEQ', 16#25, false, true, true, 3, [a,a,a], neq, {integer, integer}, boolean, "Arg0 := Arg1 /= Arg2."}
|
, { 'OR', 16#25, false, true, true, 10, [a,a,a], or_op, {boolean, boolean}, boolean, "Arg0 := Arg1 or Arg2."}
|
||||||
, { 'AND', 16#26, false, true, true, 3, [a,a,a], and_op, {boolean, boolean}, boolean, "Arg0 := Arg1 and Arg2."}
|
, { 'NOT', 16#26, false, true, true, 10, [a,a], not_op, {boolean}, boolean, "Arg0 := not Arg1."}
|
||||||
, { 'OR', 16#27, false, true, true, 3, [a,a,a], or_op, {boolean, boolean}, boolean, "Arg0 := Arg1 or Arg2."}
|
, { 'TUPLE', 16#27, false, true, true, 10, [a,ii], tuple, {integer}, tuple, "Arg0 := tuple of size = Arg1. Elements on stack."}
|
||||||
, { 'NOT', 16#28, false, true, true, 3, [a,a], not_op, {boolean}, boolean, "Arg0 := not Arg1."}
|
, { 'ELEMENT', 16#28, false, true, true, 10, [a,a,a], element_op, {integer, tuple}, any, "Arg1 := element(Arg2, Arg3)."}
|
||||||
, { 'TUPLE', 16#29, false, true, true, 3, [a,ii], tuple, {integer}, tuple, "Arg0 := tuple of size = Arg1. Elements on stack."}
|
, { 'SETELEMENT', 16#29, false, true, true, 10, [a,a,a,a], setelement, {integer, tuple, any}, tuple, "Arg0 := a new tuple similar to Arg2, but with element number Arg1 replaced by Arg3."}
|
||||||
, { 'ELEMENT', 16#2a, false, true, true, 3, [a,a,a], element_op, {integer, tuple}, any, "Arg1 := element(Arg2, Arg3)."}
|
, { 'MAP_EMPTY', 16#2a, false, true, true, 10, [a], map_empty, {}, map, "Arg0 := #{}."}
|
||||||
, { 'SETELEMENT', 16#2b, false, true, true, 3, [a,a,a,a], setelement, {integer, tuple, any}, tuple, "Arg0 := a new tuple similar to Arg2, but with element number Arg1 replaced by Arg3."}
|
, { 'MAP_LOOKUP', 16#2b, false, true, true, 10, [a,a,a], map_lookup, {map, any}, any, "Arg0 := lookup key Arg2 in map Arg1."}
|
||||||
, { 'MAP_EMPTY', 16#2c, false, true, true, 3, [a], map_empty, {}, map, "Arg0 := #{}."}
|
, { 'MAP_LOOKUPD', 16#2c, false, true, true, 10, [a,a,a,a], map_lookup, {map, any, any}, any, "Arg0 := lookup key Arg2 in map Arg1 if key exists in map otherwise Arg0 := Arg3."}
|
||||||
, { 'MAP_LOOKUP', 16#2d, false, true, true, 3, [a,a,a], map_lookup, {map, any}, any, "Arg0 := lookup key Arg2 in map Arg1."}
|
, { 'MAP_UPDATE', 16#2d, false, true, true, 10, [a,a,a,a], map_update, {map, any, any}, map, "Arg0 := update key Arg2 in map Arg1 with value Arg3."}
|
||||||
, { 'MAP_LOOKUPD', 16#2e, false, true, true, 3, [a,a,a,a], map_lookup, {map, any, any}, any, "Arg0 := lookup key Arg2 in map Arg1 if key exists in map otherwise Arg0 := Arg3."}
|
, { 'MAP_DELETE', 16#2e, false, true, true, 10, [a,a,a], map_delete, {map, any}, map, "Arg0 := delete key Arg2 from map Arg1."}
|
||||||
, { 'MAP_UPDATE', 16#2f, false, true, true, 3, [a,a,a,a], map_update, {map, any, any}, map, "Arg0 := update key Arg2 in map Arg1 with value Arg3."}
|
, { 'MAP_MEMBER', 16#2f, false, true, true, 10, [a,a,a], map_member, {map, any}, boolean, "Arg0 := true if key Arg2 is in map Arg1."}
|
||||||
, { 'MAP_DELETE', 16#30, false, true, true, 3, [a,a,a], map_delete, {map, any}, map, "Arg0 := delete key Arg2 from map Arg1."}
|
, { 'MAP_FROM_LIST', 16#30, false, true, true, 10, [a,a], map_from_list, {{list, {tuple, [any, any]}}}, map, "Arg0 := make a map from (key, value) list in Arg1."}
|
||||||
, { 'MAP_MEMBER', 16#31, false, true, true, 3, [a,a,a], map_member, {map, any}, boolean, "Arg0 := true if key Arg2 is in map Arg1."}
|
, { 'MAP_SIZE', 16#31, false, true, true, 10, [a,a], map_size_, {map}, integer, "Arg0 := The size of the map Arg1."}
|
||||||
, { 'MAP_FROM_LIST', 16#32, false, true, true, 3, [a,a], map_from_list, {{list, {tuple, [any, any]}}}, map, "Arg0 := make a map from (key, value) list in Arg1."}
|
, { 'MAP_TO_LIST', 16#32, false, true, true, 10, [a,a], map_to_list, {map}, list, "Arg0 := The tuple list representation of the map Arg1."}
|
||||||
, { 'IS_NIL', 16#33, false, true, true, 3, [a,a], is_nil, {list}, boolean, "Arg0 := true if Arg1 == []."}
|
, { 'IS_NIL', 16#33, false, true, true, 10, [a,a], is_nil, {list}, boolean, "Arg0 := true if Arg1 == []."}
|
||||||
, { 'CONS', 16#34, false, true, true, 3, [a,a,a], cons, {any, list}, list, "Arg0 := [Arg1|Arg2]."}
|
, { 'CONS', 16#34, false, true, true, 10, [a,a,a], cons, {any, list}, list, "Arg0 := [Arg1|Arg2]."}
|
||||||
, { 'HD', 16#35, false, true, true, 3, [a,a], hd, {list}, any, "Arg0 := head of list Arg1."}
|
, { 'HD', 16#35, false, true, true, 10, [a,a], hd, {list}, any, "Arg0 := head of list Arg1."}
|
||||||
, { 'TL', 16#36, false, true, true, 3, [a,a], tl, {list}, list, "Arg0 := tail of list Arg1."}
|
, { 'TL', 16#36, false, true, true, 10, [a,a], tl, {list}, list, "Arg0 := tail of list Arg1."}
|
||||||
, { 'LENGTH', 16#37, false, true, true, 3, [a,a], length, {list}, integer, "Arg0 := length of list Arg1."}
|
, { 'LENGTH', 16#37, false, true, true, 10, [a,a], length, {list}, integer, "Arg0 := length of list Arg1."}
|
||||||
, { 'NIL', 16#38, false, true, true, 3, [a], nil, {}, list, "Arg0 := []."}
|
, { 'NIL', 16#38, false, true, true, 10, [a], nil, {}, list, "Arg0 := []."}
|
||||||
, { 'STR_JOIN', 16#39, false, true, true, 3, [a,a,a], str_join, {string, string}, string, "Arg0 := string Arg1 followed by string Arg2."}
|
, { 'APPEND', 16#39, false, true, true, 10, [a,a,a], append, {list, list}, list, "Arg0 := Arg1 ++ Arg2."}
|
||||||
, { 'INT_TO_STR', 16#3a, false, true, true, 3, [a,a], int_to_str, {integer}, string, "Arg0 := turn integer Arg1 into a string."}
|
, { 'STR_JOIN', 16#3a, false, true, true, 10, [a,a,a], str_join, {string, string}, string, "Arg0 := string Arg1 followed by string Arg2."}
|
||||||
, { 'ADDR_TO_STR', 16#3b, false, true, true, 3, [a,a], addr_to_str, {address}, string, "Arg0 := turn address Arg1 into a string."}
|
, { 'INT_TO_STR', 16#3b, false, true, true, 100, [a,a], int_to_str, {integer}, string, "Arg0 := turn integer Arg1 into a string."}
|
||||||
, { 'STR_REVERSE', 16#3c, false, true, true, 3, [a,a], str_reverse, {string}, string, "Arg0 := the reverse of string Arg1."}
|
, { 'ADDR_TO_STR', 16#3c, false, true, true, 100, [a,a], addr_to_str, {address}, string, "Arg0 := turn address Arg1 into a string."}
|
||||||
, { 'APPEND', 16#3d, false, true, true, 3, [a,a,a], append, {list, list}, list, "Arg0 := Arg1 ++ Arg2."}
|
, { 'STR_REVERSE', 16#3d, false, true, true, 100, [a,a], str_reverse, {string}, string, "Arg0 := the reverse of string Arg1."}
|
||||||
, { 'INT_TO_ADDR', 16#3e, false, true, true, 3, [a,a], int_to_addr, {integer}, address, "Arg0 := turn integer Arg1 into an address."}
|
, { 'STR_LENGTH', 16#3e, false, true, true, 10, [a,a], str_length, {string}, integer, "Arg0 := The length of the string Arg1."}
|
||||||
, { 'VARIANT', 16#3f, false, true, true, 3, [a,a,a,a], variant, {integer, integer, integer}, variant, "Arg0 := create a variant of size Arg1 with the tag Arg2 (Arg2 < Arg1) and take Arg3 elements from the stack."}
|
, { 'BYTES_TO_INT', 16#3f, false, true, true, 10, [a,a], bytes_to_int, {bytes}, integer, "Arg0 := bytes_to_int(Arg1)"}
|
||||||
, { 'VARIANT_TEST', 16#40, false, true, true, 3, [a,a,a], variant_test, {variant, integer}, boolean, "Arg0 := true if variant Arg1 has the tag Arg2."}
|
, { 'BYTES_TO_STR', 16#40, false, true, true, 100, [a,a], bytes_to_str, {bytes}, string, "Arg0 := bytes_to_str(Arg1)"}
|
||||||
, { 'VARIANT_ELEMENT', 16#41, false, true, true, 3, [a,a,a], variant_element, {variant, integer}, any, "Arg0 := element number Arg2 from variant Arg1."}
|
, { 'BYTES_CONCAT', 16#41, false, true, true, 10, [a,a,a], bytes_concat, {bytes, bytes}, bytes, "Arg0 := bytes_concat(Arg1, Arg2)"}
|
||||||
, { 'BITS_NONEA', 16#42, false, true, true, 3, [], bits_none, {}, bits, "push an empty bitmap on the stack."}
|
, { 'BYTES_SPLIT', 16#42, false, true, true, 10, [a,a,a], bytes_split, {bytes, integer}, bytes, "Arg0 := bytes_split(Arg2, Arg1), where Arg2 is the length of the first chunk."}
|
||||||
, { 'BITS_NONE', 16#43, false, true, true, 3, [a], bits_none, {}, bits, "Arg0 := empty bitmap."}
|
, { 'INT_TO_ADDR', 16#43, false, true, true, 10, [a,a], int_to_addr, {integer}, address, "Arg0 := turn integer Arg1 into an address."}
|
||||||
, { 'BITS_ALLA', 16#44, false, true, true, 3, [], bits_all, {}, bits, "push a full bitmap on the stack."}
|
, { 'VARIANT', 16#44, false, true, true, 10, [a,a,a,a], variant, {integer, integer, integer}, variant, "Arg0 := create a variant of size Arg1 with the tag Arg2 (Arg2 < Arg1) and take Arg3 elements from the stack."}
|
||||||
, { 'BITS_ALL', 16#45, false, true, true, 3, [a], bits_all, {}, bits, "Arg0 := full bitmap."}
|
, { 'VARIANT_TEST', 16#45, false, true, true, 10, [a,a,a], variant_test, {variant, integer}, boolean, "Arg0 := true if variant Arg1 has the tag Arg2."}
|
||||||
, { 'BITS_ALL_N', 16#46, false, true, true, 3, [a,a], bits_all_n, {integer}, bits, "Arg0 := bitmap with Arg1 bits set."}
|
, { 'VARIANT_ELEMENT', 16#46, false, true, true, 10, [a,a,a], variant_element, {variant, integer}, any, "Arg0 := element number Arg2 from variant Arg1."}
|
||||||
, { 'BITS_SET', 16#47, false, true, true, 3, [a,a,a], bits_set, {bits, integer}, bits, "Arg0 := set bit Arg2 of bitmap Arg1."}
|
, { 'BITS_NONEA', 16#47, false, true, true, 10, [], bits_none, {}, bits, "push an empty bitmap on the stack."}
|
||||||
, { 'BITS_CLEAR', 16#48, false, true, true, 3, [a,a,a], bits_clear, {bits, integer}, bits, "Arg0 := clear bit Arg2 of bitmap Arg1."}
|
, { 'BITS_NONE', 16#48, false, true, true, 10, [a], bits_none, {}, bits, "Arg0 := empty bitmap."}
|
||||||
, { 'BITS_TEST', 16#49, false, true, true, 3, [a,a,a], bits_test, {bits, integer}, boolean, "Arg0 := true if bit Arg2 of bitmap Arg1 is set."}
|
, { 'BITS_ALLA', 16#49, false, true, true, 10, [], bits_all, {}, bits, "push a full bitmap on the stack."}
|
||||||
, { 'BITS_SUM', 16#4a, false, true, true, 3, [a,a], bits_sum, {bits}, integer, "Arg0 := sum of set bits in bitmap Arg1. Exception if infinit bitmap."}
|
, { 'BITS_ALL', 16#4a, false, true, true, 10, [a], bits_all, {}, bits, "Arg0 := full bitmap."}
|
||||||
, { 'BITS_OR', 16#4b, false, true, true, 3, [a,a,a], bits_or, {bits, bits}, bits, "Arg0 := Arg1 v Arg2."}
|
, { 'BITS_ALL_N', 16#4b, false, true, true, 10, [a,a], bits_all_n, {integer}, bits, "Arg0 := bitmap with Arg1 bits set."}
|
||||||
, { 'BITS_AND', 16#4c, false, true, true, 3, [a,a,a], bits_and, {bits, bits}, bits, "Arg0 := Arg1 ^ Arg2."}
|
, { 'BITS_SET', 16#4c, false, true, true, 10, [a,a,a], bits_set, {bits, integer}, bits, "Arg0 := set bit Arg2 of bitmap Arg1."}
|
||||||
, { 'BITS_DIFF', 16#4d, false, true, true, 3, [a,a,a], bits_diff, {bits, bits}, bits, "Arg0 := Arg1 - Arg2."}
|
, { 'BITS_CLEAR', 16#4d, false, true, true, 10, [a,a,a], bits_clear, {bits, integer}, bits, "Arg0 := clear bit Arg2 of bitmap Arg1."}
|
||||||
, { 'BALANCE', 16#4e, false, true, true, 3, [a], balance, {}, integer, "Arg0 := The current contract balance."}
|
, { 'BITS_TEST', 16#4e, false, true, true, 10, [a,a,a], bits_test, {bits, integer}, boolean, "Arg0 := true if bit Arg2 of bitmap Arg1 is set."}
|
||||||
, { 'ORIGIN', 16#4f, false, true, true, 3, [a], origin, {}, address, "Arg0 := Address of contract called by the call transaction."}
|
, { 'BITS_SUM', 16#4f, false, true, true, 10, [a,a], bits_sum, {bits}, integer, "Arg0 := sum of set bits in bitmap Arg1. Exception if infinit bitmap."}
|
||||||
, { 'CALLER', 16#50, false, true, true, 3, [a], caller, {}, address, "Arg0 := The address that signed the call transaction."}
|
, { 'BITS_OR', 16#50, false, true, true, 10, [a,a,a], bits_or, {bits, bits}, bits, "Arg0 := Arg1 v Arg2."}
|
||||||
, { 'GASPRICE', 16#51, false, true, true, 3, [a], gasprice, {}, integer, "Arg0 := The current gas price."}
|
, { 'BITS_AND', 16#51, false, true, true, 10, [a,a,a], bits_and, {bits, bits}, bits, "Arg0 := Arg1 ^ Arg2."}
|
||||||
, { 'BLOCKHASH', 16#52, false, true, true, 3, [a,a], blockhash, {integer}, hash, "Arg0 := The blockhash at height."}
|
, { 'BITS_DIFF', 16#52, false, true, true, 10, [a,a,a], bits_diff, {bits, bits}, bits, "Arg0 := Arg1 - Arg2."}
|
||||||
, { 'BENEFICIARY', 16#53, false, true, true, 3, [a], beneficiary, {}, address, "Arg0 := The address of the current beneficiary."}
|
, { 'BALANCE', 16#53, false, true, true, 10, [a], balance, {}, integer, "Arg0 := The current contract balance."}
|
||||||
, { 'TIMESTAMP', 16#54, false, true, true, 3, [a], timestamp, {}, integer, "Arg0 := The current timestamp. Unrelaiable, don't use for anything."}
|
, { 'ORIGIN', 16#54, false, true, true, 10, [a], origin, {}, address, "Arg0 := Address of contract called by the call transaction."}
|
||||||
, { 'GENERATION', 16#55, false, true, true, 3, [a], generation, {}, integer, "Arg0 := The block height of the cureent generation."}
|
, { 'CALLER', 16#55, false, true, true, 10, [a], caller, {}, address, "Arg0 := The address that signed the call transaction."}
|
||||||
, { 'MICROBLOCK', 16#56, false, true, true, 3, [a], microblock, {}, integer, "Arg0 := The current micro block number."}
|
, { 'BLOCKHASH', 16#56, false, true, true, 10, [a,a], blockhash, {integer}, hash, "Arg0 := The blockhash at height."}
|
||||||
, { 'DIFFICULTY', 16#57, false, true, true, 3, [a], difficulty, {}, integer, "Arg0 := The current difficulty."}
|
, { 'BENEFICIARY', 16#57, false, true, true, 10, [a], beneficiary, {}, address, "Arg0 := The address of the current beneficiary."}
|
||||||
, { 'GASLIMIT', 16#58, false, true, true, 3, [a], gaslimit, {}, integer, "Arg0 := The current gaslimit."}
|
, { 'TIMESTAMP', 16#58, false, true, true, 10, [a], timestamp, {}, integer, "Arg0 := The current timestamp. Unrelaiable, don't use for anything."}
|
||||||
, { 'GAS', 16#59, false, true, true, 3, [a], gas, {}, integer, "Arg0 := The amount of gas left."}
|
, { 'GENERATION', 16#59, false, true, true, 10, [a], generation, {}, integer, "Arg0 := The block height of the cureent generation."}
|
||||||
, { 'ADDRESS', 16#5a, false, true, true, 3, [a], address, {}, address, "Arg0 := The current contract address."}
|
, { 'MICROBLOCK', 16#5a, false, true, true, 10, [a], microblock, {}, integer, "Arg0 := The current micro block number."}
|
||||||
|
, { 'DIFFICULTY', 16#5b, false, true, true, 10, [a], difficulty, {}, integer, "Arg0 := The current difficulty."}
|
||||||
|
, { 'GASLIMIT', 16#5c, false, true, true, 10, [a], gaslimit, {}, integer, "Arg0 := The current gaslimit."}
|
||||||
|
, { 'GAS', 16#5d, false, true, true, 10, [a], gas, {}, integer, "Arg0 := The amount of gas left."}
|
||||||
|
, { 'ADDRESS', 16#5e, false, true, true, 10, [a], address, {}, address, "Arg0 := The current contract address."}
|
||||||
|
, { 'GASPRICE', 16#5f, false, true, true, 10, [a], gasprice, {}, integer, "Arg0 := The current gas price."}
|
||||||
|
|
||||||
, { 'LOG0', 16#5b, false, true, true, 3, [a], log, {string}, none, "Create a log message in the call object."}
|
, { 'LOG0', 16#60, false, true, true, 1000, [a], log, {string}, none, "Create a log message in the call object."}
|
||||||
, { 'LOG1', 16#5c, false, true, true, 3, [a,a], log, {integer, string}, none, "Create a log message with one topic in the call object."}
|
, { 'LOG1', 16#61, false, true, true, 1100, [a,a], log, {integer, string}, none, "Create a log message with one topic in the call object."}
|
||||||
, { 'LOG2', 16#5d, false, true, true, 3, [a,a,a], log, {integer, integer, string}, none, "Create a log message with two topics in the call object."}
|
, { 'LOG2', 16#62, false, true, true, 1200, [a,a,a], log, {integer, integer, string}, none, "Create a log message with two topics in the call object."}
|
||||||
, { 'LOG3', 16#5e, false, true, true, 3, [a,a,a,a], log, {integer, integer, integer, string}, none, "Create a log message with three topics in the call object."}
|
, { 'LOG3', 16#63, false, true, true, 1300, [a,a,a,a], log, {integer, integer, integer, string}, none, "Create a log message with three topics in the call object."}
|
||||||
, { 'LOG4', 16#5f, false, true, true, 3, [a,a,a,a,a], log, {integer, integer, integer, integer, string}, none, "Create a log message with four topics in the call object."}
|
, { 'LOG4', 16#64, false, true, true, 1400, [a,a,a,a,a], log, {integer, integer, integer, integer, string}, none, "Create a log message with four topics in the call object."}
|
||||||
%% Transaction ops
|
%% Transaction ops
|
||||||
, { 'SPEND', 16#60, false, false, true, 3, [a,a], spend, {address, integer}, none, "Transfer Arg1 tokens to account Arg0. (If the contract account has at least that many tokens."}
|
, { 'SPEND', 16#65, false, false, true, 100, [a,a], spend, {address, integer}, none, "Transfer Arg1 tokens to account Arg0. (If the contract account has at least that many tokens."}
|
||||||
, { 'ORACLE_REGISTER', 16#61, false, false, false, 3, [a,a,a,a,a,a,a], oracle_register, {signature, address, integer, variant, typerep, typerep}, oracle, "Arg0 := New oracle with address Arg2, query fee Arg3, TTL Arg4, query type Arg5 and response type Arg6. Arg0 contains delegation signature."}
|
, { 'ORACLE_REGISTER', 16#66, false, false, false, 100, [a,a,a,a,a,a,a], oracle_register, {signature, address, integer, variant, typerep, typerep}, oracle, "Arg0 := New oracle with address Arg2, query fee Arg3, TTL Arg4, query type Arg5 and response type Arg6. Arg0 contains delegation signature."}
|
||||||
, { 'ORACLE_QUERY', 16#62, false, false, false, 3, [a,a,a,a,a,a,a,a], oracle_query, {oracle, any, integer, variant, variant, typerep, typerep}, oracle_query, "Arg0 := New oracle query for oracle Arg1, question in Arg2, query fee in Arg3, query TTL in Arg4, response TTL in Arg5. Typereps for checking oracle type is in Arg6 and Arg7."}
|
, { 'ORACLE_QUERY', 16#67, false, false, false, 100, [a,a,a,a,a,a,a,a], oracle_query, {oracle, any, integer, variant, variant, typerep, typerep}, oracle_query, "Arg0 := New oracle query for oracle Arg1, question in Arg2, query fee in Arg3, query TTL in Arg4, response TTL in Arg5. Typereps for checking oracle type is in Arg6 and Arg7."}
|
||||||
, { 'ORACLE_RESPOND', 16#63, false, false, false, 3, [a,a,a,a,a,a], oracle_respond, {signature, oracle, oracle_query,any, typerep, typerep}, none, "Respond as oracle Arg1 to query in Arg2 with response Arg3. Arg0 contains delegation signature. Typereps for checking oracle type is in Arg4 and Arg5."}
|
, { 'ORACLE_RESPOND', 16#68, false, false, false, 100, [a,a,a,a,a,a], oracle_respond, {signature, oracle, oracle_query,any, typerep, typerep}, none, "Respond as oracle Arg1 to query in Arg2 with response Arg3. Arg0 contains delegation signature. Typereps for checking oracle type is in Arg4 and Arg5."}
|
||||||
, { 'ORACLE_EXTEND', 16#64, false, false, false, 3, [a,a,a], oracle_extend, {signature, oracle, variant}, none, "Extend oracle in Arg1 with TTL in Arg2. Arg0 contains delegation signature."}
|
, { 'ORACLE_EXTEND', 16#69, false, false, false, 100, [a,a,a], oracle_extend, {signature, oracle, variant}, none, "Extend oracle in Arg1 with TTL in Arg2. Arg0 contains delegation signature."}
|
||||||
, { 'ORACLE_GET_ANSWER', 16#65, false, false, true, 3, [a,a,a,a,a], oracle_get_answer, {oracle, oracle_query, typerep, typerep}, any, "Arg0 := option variant with answer (if any) from oracle query in Arg1 given by oracle Arg0. Typereps for checking oracle type is in Arg3 and Arg4."}
|
, { 'ORACLE_GET_ANSWER', 16#6a, false, false, true, 100, [a,a,a,a,a], oracle_get_answer, {oracle, oracle_query, typerep, typerep}, any, "Arg0 := option variant with answer (if any) from oracle query in Arg1 given by oracle Arg0. Typereps for checking oracle type is in Arg3 and Arg4."}
|
||||||
, { 'ORACLE_GET_QUESTION', 16#66, false, false, true, 3, [a,a,a,a,a], oracle_get_question, {oracle, oracle_query, typerep, typerep}, any, "Arg0 := question in oracle query Arg2 given to oracle Arg1. Typereps for checking oracle type is in Arg3 and Arg4."}
|
, { 'ORACLE_GET_QUESTION', 16#6b, false, false, true, 100, [a,a,a,a,a], oracle_get_question, {oracle, oracle_query, typerep, typerep}, any, "Arg0 := question in oracle query Arg2 given to oracle Arg1. Typereps for checking oracle type is in Arg3 and Arg4."}
|
||||||
, { '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#6c, false, false, true, 100, [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#6d, false, false, true, 100, [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#6e, false, false, false, 100, [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#6f, false, false, false, 100, [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#70, false, false, false, 100, [a,a,a,a,a,a], aens_update, {signature, address, string, variant, variant, variant}, none, "Updates name in Arg2 for address in Arg1. Arg3 contains optional ttl (of type Chain.ttl), Arg4 contains optional client_ttl (of type int), Arg5 contains optional pointers (of type map(string, pointee))"}
|
||||||
, { '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#71, false, false, false, 100, [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#72, false, false, false, 100, [a,a,a], aens_revoke, {signature, address, string}, none, "Revoke the name in Arg2 from owner Arg1. Arg0 contains delegation signature."}
|
||||||
, { 'BALANCE_OTHER', 16#6e, false, true, true, 3, [a,a], balance_other, {address}, integer, "Arg0 := The balance of address Arg1."}
|
, { 'BALANCE_OTHER', 16#73, false, true, true, 50, [a,a], balance_other, {address}, integer, "Arg0 := The balance of address Arg1."}
|
||||||
%% TODO: Reorder these before documenting the specification
|
|
||||||
, { 'MAP_SIZE', 16#6f, false, true, true, 3, [a,a], map_size_, {map}, integer, "Arg0 := The size 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."}
|
|
||||||
|
|
||||||
, { 'ECVERIFY', 16#72, false, true, true, 1300, [a,a,a,a], ecverify, {bytes, address, bytes}, boolean, "Arg0 := ecverify(Hash, PubKey, Signature)"}
|
, { 'VERIFY_SIG', 16#74, false, true, true, 1300, [a,a,a,a], verify_sig, {bytes, address, bytes}, boolean, "Arg0 := verify_sig(Hash, PubKey, Signature)"}
|
||||||
, { 'ECVERIFY_SECP256K1', 16#73, false, true, true, 1300, [a,a,a,a], ecverify_secp256k1, {bytes, bytes, bytes}, boolean, "Arg0 := ecverify_secp256k1(Hash, PubKey, Signature)"}
|
, { 'VERIFY_SIG_SECP256K1',16#75, false, true, true, 1300, [a,a,a,a], verify_sig_secp256k1, {bytes, bytes, bytes}, boolean, "Arg0 := verify_sig_secp256k1(Hash, PubKey, Signature)"}
|
||||||
|
|
||||||
, { 'CONTRACT_TO_ADDRESS', 16#74, false, true, true, 3, [a,a], contract_to_address, {contract}, address, "Arg0 := Arg1 - A no-op type conversion"}
|
, { 'CONTRACT_TO_ADDRESS', 16#76, false, true, true, 10, [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#77, false, true, true, 10, [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)"}
|
, { 'ORACLE_CHECK', 16#78, false, false, true, 100, [a,a,a,a], oracle_check, {oracle, typerep, typerep}, bool, "Arg0 := is Arg1 an oracle with the given query (Arg2) and response (Arg3) types"}
|
||||||
, { 'BYTES_TO_STR', 16#77, false, true, true, 3, [a,a], bytes_to_str, {bytes}, string, "Arg0 := bytes_to_str(Arg1)"}
|
, { 'ORACLE_CHECK_QUERY', 16#79, false, false, true, 100, [a,a,a,a,a], oracle_check_query, {oracle, oracle_query, typerep, typerep}, bool, "Arg0 := is Arg2 a query for the oracle Arg1 with the given types (Arg3, Arg4)"}
|
||||||
|
|
||||||
, { 'ORACLE_CHECK', 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"}
|
, { 'IS_ORACLE', 16#7a, false, false, true, 100, [a,a], is_oracle, {address}, bool, "Arg0 := is Arg1 an oracle"}
|
||||||
, { '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_CONTRACT', 16#7b, false, false, true, 100, [a,a], is_contract, {address}, bool, "Arg0 := is Arg1 a contract"}
|
||||||
|
, { 'IS_PAYABLE', 16#7c, false, false, true, 100, [a,a], is_payable, {address}, bool, "Arg0 := is Arg1 a payable address"}
|
||||||
|
, { 'CREATOR', 16#7d, false, true, true, 10, [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"}
|
, { 'ECVERIFY_SECP256K1', 16#7e, false, true, true, 1300, [a,a,a,a], ecverify_secp256k1, {bytes, bytes, bytes}, bytes, "Arg0 := ecverify_secp256k1(Hash, Addr, Signature)"}
|
||||||
, { 'IS_CONTRACT', 16#7b, false, false, true, 3, [a,a], is_contract, {address}, bool, "Arg0 := is Arg1 a contract"}
|
, { 'ECRECOVER_SECP256K1', 16#7f, false, true, true, 1300, [a,a,a], ecrecover_secp256k1, {bytes, bytes}, bytes, "Arg0 := ecrecover_secp256k1(Hash, Signature)"}
|
||||||
, { 'CREATOR', 16#7c, false, true, true, 3, [a], contract_creator, {}, address, "Arg0 := contract creator"}
|
|
||||||
|
|
||||||
, { 'DEACTIVATE', 16#fa, false, true, true, 3, [], deactivate, {}, none, "Mark the current contract for deactivation."}
|
, { 'ADDRESS_TO_CONTRACT', 16#80, false, true, true, 10, [a,a], address_to_contract, {address}, contract, "Arg0 := Arg1 - A no-op type conversion"}
|
||||||
, { '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."}
|
, { 'BLS12_381_G1_NEG', 16#81, false, true, true, 100, [a,a], bls12_381_g1_neg, {tuple}, tuple, "Arg0 := BLS12_381.g1_neg(Arg1) - Negate a G1-value"}
|
||||||
, { 'NOP', 16#fd, false, true, true, 1, [], nop, {}, none, "The no op. does nothing."}
|
, { 'BLS12_381_G1_NORM', 16#82, false, true, true, 100, [a,a], bls12_381_g1_norm, {tuple}, tuple, "Arg0 := BLS12_381.g1_normalize(Arg1) - Normalize a G1-value"}
|
||||||
|
, { 'BLS12_381_G1_VALID', 16#83, false, true, true, 2000, [a,a], bls12_381_g1_valid, {tuple}, bool, "Arg0 := BLS12_381.g1_valid(Arg1) - Check if G1-value is a valid group member"}
|
||||||
|
, { 'BLS12_381_G1_IS_ZERO', 16#84, false, true, true, 30, [a,a], bls12_381_g1_is_zero, {tuple}, bool, "Arg0 := BLS12_381.g1_is_zero(Arg1) - Check if G1-value is zero"}
|
||||||
|
, { 'BLS12_381_G1_ADD', 16#85, false, true, true, 100, [a,a,a], bls12_381_g1_add, {tuple, tuple}, tuple, "Arg0 := BLS12_381.g1_add(Arg1, Arg2) - Add two G1-values"}
|
||||||
|
, { 'BLS12_381_G1_MUL', 16#86, false, true, true, 1000, [a,a,a], bls12_381_g1_mul, {tuple, tuple}, tuple, "Arg0 := BLS12_381.g1_mul(Arg1, Arg2) - Scalar multiplication for a G1-value (Arg1), and an Fr-value"}
|
||||||
|
|
||||||
|
, { 'BLS12_381_G2_NEG', 16#87, false, true, true, 100, [a,a], bls12_381_g2_neg, {tuple}, tuple, "Arg0 := BLS12_381.g2_neg(Arg1) - Negate a G2-value"}
|
||||||
|
, { 'BLS12_381_G2_NORM', 16#88, false, true, true, 100, [a,a], bls12_381_g2_norm, {tuple}, tuple, "Arg0 := BLS12_381.g2_normalize(Arg1) - Normalize a G2-value"}
|
||||||
|
, { 'BLS12_381_G2_VALID', 16#89, false, true, true, 2000, [a,a], bls12_381_g2_valid, {tuple}, bool, "Arg0 := BLS12_381.g2_valid(Arg1) - Check if G2-value is a valid group member"}
|
||||||
|
, { 'BLS12_381_G2_IS_ZERO', 16#8a, false, true, true, 30, [a,a], bls12_381_g2_is_zero, {tuple}, bool, "Arg0 := BLS12_381.g2_is_zero(Arg1) - Check if G2-value is zero"}
|
||||||
|
, { 'BLS12_381_G2_ADD', 16#8b, false, true, true, 100, [a,a,a], bls12_381_g2_add, {tuple, tuple}, tuple, "Arg0 := BLS12_381.g2_add(Arg1, Arg2) - Add two G2-values"}
|
||||||
|
, { 'BLS12_381_G2_MUL', 16#8c, false, true, true, 1000, [a,a,a], bls12_381_g2_mul, {tuple, tuple}, tuple, "Arg0 := BLS12_381.g2_mul(Arg1, Arg2) - Scalar multiplication for a G2-value (Arg2), and an Fr-value"}
|
||||||
|
|
||||||
|
, { 'BLS12_381_GT_INV', 16#8d, false, true, true, 100, [a,a], bls12_381_gt_inv, {tuple}, tuple, "Arg0 := BLS12_381.gt_inv(Arg1) - Invert a GT-value"}
|
||||||
|
, { 'BLS12_381_GT_ADD', 16#8e, false, true, true, 100, [a,a,a], bls12_381_gt_add, {tuple, tuple}, tuple, "Arg0 := BLS12_381.gt_add(Arg1, Arg2) - Add two GT-values"}
|
||||||
|
, { 'BLS12_381_GT_MUL', 16#8f, false, true, true, 100, [a,a,a], bls12_381_gt_mul, {tuple, tuple}, tuple, "Arg0 := BLS12_381.gt_mul(Arg1, Arg2) - Multiply two GT-values"}
|
||||||
|
, { 'BLS12_381_GT_POW', 16#90, false, true, true, 2000, [a,a,a], bls12_381_gt_pow, {tuple, tuple}, tuple, "Arg0 := BLS12_381.gt_pow(Arg1, Arg2) - Scalar exponentiation for a GT-value (Arg2), and an Fr-value"}
|
||||||
|
, { 'BLS12_381_GT_IS_ONE', 16#91, false, true, true, 30, [a,a], bls12_381_gt_is_one, {tuple}, bool, "Arg0 := BLS12_381.gt_is_one(Arg1) - Check if a GT value is \"one\""}
|
||||||
|
, { 'BLS12_381_PAIRING', 16#92, false, true, true, 12000, [a,a,a], bls12_381_pairing, {tuple, tuple}, tuple, "Arg0 := BLS12_381.pairing(Arg1, Arg2) - Find the pairing of a G1-value (Arg1) and a G2-value (Arg2)"}
|
||||||
|
, { 'BLS12_381_MILLER_LOOP', 16#93, false, true, true, 5000, [a,a,a], bls12_381_miller_loop, {tuple, tuple}, tuple, "Arg0 := BLS12_381.miller_loop(Arg1, Arg2) - Do the Miller-loop step of pairing for a G1-value (Arg1) and a G2-value (Arg2)"}
|
||||||
|
, { 'BLS12_381_FINAL_EXP', 16#94, false, true, true, 7000, [a,a], bls12_381_final_exp, {tuple}, tuple, "Arg0 := BLS12_381.final_exp(Arg1) - Do the final exponentiation in pairing"}
|
||||||
|
|
||||||
|
, { 'BLS12_381_INT_TO_FR', 16#95, false, true, true, 30, [a,a], bls12_381_int_to_fr, {tuple}, tuple, "Arg0 := to_montgomery(Arg1) - Convert (Big)integer to montgomery representation (32 bytes)"}
|
||||||
|
, { 'BLS12_381_INT_TO_FP', 16#96, false, true, true, 30, [a,a], bls12_381_int_to_fp, {tuple}, tuple, "Arg0 := to_montgomery(Arg1) - Convert (Big)integer to montgomery representation (48 bytes)"}
|
||||||
|
, { 'BLS12_381_FR_TO_INT', 16#97, false, true, true, 30, [a,a], bls12_381_fr_to_int, {tuple}, tuple, "Arg0 := from_montgomery(Arg1) - Convert montgomery representation (32 bytes) to integer"}
|
||||||
|
, { 'BLS12_381_FP_TO_INT', 16#98, false, true, true, 30, [a,a], bls12_381_fp_to_int, {tuple}, tuple, "Arg0 := from_montgomery(Arg1) - Convert montgomery representation (48 bytes) to integer"}
|
||||||
|
|
||||||
|
, { 'DEACTIVATE', 16#fa, false, true, true, 10, [], deactivate, {}, none, "Mark the current contract for deactivation."}
|
||||||
|
, { 'ABORT', 16#fb, true, true, true, 10, [a], abort, {string}, none, "Abort execution (dont use all gas) with error message in Arg0."}
|
||||||
|
, { 'EXIT', 16#fc, true, true, true, 10, [a], exit, {string}, none, "Abort execution (use upp all gas) with error message in Arg0."}
|
||||||
|
, { 'NOP', 16#fd, false, true, true, 1, [], nop, {}, none, "The no op. does nothing."}
|
||||||
%% FUNCTION 16#fe "Function declaration and entrypoint."
|
%% FUNCTION 16#fe "Function declaration and entrypoint."
|
||||||
%% EXTEND 16#ff "Reserved for future extensions beyond one byte opcodes."
|
%% EXTEND 16#ff "Reserved for future extensions beyond one byte opcodes."
|
||||||
].
|
].
|
||||||
@@ -206,6 +238,7 @@ generate_opcodes_ops(Modulename, HrlFile, SrcDir, Ops) ->
|
|||||||
EndBB = lists:flatten([gen_bb(Op) || Op <- Ops]),
|
EndBB = lists:flatten([gen_bb(Op) || Op <- Ops]),
|
||||||
InAuth = lists:flatten([gen_in_auth(Op) || Op <- Ops]),
|
InAuth = lists:flatten([gen_in_auth(Op) || Op <- Ops]),
|
||||||
Offchain = lists:flatten([gen_allowed_offchain(Op) || Op <- Ops]),
|
Offchain = lists:flatten([gen_allowed_offchain(Op) || Op <- Ops]),
|
||||||
|
GasCost = lists:flatten([gen_gas_cost(Op) || Op <- Ops]),
|
||||||
|
|
||||||
io:format(File, "~s", [prelude("Provides opcode primitives.\n")]),
|
io:format(File, "~s", [prelude("Provides opcode primitives.\n")]),
|
||||||
io:format(File, "~s", [ops_exports(Modulename, HrlFile,
|
io:format(File, "~s", [ops_exports(Modulename, HrlFile,
|
||||||
@@ -215,6 +248,7 @@ generate_opcodes_ops(Modulename, HrlFile, SrcDir, Ops) ->
|
|||||||
" , allowed_offchain/1\n"
|
" , allowed_offchain/1\n"
|
||||||
" , mnemonic/1\n"
|
" , mnemonic/1\n"
|
||||||
" , m_to_op/1\n"
|
" , m_to_op/1\n"
|
||||||
|
" , gas_cost/1\n"
|
||||||
])]),
|
])]),
|
||||||
|
|
||||||
io:format(File, "%% FATE mnemonics\n~s", [Mnemonic]),
|
io:format(File, "%% FATE mnemonics\n~s", [Mnemonic]),
|
||||||
@@ -235,6 +269,9 @@ generate_opcodes_ops(Modulename, HrlFile, SrcDir, Ops) ->
|
|||||||
io:format(File, "%% Is FATE Op allowed in a state channel offchain context?\n~s", [Offchain]),
|
io:format(File, "%% Is FATE Op allowed in a state channel offchain context?\n~s", [Offchain]),
|
||||||
io:format(File, "allowed_offchain(_) -> false.\n\n", []),
|
io:format(File, "allowed_offchain(_) -> false.\n\n", []),
|
||||||
|
|
||||||
|
io:format(File, "%% Base cost of operation\n~s", [GasCost]),
|
||||||
|
io:format(File, "gas_cost(Op) -> exit({bad_opcode, Op}).\n\n", []),
|
||||||
|
|
||||||
file:close(File).
|
file:close(File).
|
||||||
|
|
||||||
generate_code_ops(Modulename, SrcDir, Ops) ->
|
generate_code_ops(Modulename, SrcDir, Ops) ->
|
||||||
@@ -277,7 +314,7 @@ generate_code_ops(Modulename, SrcDir, Ops) ->
|
|||||||
file:close(File).
|
file:close(File).
|
||||||
|
|
||||||
gen_type(#{type_name := TypeName, type := Type}) ->
|
gen_type(#{type_name := TypeName, type := Type}) ->
|
||||||
lists:flatten(io_lib:format("-type ~-26s :: ~s.\n",
|
lists:flatten(io_lib:format("-type ~-29s :: ~s.\n",
|
||||||
[TypeName, Type])).
|
[TypeName, Type])).
|
||||||
|
|
||||||
gen_fate_code_type(#{type_name := TypeName}) ->
|
gen_fate_code_type(#{type_name := TypeName}) ->
|
||||||
@@ -355,29 +392,33 @@ ops_exports(Module, HrlFile, Exports) ->
|
|||||||
[Module, Exports])).
|
[Module, Exports])).
|
||||||
|
|
||||||
gen_mnemonic(#{opname := Name, macro := Macro}) ->
|
gen_mnemonic(#{opname := Name, macro := Macro}) ->
|
||||||
lists:flatten(io_lib:format("mnemonic(~21s) -> ~21w ;\n",
|
lists:flatten(io_lib:format("mnemonic(~24s) -> ~24w ;\n",
|
||||||
[Macro, Name])).
|
[Macro, Name])).
|
||||||
|
|
||||||
gen_m_to_op(#{opname := Name, macro := Macro}) ->
|
gen_m_to_op(#{opname := Name, macro := Macro}) ->
|
||||||
lists:flatten(io_lib:format("m_to_op(~21w) -> ~21s ;\n",
|
lists:flatten(io_lib:format("m_to_op(~24w) -> ~24s ;\n",
|
||||||
[Name, Macro])).
|
[Name, Macro])).
|
||||||
|
|
||||||
gen_args(#{macro := Macro, arity := Arity}) ->
|
gen_args(#{macro := Macro, arity := Arity}) ->
|
||||||
lists:flatten(io_lib:format("args(~21s) -> ~2w ;\n",
|
lists:flatten(io_lib:format("args(~24s) -> ~2w ;\n",
|
||||||
[Macro, Arity])).
|
[Macro, Arity])).
|
||||||
|
|
||||||
gen_bb(#{macro := Macro, end_bb := EndBB}) ->
|
gen_bb(#{macro := Macro, end_bb := EndBB}) ->
|
||||||
lists:flatten(io_lib:format("end_bb(~21s) -> ~w ;\n",
|
lists:flatten(io_lib:format("end_bb(~24s) -> ~w ;\n",
|
||||||
[Macro, EndBB])).
|
[Macro, EndBB])).
|
||||||
|
|
||||||
gen_in_auth(#{macro := Macro, in_auth := InAuth}) ->
|
gen_in_auth(#{macro := Macro, in_auth := InAuth}) ->
|
||||||
lists:flatten(io_lib:format("in_auth(~21s) -> ~w ;\n",
|
lists:flatten(io_lib:format("in_auth(~24s) -> ~w ;\n",
|
||||||
[Macro, InAuth])).
|
[Macro, InAuth])).
|
||||||
|
|
||||||
gen_allowed_offchain(#{macro := Macro, offchain := Offchain}) ->
|
gen_allowed_offchain(#{macro := Macro, offchain := Offchain}) ->
|
||||||
lists:flatten(io_lib:format("allowed_offchain(~21s) -> ~w ;\n",
|
lists:flatten(io_lib:format("allowed_offchain(~24s) -> ~w ;\n",
|
||||||
[Macro, Offchain])).
|
[Macro, Offchain])).
|
||||||
|
|
||||||
|
gen_gas_cost(#{macro := Macro, gas := Gas}) ->
|
||||||
|
lists:flatten(io_lib:format("gas_cost(~24s) -> ~w ;\n",
|
||||||
|
[Macro, Gas])).
|
||||||
|
|
||||||
prelude(Doc) ->
|
prelude(Doc) ->
|
||||||
"%%%-------------------------------------------------------------------\n"
|
"%%%-------------------------------------------------------------------\n"
|
||||||
"%%% @copyright (C) 2019, Aeternity Anstalt\n"
|
"%%% @copyright (C) 2019, Aeternity Anstalt\n"
|
||||||
@@ -392,7 +433,7 @@ prelude(Doc) ->
|
|||||||
|
|
||||||
|
|
||||||
gen_defines(#{opname := Name, opcode := OpCode}) ->
|
gen_defines(#{opname := Name, opcode := OpCode}) ->
|
||||||
lists:flatten(io_lib:format("-define(~-26w, 16#~2.16.0b).\n", [Name, OpCode])).
|
lists:flatten(io_lib:format("-define(~-29w, 16#~2.16.0b).\n", [Name, OpCode])).
|
||||||
|
|
||||||
gen([]) ->
|
gen([]) ->
|
||||||
[];
|
[];
|
||||||
@@ -489,28 +530,32 @@ gen_asm_pp(Module, Path, Ops) ->
|
|||||||
file:close(File).
|
file:close(File).
|
||||||
|
|
||||||
gen_format(#{opname := Name}) when (Name =:= 'CALL_R') ->
|
gen_format(#{opname := Name}) when (Name =:= 'CALL_R') ->
|
||||||
io_lib:format("format_op({~w, {immediate, Contract}, {immediate, Function}, Arity, Value}, Symbols) ->\n"
|
io_lib:format("format_op({~w, {immediate, Contract}, {immediate, Function}, ArgType, RetType, Value}, Symbols) ->\n"
|
||||||
" [\"~s \", lookup(Contract, Symbols), \".\", "
|
" [\"~s \", lookup(Contract, Symbols), \".\", "
|
||||||
"lookup(Function, Symbols), \" \", "
|
"lookup(Function, Symbols), \" \", "
|
||||||
"format_arg(a, Arity), \" \", "
|
"format_arg(a, ArgType), \" \", "
|
||||||
|
"format_arg(a, RetType), \" \", "
|
||||||
"format_arg(a, Value)];\n"
|
"format_arg(a, Value)];\n"
|
||||||
"format_op({~w, Contract, {immediate, Function}, Arity, Value}, Symbols) ->\n"
|
"format_op({~w, Contract, {immediate, Function}, ArgType, RetType, Value}, Symbols) ->\n"
|
||||||
"[\"~s \", format_arg(a, Contract), \".\", "
|
"[\"~s \", format_arg(a, Contract), \".\", "
|
||||||
"lookup(Function, Symbols), \" \", "
|
"lookup(Function, Symbols), \" \", "
|
||||||
"format_arg(a, Arity), \" \", "
|
"format_arg(a, ArgType), \" \", "
|
||||||
|
"format_arg(a, RetType), \" \", "
|
||||||
"format_arg(a, Value)];\n",
|
"format_arg(a, Value)];\n",
|
||||||
[Name, atom_to_list(Name), Name, atom_to_list(Name)]);
|
[Name, atom_to_list(Name), Name, atom_to_list(Name)]);
|
||||||
gen_format(#{opname := Name}) when (Name =:= 'CALL_GR') ->
|
gen_format(#{opname := Name}) when (Name =:= 'CALL_GR') ->
|
||||||
io_lib:format("format_op({~w, {immediate, Contract}, {immediate, Function}, Arity, Value, Gas}, Symbols) ->\n"
|
io_lib:format("format_op({~w, {immediate, Contract}, {immediate, Function}, ArgType, RetType, Value, Gas}, Symbols) ->\n"
|
||||||
" [\"~s \", lookup(Contract, Symbols), \".\", "
|
" [\"~s \", lookup(Contract, Symbols), \".\", "
|
||||||
"lookup(Function, Symbols), \" \", "
|
"lookup(Function, Symbols), \" \", "
|
||||||
"format_arg(a, Arity), \" \", "
|
"format_arg(a, ArgType), \" \", "
|
||||||
|
"format_arg(a, RetType), \" \", "
|
||||||
"format_arg(a, Value), \" \", "
|
"format_arg(a, Value), \" \", "
|
||||||
"format_arg(a, Gas)];\n"
|
"format_arg(a, Gas)];\n"
|
||||||
"format_op({~w, Contract, {immediate, Function}, Arity, Value, Gas}, Symbols) ->\n"
|
"format_op({~w, Contract, {immediate, Function}, ArgType, RetType, Value, Gas}, Symbols) ->\n"
|
||||||
"[\"~s \", format_arg(a, Contract), \".\", "
|
"[\"~s \", format_arg(a, Contract), \".\", "
|
||||||
"lookup(Function, Symbols), \" \", "
|
"lookup(Function, Symbols), \" \", "
|
||||||
"format_arg(a, Arity), \" \", "
|
"format_arg(a, ArgType), \" \", "
|
||||||
|
"format_arg(a, RetType), \" \", "
|
||||||
"format_arg(a, Value), \" \", "
|
"format_arg(a, Value), \" \", "
|
||||||
"format_arg(a, Gas)];\n",
|
"format_arg(a, Gas)];\n",
|
||||||
[Name, atom_to_list(Name), Name, atom_to_list(Name)]);
|
[Name, atom_to_list(Name), Name, atom_to_list(Name)]);
|
||||||
@@ -756,4 +801,3 @@ format_arg_doc({is,_N}) -> "Identifier";
|
|||||||
format_arg_doc({ii,_N}) -> "Integer";
|
format_arg_doc({ii,_N}) -> "Integer";
|
||||||
format_arg_doc({li,_N}) -> "[Integers]";
|
format_arg_doc({li,_N}) -> "[Integers]";
|
||||||
format_arg_doc({t,_N}) -> "Type".
|
format_arg_doc({t,_N}) -> "Type".
|
||||||
|
|
||||||
|
|||||||
+16
-8
@@ -25,20 +25,26 @@
|
|||||||
%% Size in bytes of serialization of a map for which we turn it into a store
|
%% 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.
|
%% map. It's not worth turning small maps into store maps.
|
||||||
%% Under consensus!
|
%% Under consensus!
|
||||||
-define(STORE_MAP_THRESHOLD, 500).
|
-ifdef(TEST).
|
||||||
|
-define(STORE_MAP_THRESHOLD, 0).
|
||||||
|
-else.
|
||||||
|
-define(STORE_MAP_THRESHOLD, 100).
|
||||||
|
-endif.
|
||||||
|
|
||||||
-type fate_value() :: aeb_fate_data:fate_type().
|
-type fate_value() :: aeb_fate_data:fate_type().
|
||||||
|
-type fate_value_or_tombstone() :: fate_value() | ?FATE_MAP_TOMBSTONE.
|
||||||
-type id() :: integer().
|
-type id() :: integer().
|
||||||
-type used_ids() :: list(id()).
|
-type used_ids() :: list(id()).
|
||||||
-type maps() :: #{ id() => aeb_fate_data:fate_map() | aeb_fate_data:fate_store_map() }.
|
-type maps() :: #{ id() => aeb_fate_data:fate_map() | aeb_fate_data:fate_store_map() }.
|
||||||
|
|
||||||
%% -- Allocating store maps --------------------------------------------------
|
%% -- Allocating store maps --------------------------------------------------
|
||||||
|
|
||||||
-spec allocate_store_maps(used_ids(), [fate_value()]) -> {[fate_value()], maps()}.
|
-spec allocate_store_maps(used_ids(), [fate_value_or_tombstone()]) -> {[fate_value_or_tombstone()], maps()}.
|
||||||
allocate_store_maps(Used, Vals) ->
|
allocate_store_maps(Used, Vals) ->
|
||||||
{_Used, Vals1, Maps} = allocate_store_maps_l(Used, Vals, #{}),
|
{_Used, Vals1, Maps} = allocate_store_maps_l(Used, Vals, #{}),
|
||||||
{Vals1, Maps}.
|
{Vals1, Maps}.
|
||||||
|
|
||||||
|
allocate_store_maps(Used, ?FATE_MAP_TOMBSTONE = Val, Maps) -> {Used, Val, Maps};
|
||||||
allocate_store_maps(Used, ?FATE_TRUE = Val, Maps) -> {Used, Val, Maps};
|
allocate_store_maps(Used, ?FATE_TRUE = Val, Maps) -> {Used, Val, Maps};
|
||||||
allocate_store_maps(Used, ?FATE_FALSE = Val, Maps) -> {Used, Val, Maps};
|
allocate_store_maps(Used, ?FATE_FALSE = Val, Maps) -> {Used, Val, Maps};
|
||||||
allocate_store_maps(Used, ?FATE_UNIT = Val, Maps) -> {Used, Val, Maps};
|
allocate_store_maps(Used, ?FATE_UNIT = Val, Maps) -> {Used, Val, Maps};
|
||||||
@@ -74,8 +80,8 @@ allocate_store_maps(Used, ?FATE_STORE_MAP(Cache, _Id) = Val, Maps) when Cache =:
|
|||||||
{Used, Val, Maps};
|
{Used, Val, Maps};
|
||||||
allocate_store_maps(Used, ?FATE_STORE_MAP(Cache, Id), Maps) ->
|
allocate_store_maps(Used, ?FATE_STORE_MAP(Cache, Id), Maps) ->
|
||||||
{NewId, Used1} = next_id(Used),
|
{NewId, Used1} = next_id(Used),
|
||||||
{Used1, Cache1, Maps1} = allocate_store_maps_m(Used1, Cache, Maps),
|
{Used2, Cache1, Maps1} = allocate_store_maps_m(Used1, Cache, Maps),
|
||||||
{Used1, ?FATE_STORE_MAP(#{}, NewId), Maps1#{NewId => ?FATE_STORE_MAP(Cache1, Id)}}.
|
{Used2, ?FATE_STORE_MAP(#{}, NewId), Maps1#{NewId => ?FATE_STORE_MAP(Cache1, Id)}}.
|
||||||
|
|
||||||
allocate_store_maps_l(Used, [], Maps) -> {Used, [], Maps};
|
allocate_store_maps_l(Used, [], Maps) -> {Used, [], Maps};
|
||||||
allocate_store_maps_l(Used, [H | T], Maps) ->
|
allocate_store_maps_l(Used, [H | T], Maps) ->
|
||||||
@@ -93,7 +99,8 @@ allocate_store_maps_m(Used, Val, Maps) ->
|
|||||||
|
|
||||||
-type unfold_fun() :: fun((id()) -> aeb_fate_data:fate_map()).
|
-type unfold_fun() :: fun((id()) -> aeb_fate_data:fate_map()).
|
||||||
|
|
||||||
-spec unfold_store_maps(unfold_fun(), fate_value()) -> fate_value().
|
-spec unfold_store_maps(unfold_fun(), fate_value_or_tombstone()) -> fate_value_or_tombstone().
|
||||||
|
unfold_store_maps(_Unfold, ?FATE_MAP_TOMBSTONE = Val) -> Val;
|
||||||
unfold_store_maps(_Unfold, ?FATE_TRUE = Val) -> Val;
|
unfold_store_maps(_Unfold, ?FATE_TRUE = Val) -> Val;
|
||||||
unfold_store_maps(_Unfold, ?FATE_FALSE = Val) -> Val;
|
unfold_store_maps(_Unfold, ?FATE_FALSE = Val) -> Val;
|
||||||
unfold_store_maps(_Unfold, ?FATE_UNIT = Val) -> Val;
|
unfold_store_maps(_Unfold, ?FATE_UNIT = Val) -> Val;
|
||||||
@@ -119,7 +126,8 @@ unfold_store_maps(Unfold, Val) when ?IS_FATE_MAP(Val) ->
|
|||||||
?MAKE_FATE_MAP(unfold_store_maps_m(Unfold, ?FATE_MAP_VALUE(Val)));
|
?MAKE_FATE_MAP(unfold_store_maps_m(Unfold, ?FATE_MAP_VALUE(Val)));
|
||||||
unfold_store_maps(Unfold, ?FATE_STORE_MAP(Cache, Id)) ->
|
unfold_store_maps(Unfold, ?FATE_STORE_MAP(Cache, Id)) ->
|
||||||
StoreMap = Unfold(Id),
|
StoreMap = Unfold(Id),
|
||||||
maps:fold(fun write_cache/3, unfold_store_maps(Unfold, StoreMap), Cache).
|
maps:fold(fun write_cache/3, unfold_store_maps(Unfold, StoreMap),
|
||||||
|
unfold_store_maps_m(Unfold, Cache)).
|
||||||
|
|
||||||
unfold_store_maps_l(Unfold, Vals) ->
|
unfold_store_maps_l(Unfold, Vals) ->
|
||||||
[ unfold_store_maps(Unfold, Val) || Val <- Vals ].
|
[ unfold_store_maps(Unfold, Val) || Val <- Vals ].
|
||||||
@@ -134,7 +142,7 @@ write_cache(Key, Val, Map) ->
|
|||||||
|
|
||||||
%% -- Reference counting -----------------------------------------------------
|
%% -- Reference counting -----------------------------------------------------
|
||||||
|
|
||||||
-type refcount() :: #{id() => pos_integer()}.
|
-type refcount() :: #{id() => integer()}.
|
||||||
|
|
||||||
-spec refcount_zero() -> refcount().
|
-spec refcount_zero() -> refcount().
|
||||||
refcount_zero() -> #{}.
|
refcount_zero() -> #{}.
|
||||||
@@ -159,7 +167,7 @@ has_store_maps(Val) ->
|
|||||||
-spec refcount(fate_value()) -> refcount().
|
-spec refcount(fate_value()) -> refcount().
|
||||||
refcount(Val) -> refcount(Val, #{}).
|
refcount(Val) -> refcount(Val, #{}).
|
||||||
|
|
||||||
-spec refcount(fate_value(), refcount()) -> refcount().
|
-spec refcount(fate_value_or_tombstone(), refcount()) -> refcount().
|
||||||
refcount(?FATE_MAP_TOMBSTONE, Count) -> Count;
|
refcount(?FATE_MAP_TOMBSTONE, Count) -> Count;
|
||||||
refcount(?FATE_TRUE, Count) -> Count;
|
refcount(?FATE_TRUE, Count) -> Count;
|
||||||
refcount(?FATE_FALSE, Count) -> Count;
|
refcount(?FATE_FALSE, Count) -> Count;
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
, heap_value_maps/1
|
, heap_value_maps/1
|
||||||
, heap_value_offset/1
|
, heap_value_offset/1
|
||||||
, heap_value_heap/1
|
, heap_value_heap/1
|
||||||
|
, heap_value_byte_size/1
|
||||||
, heap_fragment_maps/1
|
, heap_fragment_maps/1
|
||||||
, heap_fragment_offset/1
|
, heap_fragment_offset/1
|
||||||
, heap_fragment_heap/1
|
, heap_fragment_heap/1
|
||||||
@@ -90,6 +91,25 @@ heap_value_offset({_, Heap}) -> Heap#heap.offset.
|
|||||||
binary() | #{non_neg_integer() => non_neg_integer()}.
|
binary() | #{non_neg_integer() => non_neg_integer()}.
|
||||||
heap_value_heap({_, Heap}) -> Heap#heap.heap.
|
heap_value_heap({_, Heap}) -> Heap#heap.heap.
|
||||||
|
|
||||||
|
%% -- Byte size of a heap value ----------------------------------------------
|
||||||
|
|
||||||
|
-spec heap_value_byte_size(heap_value()) -> non_neg_integer().
|
||||||
|
heap_value_byte_size({_, Heap}) ->
|
||||||
|
Value = Heap#heap.heap,
|
||||||
|
Maps = Heap#heap.maps,
|
||||||
|
ValueSize =
|
||||||
|
if is_binary(Value) -> byte_size(Value);
|
||||||
|
true -> 0 end,
|
||||||
|
MapsSize =
|
||||||
|
lists:sum([ pmap_size(Map) || Map <- maps:values(Maps#maps.maps) ]),
|
||||||
|
ValueSize + MapsSize.
|
||||||
|
|
||||||
|
pmap_size(#pmap{data = stored}) -> 0;
|
||||||
|
pmap_size(#pmap{data = Data}) when is_map(Data) ->
|
||||||
|
lists:sum([ byte_size(Key) + byte_size(Val)
|
||||||
|
|| {Key, Val} <- maps:to_list(Data),
|
||||||
|
Val /= tombstone ]).
|
||||||
|
|
||||||
%% -- Value to binary --------------------------------------------------------
|
%% -- Value to binary --------------------------------------------------------
|
||||||
|
|
||||||
-spec to_binary(aeb_aevm_data:data()) -> aeb_aevm_data:heap().
|
-spec to_binary(aeb_aevm_data:data()) -> aeb_aevm_data:heap().
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
;; CONTRACT all_instructions
|
;; CONTRACT all_instructions
|
||||||
|
|
||||||
;; Dont expect this contract to typecheck or run.
|
;; Dont expect this contract to typecheck or run.
|
||||||
;; Just used to check assembler rountrip of all instructions.
|
;; Just used to check assembler roundtrip of all instructions.
|
||||||
|
|
||||||
FUNCTION foo () : {tuple, []}
|
FUNCTION foo () : {tuple, []}
|
||||||
RETURN
|
RETURN
|
||||||
@@ -224,7 +224,13 @@ FUNCTION foo () : {tuple, []}
|
|||||||
|
|
||||||
AENS_REVOKE
|
AENS_REVOKE
|
||||||
|
|
||||||
ECVERIFY
|
ECRECOVER_SECP256K1
|
||||||
|
|
||||||
|
VERIFY_SIG
|
||||||
|
|
||||||
|
VERIFY_SIG_SECP256K1
|
||||||
|
|
||||||
|
ECVERIFY_SECP256K1
|
||||||
|
|
||||||
SHA3 a
|
SHA3 a
|
||||||
|
|
||||||
@@ -247,3 +253,9 @@ FUNCTION foo () : {tuple, []}
|
|||||||
AUTH_TX_HASH
|
AUTH_TX_HASH
|
||||||
|
|
||||||
CONTRACT_TO_ADDRESS @ct_nv5B93FPzRHrGNmMdTDfGdd5xGZvep3MVSpJqzcQmMp59bBCv
|
CONTRACT_TO_ADDRESS @ct_nv5B93FPzRHrGNmMdTDfGdd5xGZvep3MVSpJqzcQmMp59bBCv
|
||||||
|
|
||||||
|
IS_ORACLE @ak_nv5B93FPzRHrGNmMdTDfGdd5xGZvep3MVSpJqzcQmMp59bBCv
|
||||||
|
|
||||||
|
IS_CONTRACT @ak_nv5B93FPzRHrGNmMdTDfGdd5xGZvep3MVSpJqzcQmMp59bBCv
|
||||||
|
|
||||||
|
IS_PAYABLE @ak_nv5B93FPzRHrGNmMdTDfGdd5xGZvep3MVSpJqzcQmMp59bBCv
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -28,11 +28,11 @@ FUNCTION tailcall(integer) -> integer
|
|||||||
INCA
|
INCA
|
||||||
CALL_T "inc"
|
CALL_T "inc"
|
||||||
|
|
||||||
FUNCTION remote_call(integer) : integer
|
;; FUNCTION remote_call(integer) : integer
|
||||||
PUSH arg0
|
;; PUSH arg0
|
||||||
CALL_R remote.add_five 1 0
|
;; CALL_R remote.add_five {tuple, [integer]} integer 0 ;; typereps don't parse
|
||||||
INCA
|
;; INCA
|
||||||
RETURN
|
;; RETURN
|
||||||
|
|
||||||
;; Test the code from the shell
|
;; Test the code from the shell
|
||||||
;; _build/default/rel/aessembler/bin/aessembler console
|
;; _build/default/rel/aessembler/bin/aessembler console
|
||||||
|
|||||||
Reference in New Issue
Block a user