Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b47b2fe23c | |||
| 5e38d6e829 | |||
| 009e036192 | |||
| 37808419a8 | |||
| f4c3782888 | |||
| 1688f85f2b | |||
| b38349274f | |||
| b8d593e351 | |||
| 0f7529b26a |
@@ -0,0 +1,27 @@
|
|||||||
|
%%% @author Thomas Arts
|
||||||
|
%%% @doc Allow to run QuickCheck tests as eunit tests
|
||||||
|
%%% `rebar3 as eqc eunit --cover`
|
||||||
|
%%% or `rebar3 as eqc eunit --module=aeb_fate_code`
|
||||||
|
%%% Note that for obtainign cover file, one needs `rebar3 as eqc cover
|
||||||
|
%%%
|
||||||
|
%%%
|
||||||
|
%%% @end
|
||||||
|
%%% Created : 13 Dec 2018 by Thomas Arts <thomas@SpaceGrey.lan>
|
||||||
|
|
||||||
|
-module(aeb_fate_code_tests).
|
||||||
|
|
||||||
|
-include_lib("eunit/include/eunit.hrl").
|
||||||
|
|
||||||
|
-compile([export_all, nowarn_export_all]).
|
||||||
|
|
||||||
|
-define(EQC_EUNIT(Module, PropName, Ms),
|
||||||
|
{ atom_to_list(PropName),
|
||||||
|
{timeout, (Ms * 10) div 1000, ?_assert(eqc:quickcheck(eqc:testing_time(Ms / 1000, Module:PropName())))}}).
|
||||||
|
|
||||||
|
quickcheck_test_() ->
|
||||||
|
{setup, fun() -> eqc:start() end,
|
||||||
|
[ ?EQC_EUNIT(aefate_code_eqc, prop_opcodes, 200),
|
||||||
|
?EQC_EUNIT(aefate_code_eqc, prop_serializes, 3000),
|
||||||
|
?EQC_EUNIT(aefate_code_eqc, prop_fail_serializes, 3000),
|
||||||
|
?EQC_EUNIT(aefate_code_eqc, prop_fuzz, 3000)
|
||||||
|
]}.
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
%%% @author Thomas Arts
|
||||||
|
%%% @doc Allow to run QuickCheck tests as eunit tests
|
||||||
|
%%% `rebar3 as eqc eunit --cover`
|
||||||
|
%%% or `rebar3 as eqc eunit --module=aeb_fate_data`
|
||||||
|
%%% Note that for obtainign cover file, one needs `rebar3 as eqc cover
|
||||||
|
%%%
|
||||||
|
%%%
|
||||||
|
%%% @end
|
||||||
|
%%% Created : 13 Dec 2018 by Thomas Arts <thomas@SpaceGrey.lan>
|
||||||
|
|
||||||
|
-module(aeb_fate_data_tests).
|
||||||
|
|
||||||
|
-include_lib("eunit/include/eunit.hrl").
|
||||||
|
|
||||||
|
-compile([export_all, nowarn_export_all]).
|
||||||
|
|
||||||
|
-define(EQC_EUNIT(Module, PropName, Ms),
|
||||||
|
{ atom_to_list(PropName),
|
||||||
|
{timeout, (Ms * 3) / 1000, ?_assert(eqc:quickcheck(eqc:testing_time(Ms / 1000, Module:PropName())))}}).
|
||||||
|
|
||||||
|
quickcheck_test_() ->
|
||||||
|
{setup, fun() -> eqc:start() end,
|
||||||
|
[ ?EQC_EUNIT(aefate_eqc, prop_roundtrip, 500),
|
||||||
|
?EQC_EUNIT(aefate_eqc, prop_format_scan, 2000),
|
||||||
|
?EQC_EUNIT(aefate_eqc, prop_order, 2000),
|
||||||
|
?EQC_EUNIT(aefate_eqc, prop_fuzz, 2000)
|
||||||
|
]}.
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
%%% @author Thomas Arts
|
||||||
|
%%% @doc Allow to run QuickCheck tests as eunit tests
|
||||||
|
%%% `rebar3 as eqc eunit --cover`
|
||||||
|
%%% or `rebar3 as eqc eunit --module=aeb_fate_encoding`
|
||||||
|
%%% Note that for obtaining cover file, one needs `rebar3 as eqc cover
|
||||||
|
%%%
|
||||||
|
%%%
|
||||||
|
%%% @end
|
||||||
|
%%% Created : 13 Dec 2018 by Thomas Arts
|
||||||
|
|
||||||
|
-module(aeb_fate_encoding_tests).
|
||||||
|
|
||||||
|
-include_lib("eunit/include/eunit.hrl").
|
||||||
|
|
||||||
|
-compile([export_all, nowarn_export_all]).
|
||||||
|
|
||||||
|
-define(EQC_EUNIT(Module, PropName, Ms),
|
||||||
|
{ atom_to_list(PropName),
|
||||||
|
{timeout, (Ms * 3) / 1000, ?_assert(eqc:quickcheck(eqc:testing_time(Ms / 1000, Module:PropName())))}}).
|
||||||
|
|
||||||
|
quickcheck_test_() ->
|
||||||
|
{setup, fun() -> eqc:start() end,
|
||||||
|
[ ?EQC_EUNIT(aefate_type_eqc, prop_roundtrip, 1000),
|
||||||
|
?EQC_EUNIT(aefate_eqc, prop_serializes, 1000),
|
||||||
|
?EQC_EUNIT(aefate_eqc, prop_no_maps_in_keys, 1000),
|
||||||
|
?EQC_EUNIT(aefate_eqc, prop_idempotent, 1000)
|
||||||
|
]}.
|
||||||
@@ -0,0 +1,167 @@
|
|||||||
|
%%% @author Thomas Arts
|
||||||
|
%%% @doc Use `rebar3 as eqc shell` to run properties in the shell
|
||||||
|
%%%
|
||||||
|
%%% We want to be sure that we can deserialize all FATE assembler that is accepted on chain.
|
||||||
|
%%%
|
||||||
|
%%% We test something slightly weaker here,
|
||||||
|
%%% viz. All FATE assembler we serialize, we can deserialize
|
||||||
|
%%%
|
||||||
|
%%% Negative testing modelled:
|
||||||
|
%%% Failure 1: function names differ from 4 bytes
|
||||||
|
%%% Failure 2: pointer to empty code block
|
||||||
|
%%% Failure 3: end_BB operation as not ending block or not at end of block
|
||||||
|
%%% - empty code blocks
|
||||||
|
%%% - blocks that are not of the form (not end_bb)* end_bb.
|
||||||
|
%%%
|
||||||
|
%%% @end
|
||||||
|
%%% Created : 13 Dec 2018 by Thomas Arts <thomas@SpaceGrey.lan>
|
||||||
|
|
||||||
|
-module(aefate_code_eqc).
|
||||||
|
|
||||||
|
-include_lib("eqc/include/eqc.hrl").
|
||||||
|
|
||||||
|
-compile([export_all, nowarn_export_all]).
|
||||||
|
%%-define(Failure(Failures, Number), case lists:member(Number, Failures) of true -> 1; false -> 0 end)
|
||||||
|
|
||||||
|
|
||||||
|
prop_serializes() ->
|
||||||
|
in_parallel(
|
||||||
|
?FORALL(FateCode, fate_code(0),
|
||||||
|
begin
|
||||||
|
{T0, Binary} = timer:tc(fun() -> aeb_fate_code:serialize(FateCode) end),
|
||||||
|
?WHENFAIL(eqc:format("serialized:\n ~120p~n", [Binary]),
|
||||||
|
begin
|
||||||
|
{T1, Decoded} = timer:tc(fun() -> aeb_fate_code:deserialize(Binary) end),
|
||||||
|
measure(binary_size, size(Binary),
|
||||||
|
measure(serialize, T0 / 1000,
|
||||||
|
measure(deserialize, T1 / 1000,
|
||||||
|
conjunction([{equal, equals(Decoded, FateCode)},
|
||||||
|
{serialize_time, T0 / 1000 < 500},
|
||||||
|
{deserialize_time, T1 / 1000 < 500}]))))
|
||||||
|
end)
|
||||||
|
end)).
|
||||||
|
|
||||||
|
prop_fail_serializes() ->
|
||||||
|
conjunction([{Failure, eqc:counterexample(
|
||||||
|
?FORALL(FateCode, fate_code(Failure),
|
||||||
|
?FORALL(Binary, catch aeb_fate_code:serialize(FateCode),
|
||||||
|
is_binary(Binary))))
|
||||||
|
=/= true} || Failure <- [1, 2, 3, 4, 5] ]).
|
||||||
|
|
||||||
|
prop_fuzz() ->
|
||||||
|
in_parallel(
|
||||||
|
?FORALL(Binary, ?LET(FateCode, fate_code(0), aeb_fate_code:serialize(FateCode)),
|
||||||
|
?FORALL(FuzzedBin, fuzz(Binary),
|
||||||
|
try aeb_fate_code:deserialize(FuzzedBin) of
|
||||||
|
Code ->
|
||||||
|
?WHENFAIL(eqc:format("Code:\n ~p\n", [Code]),
|
||||||
|
begin
|
||||||
|
Bin1 = aeb_fate_code:serialize(Code),
|
||||||
|
Code1 = aeb_fate_code:deserialize(Bin1),
|
||||||
|
?WHENFAIL(eqc:format("Reserialized\n ~120p\n", [Bin1]),
|
||||||
|
equals(Code, Code1))
|
||||||
|
end)
|
||||||
|
catch _:_ -> true
|
||||||
|
end))).
|
||||||
|
|
||||||
|
prop_opcodes() ->
|
||||||
|
?FORALL(Opcode, choose(0, 16#ff),
|
||||||
|
try M = aeb_fate_opcodes:mnemonic(Opcode),
|
||||||
|
?WHENFAIL(eqc:format("opcode ~p -> ~p", [Opcode, M]),
|
||||||
|
conjunction([{valid, lists:member(Opcode, valid_opcodes())},
|
||||||
|
{eq, equals(aeb_fate_opcodes:m_to_op(M), Opcode)}]))
|
||||||
|
catch
|
||||||
|
_:_ ->
|
||||||
|
not lists:member(Opcode, valid_opcodes())
|
||||||
|
end).
|
||||||
|
|
||||||
|
|
||||||
|
valid_opcodes() ->
|
||||||
|
[ Op || #{opcode := Op} <- aeb_fate_generate_ops:get_ops() ].
|
||||||
|
|
||||||
|
|
||||||
|
fate_code(Failure) ->
|
||||||
|
?SIZED(Size,
|
||||||
|
?LET({FMap, SMap, AMap},
|
||||||
|
{non_empty(map(if Failure == 1 -> binary(1);
|
||||||
|
true -> binary(4) end,
|
||||||
|
{sublist(lists:sort([private, payable])), %% deserialize sorts them
|
||||||
|
{list(aefate_type_eqc:fate_type(Size div 3)), aefate_type_eqc:fate_type(Size div 3)}, bbs_code(Failure)})),
|
||||||
|
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_symbols(
|
||||||
|
aeb_fate_code:update_functions(
|
||||||
|
aeb_fate_code:new(), FMap), SMap), AMap))).
|
||||||
|
|
||||||
|
short_list(Max, Gen) ->
|
||||||
|
?LET(N, choose(0, Max), eqc_gen:list(N, Gen)).
|
||||||
|
|
||||||
|
small_map(KeyGen, ValGen) ->
|
||||||
|
?LET(KeyVals, short_list(6, {KeyGen, ValGen}),
|
||||||
|
return(maps:from_list(KeyVals))).
|
||||||
|
|
||||||
|
bbs_code(Failure) ->
|
||||||
|
frequency([{if Failure == 2 -> 5; true -> 0 end, #{0 => []}},
|
||||||
|
{10, ?LET(BBs, short_list(6, bb_code(Failure)),
|
||||||
|
maps:from_list(
|
||||||
|
lists:zip(lists:seq(0, length(BBs)-1), BBs)))}]).
|
||||||
|
|
||||||
|
bb_code(Failure) ->
|
||||||
|
EndBB = [ Op || Op <- valid_opcodes(), aeb_fate_opcodes:end_bb(Op) ],
|
||||||
|
NonEndBB = valid_opcodes() -- EndBB,
|
||||||
|
frequency(
|
||||||
|
[{if Failure == 3 -> 5; true -> 0 end, ?LET(Ops, non_empty(short_list(6, elements(NonEndBB))), bblock(Failure, Ops))},
|
||||||
|
{if Failure == 4 -> 5; true -> 0 end, ?LET({Ops, Op}, {short_list(6, elements(valid_opcodes())), elements(EndBB)}, bblock(Failure, Ops ++ [Op]))},
|
||||||
|
{10, ?LET({Ops, Op}, {short_list(6, elements(NonEndBB)), elements(EndBB)},
|
||||||
|
bblock(Failure, Ops ++ [Op]))}]).
|
||||||
|
|
||||||
|
bblock(Failure, Ops) ->
|
||||||
|
[ begin
|
||||||
|
Mnemonic = aeb_fate_opcodes:mnemonic(Op),
|
||||||
|
Arity = aeb_fate_opcodes:args(Op),
|
||||||
|
case Arity of
|
||||||
|
0 -> Mnemonic;
|
||||||
|
_ -> list_to_tuple([Mnemonic |
|
||||||
|
[ frequency([{if Failure == 5 -> 5; true -> 0 end, {stack, nat()}},
|
||||||
|
{5, {stack, 0}},
|
||||||
|
{5, {arg, nat()}},
|
||||||
|
{5, {var, nat()}},
|
||||||
|
{5, {immediate, small_fate_data(4)}}]) ||
|
||||||
|
_ <- lists:seq(1, Arity) ]])
|
||||||
|
end
|
||||||
|
end || Op <- Ops ].
|
||||||
|
|
||||||
|
fuzz(Binary) ->
|
||||||
|
?LET({N, Inj}, {choose(0, byte_size(Binary) - 1), choose(0, 255)},
|
||||||
|
begin
|
||||||
|
M = N * 8,
|
||||||
|
<<X:M, _:8, Z/binary>> = Binary,
|
||||||
|
<<X:M, Inj:8, Z/binary>>
|
||||||
|
end).
|
||||||
|
|
||||||
|
prop_small() ->
|
||||||
|
?FORALL(Value, small_fate_data(4),
|
||||||
|
begin
|
||||||
|
Bin = aeb_fate_encoding:serialize(Value),
|
||||||
|
Size = byte_size(Bin),
|
||||||
|
measure(size, Size,
|
||||||
|
?WHENFAIL(eqc:format("Size: ~p\n", [Size]),
|
||||||
|
Size < 1000))
|
||||||
|
end).
|
||||||
|
|
||||||
|
prop_small_type() ->
|
||||||
|
?FORALL(Type, ?SIZED(Size, aefate_type_eqc:fate_type(Size div 3)),
|
||||||
|
begin
|
||||||
|
Bin = iolist_to_binary(aeb_fate_encoding:serialize_type(Type)),
|
||||||
|
Size = byte_size(Bin),
|
||||||
|
measure(size, Size,
|
||||||
|
?WHENFAIL(eqc:format("Size: ~p\n", [Size]),
|
||||||
|
Size < 1000))
|
||||||
|
end).
|
||||||
|
|
||||||
|
small_fate_data(N) ->
|
||||||
|
?SIZED(Size, resize(Size div N, aefate_eqc:fate_data())).
|
||||||
|
|
||||||
|
small_fate_data_key(N) ->
|
||||||
|
?SIZED(Size, ?LET(Data, aefate_eqc:fate_data(Size div N, []), eqc_symbolic:eval(Data))).
|
||||||
@@ -0,0 +1,211 @@
|
|||||||
|
%%% @author Thomas Arts
|
||||||
|
%%% @doc Use `rebar3 as eqc shell` to run properties in the shell
|
||||||
|
%%%
|
||||||
|
%%% We need to be able to generate data that serializes with ?LONG_LIST, ?LONG_TUPLE etc.
|
||||||
|
%%% In other words make some rather broad terms as well as some deep terms
|
||||||
|
%%%
|
||||||
|
%%% @end
|
||||||
|
%%% Created : 13 Dec 2018 by Thomas Arts <thomas@SpaceGrey.lan>
|
||||||
|
|
||||||
|
-module(aefate_eqc).
|
||||||
|
|
||||||
|
-include_lib("eqc/include/eqc.hrl").
|
||||||
|
-include("../include/aeb_fate_data.hrl").
|
||||||
|
|
||||||
|
-compile([export_all, nowarn_export_all]).
|
||||||
|
|
||||||
|
prop_roundtrip() ->
|
||||||
|
?FORALL(FateData, fate_data(),
|
||||||
|
measure(bytes, size(term_to_binary(FateData)),
|
||||||
|
begin
|
||||||
|
Serialized = aeb_fate_encoding:serialize(FateData),
|
||||||
|
?WHENFAIL(eqc:format("Serialized ~p to ~p~n", [FateData, Serialized]),
|
||||||
|
equals(aeb_fate_encoding:deserialize(Serialized), FateData))
|
||||||
|
end)).
|
||||||
|
|
||||||
|
prop_format_scan() ->
|
||||||
|
?FORALL(FateData, fate_data([variant, map]),
|
||||||
|
?WHENFAIL(eqc:format("Trying to format ~p failed~n", [FateData]),
|
||||||
|
begin
|
||||||
|
String = aeb_fate_data:format(FateData),
|
||||||
|
{ok, _Scanned, _} = aeb_fate_asm_scan:scan(unicode:characters_to_list(String)),
|
||||||
|
true
|
||||||
|
end)).
|
||||||
|
|
||||||
|
prop_serializes() ->
|
||||||
|
?FORALL({Data, Garbage}, {fate_data(), binary()},
|
||||||
|
?WHENFAIL(eqc:format("Trying to serialize/deserialize ~p failed~n", [Data]),
|
||||||
|
begin
|
||||||
|
Binary = <<(aeb_fate_encoding:serialize(Data))/binary, Garbage/binary>>,
|
||||||
|
{FateData, Rest} = aeb_fate_encoding:deserialize_one(Binary),
|
||||||
|
measure(binary_size, size(Binary),
|
||||||
|
conjunction([{equal, equals(Data, FateData)},
|
||||||
|
{rest, equals(Garbage, Rest)},
|
||||||
|
{size, size(Binary) < 500000}]))
|
||||||
|
end)).
|
||||||
|
|
||||||
|
prop_no_maps_in_keys() ->
|
||||||
|
?FORALL(FateData, fate_bad_map(), %% may contain a map in its keys
|
||||||
|
begin
|
||||||
|
HasMapInKeys = lists:any(fun(K) -> has_map(K) end, maps:keys(FateData)),
|
||||||
|
try aeb_fate_encoding:serialize(FateData),
|
||||||
|
?WHENFAIL(eqc:format("Should not serialize, contains a map in key\n", []),
|
||||||
|
not HasMapInKeys)
|
||||||
|
catch error:Reason ->
|
||||||
|
?WHENFAIL(eqc:format("(~p) Should serialize\n", [Reason]), HasMapInKeys)
|
||||||
|
end
|
||||||
|
end).
|
||||||
|
|
||||||
|
prop_fuzz() ->
|
||||||
|
in_parallel(
|
||||||
|
?FORALL(Binary, ?LET(FateData, ?SIZED(Size, resize(Size div 4, fate_data())), aeb_fate_encoding:serialize(FateData)),
|
||||||
|
?FORALL(InjectedBin, injection(Binary),
|
||||||
|
try Org = aeb_fate_encoding:deserialize(InjectedBin),
|
||||||
|
NewBin = aeb_fate_encoding:serialize(Org),
|
||||||
|
NewOrg = aeb_fate_encoding:deserialize(NewBin),
|
||||||
|
measure(success, 1,
|
||||||
|
?WHENFAIL(eqc:format("Deserialize ~p gives\n~p\nSerializes to ~p\n", [InjectedBin, Org, NewOrg]),
|
||||||
|
equals(NewBin, InjectedBin)))
|
||||||
|
catch _:_ ->
|
||||||
|
true
|
||||||
|
end))).
|
||||||
|
|
||||||
|
|
||||||
|
prop_order() ->
|
||||||
|
?FORALL(Items, vector(3, fate_data([variant, map])),
|
||||||
|
begin
|
||||||
|
%% Use lt to take minimum
|
||||||
|
Min = lt_min(Items),
|
||||||
|
Max = lt_max(Items),
|
||||||
|
conjunction([ {minimum, is_empty([ {Min, '>', I} || I<-Items, aeb_fate_data:lt(I, Min)])},
|
||||||
|
{maximum, is_empty([ {Max, '<', I} || I<-Items, aeb_fate_data:lt(Max, I)])},
|
||||||
|
{asym, aeb_fate_data:lt(Min, Max) orelse Min == Max}])
|
||||||
|
end).
|
||||||
|
|
||||||
|
lt_min([X, Y | Rest]) ->
|
||||||
|
case aeb_fate_data:lt(X, Y) of
|
||||||
|
true -> lt_min([X | Rest]);
|
||||||
|
false -> lt_min([Y| Rest])
|
||||||
|
end;
|
||||||
|
lt_min([X]) -> X.
|
||||||
|
|
||||||
|
lt_max([X, Y | Rest]) ->
|
||||||
|
case aeb_fate_data:lt(X, Y) of
|
||||||
|
true -> lt_max([Y | Rest]);
|
||||||
|
false -> lt_max([X| Rest])
|
||||||
|
end;
|
||||||
|
lt_max([X]) -> X.
|
||||||
|
|
||||||
|
prop_idempotent() ->
|
||||||
|
?FORALL(Items, list({fate_data_key(), fate_data()}),
|
||||||
|
equals(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([map, variant, store_map]).
|
||||||
|
|
||||||
|
%% keys may contain variants but no maps
|
||||||
|
fate_data_key() ->
|
||||||
|
fate_data([variant]).
|
||||||
|
|
||||||
|
fate_data(0, Options) ->
|
||||||
|
?LAZY(
|
||||||
|
frequency(
|
||||||
|
[{50, oneof([fate_integer(), fate_boolean(), fate_nil(), fate_unit()])},
|
||||||
|
{10, oneof([fate_string(), fate_address(), fate_bytes(), fate_contract(),
|
||||||
|
fate_oracle(), fate_oracle_q(), fate_bits(), fate_channel()])}] ++
|
||||||
|
[{1, fate_store_map()} || lists:member(store_map, Options)]));
|
||||||
|
fate_data(Size, Options) ->
|
||||||
|
?LAZY(
|
||||||
|
oneof([fate_data(0, Options),
|
||||||
|
fate_list(Size, Options),
|
||||||
|
fate_tuple(Size, Options)] ++
|
||||||
|
[fate_variant(Size, Options)
|
||||||
|
|| lists:member(variant, Options)] ++
|
||||||
|
[fate_map(Size, Options)
|
||||||
|
|| lists:member(map, Options)])).
|
||||||
|
|
||||||
|
|
||||||
|
fate_integer() -> ?LET(X, oneof([int(), largeint()]), return(aeb_fate_data:make_integer(X))).
|
||||||
|
fate_bits() -> ?LET(X, oneof([int(), largeint()]), return(aeb_fate_data:make_bits(X))).
|
||||||
|
fate_boolean() -> ?LET(X, elements([true, false]), return(aeb_fate_data:make_boolean(X))).
|
||||||
|
fate_nil() -> aeb_fate_data:make_list([]).
|
||||||
|
fate_unit() -> aeb_fate_data:make_unit().
|
||||||
|
fate_string() -> ?LET(X, frequency([{10, non_quote_string()}, {2, list(non_quote_string())},
|
||||||
|
{1, ?LET(N, choose(64-3, 64+3), vector(N, $a))}]),
|
||||||
|
return(aeb_fate_data:make_string(X))).
|
||||||
|
fate_address() -> ?LET(X, binary(256 div 8), return(aeb_fate_data:make_address(X))).
|
||||||
|
fate_bytes() -> ?LET(X, non_empty(binary()), return(aeb_fate_data:make_bytes(X))).
|
||||||
|
fate_contract() -> ?LET(X, binary(256 div 8), return(aeb_fate_data:make_contract(X))).
|
||||||
|
fate_oracle() -> ?LET(X, binary(256 div 8), return(aeb_fate_data:make_oracle(X))).
|
||||||
|
fate_oracle_q() -> ?LET(X, binary(256 div 8), return(aeb_fate_data:make_oracle_query(X))).
|
||||||
|
fate_channel() -> ?LET(X, binary(256 div 8), return(aeb_fate_data:make_channel(X))).
|
||||||
|
|
||||||
|
fate_values(Size, N, Options) ->
|
||||||
|
eqc_gen:list(N, fate_data(Size div max(1, N), Options)).
|
||||||
|
|
||||||
|
%% May shrink to fate_unit
|
||||||
|
fate_tuple(Size, Options) ->
|
||||||
|
?LET(N, choose(0, 6),
|
||||||
|
?LETSHRINK(Elements, fate_values(Size, N, Options),
|
||||||
|
return(aeb_fate_data:make_tuple(list_to_tuple(Elements))))).
|
||||||
|
|
||||||
|
fate_variant(Size, Options) ->
|
||||||
|
?LET({L1, L2, {tuple, Args}}, {list(choose(0, 255)), list(choose(0,255)), fate_tuple(Size, Options)},
|
||||||
|
return(aeb_fate_data:make_variant(L1 ++ [tuple_size(Args)] ++ L2,
|
||||||
|
length(L1), Args))).
|
||||||
|
|
||||||
|
fate_list(Size, Options) ->
|
||||||
|
?LET(N, frequency([{20, choose(0, 6)}, {1, choose(64 - 3, 64 + 3)}]),
|
||||||
|
?LETSHRINK(Vs, fate_values(Size, N, Options),
|
||||||
|
return(aeb_fate_data:make_list(Vs)))).
|
||||||
|
|
||||||
|
fate_map(Size, Options) ->
|
||||||
|
?LET(N, choose(0, 6),
|
||||||
|
?LETSHRINK(Values, fate_values(Size, N, Options),
|
||||||
|
?LET(Keys, vector(length(Values), fate_data(Size div max(1, N * 2), Options -- [map, store_map])),
|
||||||
|
return(aeb_fate_data:make_map(maps:from_list(lists:zip(Keys, Values))))))).
|
||||||
|
|
||||||
|
fate_store_map() ->
|
||||||
|
%% only #{} is allowed as cache in serialization
|
||||||
|
?LET(X, oneof([int(), largeint()]),
|
||||||
|
return(aeb_fate_data:make_store_map(abs(X)))).
|
||||||
|
|
||||||
|
fate_bad_map() ->
|
||||||
|
?LET(N, choose(0, 6),
|
||||||
|
?LET(Values, vector(N, ?SIZED(Size, resize(Size div 8, fate_data()))),
|
||||||
|
?LET(Keys, vector(N, ?SIZED(Size, resize(Size div 4, fate_data()))),
|
||||||
|
return(aeb_fate_data:make_map(maps:from_list(lists:zip(Keys, Values))))))).
|
||||||
|
|
||||||
|
non_quote_string() ->
|
||||||
|
?SUCHTHAT(S, utf8(), [ quote || <<34>> <= S ] == []).
|
||||||
|
|
||||||
|
char() ->
|
||||||
|
choose(1, 255).
|
||||||
|
|
||||||
|
injection(Binary) ->
|
||||||
|
?LET({N, Inj}, {choose(0, byte_size(Binary) - 1), choose(0,255)},
|
||||||
|
begin
|
||||||
|
M = N * 8,
|
||||||
|
<<X:M, _:8, Z/binary>> = Binary,
|
||||||
|
<<X:M, Inj:8, Z/binary>>
|
||||||
|
end).
|
||||||
|
|
||||||
|
is_empty(L) ->
|
||||||
|
?WHENFAIL(eqc:format("~p\n", [L]), L == []).
|
||||||
|
|
||||||
|
has_map(L) when is_list(L) ->
|
||||||
|
lists:any(fun(V) -> has_map(V) end, L);
|
||||||
|
has_map(T) when is_tuple(T) ->
|
||||||
|
has_map(tuple_to_list(T));
|
||||||
|
has_map(M) when is_map(M) ->
|
||||||
|
true;
|
||||||
|
has_map(?FATE_STORE_MAP(_, _)) ->
|
||||||
|
true;
|
||||||
|
has_map(_) ->
|
||||||
|
false.
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
%%% @author Thomas Arts
|
||||||
|
%%% @doc Use `rebar3 as eqc shell` to run properties in the shell
|
||||||
|
%%% Properties for testing Fate type representations
|
||||||
|
%%%
|
||||||
|
%%% @end
|
||||||
|
%%% Created : 13 Dec 2018 by Thomas Arts <thomas@SpaceGrey.lan>
|
||||||
|
|
||||||
|
-module(aefate_type_eqc).
|
||||||
|
|
||||||
|
-include_lib("eqc/include/eqc.hrl").
|
||||||
|
|
||||||
|
-compile([export_all, nowarn_export_all]).
|
||||||
|
|
||||||
|
kind(X) when is_atom(X) -> X;
|
||||||
|
kind(T) when is_tuple(T) -> element(1, T).
|
||||||
|
|
||||||
|
prop_roundtrip() ->
|
||||||
|
?FORALL(FateType, fate_type(),
|
||||||
|
collect(kind(FateType),
|
||||||
|
begin
|
||||||
|
Serialized = aeb_fate_encoding:serialize_type(FateType),
|
||||||
|
BinSerialized = list_to_binary(Serialized),
|
||||||
|
?WHENFAIL(eqc:format("Serialized ~p to ~p (~p)~n", [FateType, Serialized, BinSerialized]),
|
||||||
|
begin
|
||||||
|
{Type, <<>>} = aeb_fate_encoding:deserialize_type(BinSerialized),
|
||||||
|
equals(Type, FateType)
|
||||||
|
end)
|
||||||
|
end)).
|
||||||
|
|
||||||
|
|
||||||
|
fate_type() ->
|
||||||
|
?SIZED(Size, fate_type(Size)).
|
||||||
|
|
||||||
|
fate_type(0) ->
|
||||||
|
oneof([integer,
|
||||||
|
boolean,
|
||||||
|
address,
|
||||||
|
{bytes, nat()},
|
||||||
|
contract,
|
||||||
|
oracle,
|
||||||
|
channel,
|
||||||
|
bits,
|
||||||
|
string]);
|
||||||
|
fate_type(Size) ->
|
||||||
|
?LAZY(
|
||||||
|
oneof([fate_type(0),
|
||||||
|
{list, fate_type(Size div 2)},
|
||||||
|
?LETSHRINK(Ts, fate_types(Size), {tuple, Ts}),
|
||||||
|
?LETSHRINK(Ts, fate_types(Size), {variant, Ts}),
|
||||||
|
?LETSHRINK([T1, T2], vector(2, fate_type(Size div 2)),
|
||||||
|
{map, T1, T2})])).
|
||||||
|
|
||||||
|
fate_types(Size) ->
|
||||||
|
?LET(N, choose(0, 6),
|
||||||
|
eqc_gen:list(N, fate_type(Size div max(2, N)))).
|
||||||
|
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
%% -*- mode: erlang; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
|
{minimum_otp_vsn, "20.1"}.
|
||||||
|
|
||||||
|
{erl_opts, [debug_info]}.
|
||||||
|
|
||||||
|
{deps, [ {eblake2, "1.0.0"}
|
||||||
|
, {aeserialization, {git, "https://github.com/aeternity/aeserialization.git",
|
||||||
|
{tag, "v1.0.0"}}}
|
||||||
|
, {getopt, "1.0.1"}
|
||||||
|
]}.
|
||||||
|
|
||||||
|
{escript_incl_apps, [aebytecode, eblake2, aeserialization, getopt]}.
|
||||||
|
{escript_main_app, aebytecode}.
|
||||||
|
{escript_name, aefateasm}.
|
||||||
|
{escript_emu_args, "%%!"}.
|
||||||
|
|
||||||
|
{pre_hooks,
|
||||||
|
[{"(linux|darwin|solaris|win32)", compile, "make sources"},
|
||||||
|
{"(freebsd)", compile, "gmake sources"}]}.
|
||||||
|
|
||||||
|
{provider_hooks, [{post, [{compile, escriptize}]}]}.
|
||||||
|
|
||||||
|
|
||||||
|
{dialyzer, [
|
||||||
|
{warnings, [unknown]},
|
||||||
|
{plt_apps, all_deps},
|
||||||
|
{base_plt_apps, [erts, kernel, stdlib, crypto, getopt]}
|
||||||
|
]}.
|
||||||
|
|
||||||
|
|
||||||
|
{relx, [{release, {aebytecode, "3.4.0"},
|
||||||
|
[aebytecode, eblake2, getopt]},
|
||||||
|
|
||||||
|
{dev_mode, true},
|
||||||
|
{include_erts, false},
|
||||||
|
|
||||||
|
{extended_start_script, true}]}.
|
||||||
|
|
||||||
|
{profiles, [{binary, [
|
||||||
|
{deps, [ {eblake2, "1.0.0"}
|
||||||
|
, {aeserialization, {git, "https://github.com/aeternity/aeserialization.git",
|
||||||
|
{tag, "v1.0.0"}}}
|
||||||
|
, {getopt, "1.0.1"}
|
||||||
|
]},
|
||||||
|
|
||||||
|
{post_hooks, [{"(linux|darwin|solaris|freebsd|netbsd|openbsd)",
|
||||||
|
escriptize,
|
||||||
|
"cp \"$REBAR_BUILD_DIR/bin/aefateasm\" ./aefateasm"},
|
||||||
|
{"win32",
|
||||||
|
escriptize,
|
||||||
|
"robocopy \"%REBAR_BUILD_DIR%/bin/\" ./ aefateasm* "
|
||||||
|
"/njs /njh /nfl /ndl & exit /b 0"} % silence things
|
||||||
|
]}
|
||||||
|
]},
|
||||||
|
{eqc, [{erl_opts, [{parse_transform, eqc_cover}, {d, 'EQC'}]},
|
||||||
|
{extra_src_dirs, ["quickcheck"]} %% May not be called eqc!
|
||||||
|
]}
|
||||||
|
]}.
|
||||||
+23
@@ -0,0 +1,23 @@
|
|||||||
|
{"1.2.0",
|
||||||
|
[{<<"aeserialization">>,
|
||||||
|
{git,"https://github.com/aeternity/aeserialization.git",
|
||||||
|
{ref,"177bf604b2a05e940f92cf00e96e6e269e708245"}},
|
||||||
|
0},
|
||||||
|
{<<"base58">>,
|
||||||
|
{git,"https://github.com/aeternity/erl-base58.git",
|
||||||
|
{ref,"60a335668a60328a29f9731b67c4a0e9e3d50ab6"}},
|
||||||
|
1},
|
||||||
|
{<<"eblake2">>,{pkg,<<"eblake2">>,<<"1.0.0">>},0},
|
||||||
|
{<<"enacl">>,
|
||||||
|
{git,"https://github.com/aeternity/enacl.git",
|
||||||
|
{ref,"793ddb502f7fe081302e1c42227dca70b09f8e17"}},
|
||||||
|
1},
|
||||||
|
{<<"getopt">>,{pkg,<<"getopt">>,<<"1.0.1">>},0}]}.
|
||||||
|
[
|
||||||
|
{pkg_hash,[
|
||||||
|
{<<"eblake2">>, <<"EC8AD20E438AAB3F2E8D5D118C366A0754219195F8A0F536587440F8F9BCF2EF">>},
|
||||||
|
{<<"getopt">>, <<"C73A9FA687B217F2FF79F68A3B637711BB1936E712B521D8CE466B29CBF7808A">>}]},
|
||||||
|
{pkg_hash_ext,[
|
||||||
|
{<<"eblake2">>, <<"3C4D300A91845B25D501929A26AC2E6F7157480846FAB2347A4C11AE52E08A99">>},
|
||||||
|
{<<"getopt">>, <<"53E1AB83B9CEB65C9672D3E7A35B8092E9BDC9B3EE80721471A161C10C59959C">>}]}
|
||||||
|
].
|
||||||
@@ -8,7 +8,6 @@
|
|||||||
%%%
|
%%%
|
||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
-module(aeb_aevm_abi).
|
-module(aeb_aevm_abi).
|
||||||
-vsn("3.2.1").
|
|
||||||
-define(HASH_SIZE, 32).
|
-define(HASH_SIZE, 32).
|
||||||
|
|
||||||
-export([ create_calldata/4
|
-export([ create_calldata/4
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
-module(aeb_aevm_data).
|
-module(aeb_aevm_data).
|
||||||
-vsn("3.2.1").
|
|
||||||
|
|
||||||
-export_type([data/0,
|
-export_type([data/0,
|
||||||
type/0,
|
type/0,
|
||||||
|
|||||||
+1
-2
@@ -29,14 +29,13 @@
|
|||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
|
|
||||||
-module(aeb_asm).
|
-module(aeb_asm).
|
||||||
-vsn("3.2.1").
|
|
||||||
|
|
||||||
-export([ file/2
|
-export([ file/2
|
||||||
, pp/1
|
, pp/1
|
||||||
, to_hexstring/1
|
, to_hexstring/1
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-include("aeb_opcodes.hrl").
|
-include_lib("aebytecode/include/aeb_opcodes.hrl").
|
||||||
|
|
||||||
|
|
||||||
pp(Asm) ->
|
pp(Asm) ->
|
||||||
|
|||||||
@@ -7,14 +7,13 @@
|
|||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
|
|
||||||
-module(aeb_disassemble).
|
-module(aeb_disassemble).
|
||||||
-vsn("3.2.1").
|
|
||||||
|
|
||||||
-export([ pp/1,
|
-export([ pp/1,
|
||||||
format/2,
|
format/2,
|
||||||
format_address/1
|
format_address/1
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-include("aeb_opcodes.hrl").
|
-include_lib("aebytecode/include/aeb_opcodes.hrl").
|
||||||
|
|
||||||
|
|
||||||
pp(Binary) ->
|
pp(Binary) ->
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
%%%
|
%%%
|
||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
-module(aeb_fate_abi).
|
-module(aeb_fate_abi).
|
||||||
-vsn("3.2.1").
|
|
||||||
|
|
||||||
-export([ create_calldata/2
|
-export([ create_calldata/2
|
||||||
, decode_calldata/2
|
, decode_calldata/2
|
||||||
@@ -17,7 +16,7 @@
|
|||||||
, get_function_type_from_function_hash/2
|
, get_function_type_from_function_hash/2
|
||||||
, abi_version/0 ]).
|
, abi_version/0 ]).
|
||||||
|
|
||||||
-include("aeb_fate_data.hrl").
|
-include("../include/aeb_fate_data.hrl").
|
||||||
|
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
%%% API
|
%%% API
|
||||||
|
|||||||
@@ -84,7 +84,6 @@
|
|||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
|
|
||||||
-module(aeb_fate_asm).
|
-module(aeb_fate_asm).
|
||||||
-vsn("3.2.1").
|
|
||||||
|
|
||||||
-export([ assemble_file/3
|
-export([ assemble_file/3
|
||||||
, asm_to_bytecode/2
|
, asm_to_bytecode/2
|
||||||
@@ -95,8 +94,8 @@
|
|||||||
, to_asm/1
|
, to_asm/1
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-include("aeb_fate_opcodes.hrl").
|
-include_lib("aebytecode/include/aeb_fate_opcodes.hrl").
|
||||||
-include("aeb_fate_data.hrl").
|
-include_lib("aebytecode/include/aeb_fate_data.hrl").
|
||||||
-define(HASH_BYTES, 32).
|
-define(HASH_BYTES, 32).
|
||||||
|
|
||||||
assemble_file(InFile, OutFile, Options) ->
|
assemble_file(InFile, OutFile, Options) ->
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
%%%
|
%%%
|
||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
-module(aeb_fate_code).
|
-module(aeb_fate_code).
|
||||||
-vsn("3.2.1").
|
|
||||||
|
|
||||||
-export([ annotations/1
|
-export([ annotations/1
|
||||||
, deserialize/1
|
, deserialize/1
|
||||||
@@ -25,8 +24,8 @@
|
|||||||
, symbols/1
|
, symbols/1
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-include("aeb_fate_opcodes.hrl").
|
-include("../include/aeb_fate_opcodes.hrl").
|
||||||
-include("aeb_fate_data.hrl").
|
-include("../include/aeb_fate_data.hrl").
|
||||||
|
|
||||||
-export([ update_annotations/2
|
-export([ update_annotations/2
|
||||||
, update_functions/2
|
, update_functions/2
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
-include("aeb_fate_data.hrl").
|
-include("aeb_fate_data.hrl").
|
||||||
|
|
||||||
-module(aeb_fate_data).
|
-module(aeb_fate_data).
|
||||||
-vsn("3.2.1").
|
|
||||||
|
|
||||||
-type fate_integer() :: ?FATE_INTEGER_T.
|
-type fate_integer() :: ?FATE_INTEGER_T.
|
||||||
-type fate_boolean() :: ?FATE_BOOLEAN_T.
|
-type fate_boolean() :: ?FATE_BOOLEAN_T.
|
||||||
|
|||||||
@@ -40,7 +40,6 @@
|
|||||||
%%
|
%%
|
||||||
%% ------------------------------------------------------------------------
|
%% ------------------------------------------------------------------------
|
||||||
-module(aeb_fate_encoding).
|
-module(aeb_fate_encoding).
|
||||||
-vsn("3.2.1").
|
|
||||||
|
|
||||||
-export([ deserialize/1
|
-export([ deserialize/1
|
||||||
, deserialize_one/1
|
, deserialize_one/1
|
||||||
@@ -239,6 +238,8 @@ serialize_type({tuple, Ts}) ->
|
|||||||
N when N =< 255 ->
|
N when N =< 255 ->
|
||||||
[?TYPE_TUPLE, N | [serialize_type(T) || T <- Ts]]
|
[?TYPE_TUPLE, N | [serialize_type(T) || T <- Ts]]
|
||||||
end;
|
end;
|
||||||
|
serialize_type({bytes, any}) ->
|
||||||
|
[?TYPE_BYTES | binary_to_list(serialize_integer(-1))];
|
||||||
serialize_type({bytes, N}) when 0 =< N ->
|
serialize_type({bytes, N}) when 0 =< N ->
|
||||||
[?TYPE_BYTES | binary_to_list(serialize_integer(N))];
|
[?TYPE_BYTES | binary_to_list(serialize_integer(N))];
|
||||||
serialize_type(address) -> [?TYPE_OBJECT, ?OTYPE_ADDRESS];
|
serialize_type(address) -> [?TYPE_OBJECT, ?OTYPE_ADDRESS];
|
||||||
@@ -271,8 +272,12 @@ deserialize_type(<<?TYPE_TUPLE, N, Rest/binary>>) ->
|
|||||||
{{tuple, Ts}, Rest2};
|
{{tuple, Ts}, Rest2};
|
||||||
deserialize_type(<<?TYPE_BYTES, Rest/binary>>) ->
|
deserialize_type(<<?TYPE_BYTES, Rest/binary>>) ->
|
||||||
{N, Rest2} = deserialize_one(Rest),
|
{N, Rest2} = deserialize_one(Rest),
|
||||||
true = is_integer(N) andalso N >= 0,
|
true = is_integer(N),
|
||||||
{{bytes, N}, Rest2};
|
if N == -1 ->
|
||||||
|
{{bytes, any}, Rest2};
|
||||||
|
0 =< N ->
|
||||||
|
{{bytes, N}, Rest2}
|
||||||
|
end;
|
||||||
deserialize_type(<<?TYPE_OBJECT, ObjectType, Rest/binary>>) ->
|
deserialize_type(<<?TYPE_OBJECT, ObjectType, Rest/binary>>) ->
|
||||||
case ObjectType of
|
case ObjectType of
|
||||||
?OTYPE_ADDRESS -> {address, Rest};
|
?OTYPE_ADDRESS -> {address, Rest};
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
-module(aeb_fate_generate_docs).
|
-module(aeb_fate_generate_docs).
|
||||||
-vsn("3.2.1").
|
|
||||||
|
|
||||||
-export([generate_documentation/2, generate_documentation/3]).
|
-export([generate_documentation/2, generate_documentation/3]).
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
-module(aeb_fate_generate_ops).
|
-module(aeb_fate_generate_ops).
|
||||||
-vsn("3.2.1").
|
|
||||||
|
|
||||||
-export([ gen_and_halt/1
|
-export([ gen_and_halt/1
|
||||||
, generate/0
|
, generate/0
|
||||||
@@ -33,6 +32,10 @@ check_numbering(N, [T|Rest]) ->
|
|||||||
OpCode = element(2, T),
|
OpCode = element(2, T),
|
||||||
case OpCode of
|
case OpCode of
|
||||||
N -> check_numbering(N+1, Rest);
|
N -> check_numbering(N+1, Rest);
|
||||||
|
16#6d -> check_numbering(16#6d+1, Rest); %% Oracles
|
||||||
|
16#7b -> check_numbering(16#7b+1, Rest); %% Oracles
|
||||||
|
16#9b -> check_numbering(16#9b+1, Rest); %% Oracles
|
||||||
|
16#f0 -> check_numbering(16#f0+1, Rest);
|
||||||
16#fa -> check_numbering(16#fa+1, Rest);
|
16#fa -> check_numbering(16#fa+1, Rest);
|
||||||
_ when OpCode < N -> {duplicate_opcode, OpCode};
|
_ when OpCode < N -> {duplicate_opcode, OpCode};
|
||||||
_ when OpCode > N -> {missing_opcode, N}
|
_ when OpCode > N -> {missing_opcode, N}
|
||||||
@@ -151,13 +154,8 @@ ops_defs() ->
|
|||||||
, { 'LOG4', 16#64, false, true, true, ?GAS(1400), [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, ?GAS(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#65, false, false, true, ?GAS_IRIS(100, 5000), [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, ?GAS_IRIS(100, 5000), [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#66, false, false, false, ?GAS_IRIS(100, 10000), [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."}
|
%% Intentional gap (was oracles)
|
||||||
, { 'ORACLE_QUERY', 16#67, false, false, false, ?GAS_IRIS(100, 10000), [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#68, false, false, false, ?GAS_IRIS(100, 10000), [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#69, false, false, false, ?GAS_IRIS(100, 10000), [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#6a, false, false, true, ?GAS_IRIS(100, 2000), [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#6b, false, false, true, ?GAS_IRIS(100, 2000), [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#6c, false, false, true, ?GAS_IRIS(100, 2000), [a,a], oracle_query_fee, {oracle}, integer, "Arg0 := query fee for oracle Arg1"}
|
|
||||||
, { 'AENS_RESOLVE', 16#6d, false, false, true, ?GAS_IRIS(100, 2000), [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, ?GAS_IRIS(100, 2000), [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#6e, false, false, false, ?GAS_IRIS(100, 10000), [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, ?GAS_IRIS(100, 10000), [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#6f, false, false, false, ?GAS_IRIS(100, 10000), [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_CLAIM', 16#6f, false, false, false, ?GAS_IRIS(100, 10000), [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."}
|
||||||
@@ -172,10 +170,8 @@ ops_defs() ->
|
|||||||
, { 'CONTRACT_TO_ADDRESS', 16#76, false, true, true, ?GAS(10), [a,a], contract_to_address, {contract}, address, "Arg0 := Arg1 - A no-op type conversion"}
|
, { 'CONTRACT_TO_ADDRESS', 16#76, false, true, true, ?GAS(10), [a,a], contract_to_address, {contract}, address, "Arg0 := Arg1 - A no-op type conversion"}
|
||||||
, { 'AUTH_TX_HASH', 16#77, false, true, true, ?GAS(10), [a], auth_tx_hash, {}, variant, "If in GA authentication context return Some(TxHash) otherwise None."}
|
, { 'AUTH_TX_HASH', 16#77, false, true, true, ?GAS(10), [a], auth_tx_hash, {}, variant, "If in GA authentication context return Some(TxHash) otherwise None."}
|
||||||
|
|
||||||
, { 'ORACLE_CHECK', 16#78, false, false, true, ?GAS(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"}
|
%% Intentional gap (was oracles)
|
||||||
, { 'ORACLE_CHECK_QUERY', 16#79, false, false, true, ?GAS(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)"}
|
|
||||||
|
|
||||||
, { 'IS_ORACLE', 16#7a, false, false, true, ?GAS(100), [a,a], is_oracle, {address}, bool, "Arg0 := is Arg1 an oracle"}
|
|
||||||
, { 'IS_CONTRACT', 16#7b, false, false, true, ?GAS(100), [a,a], is_contract, {address}, bool, "Arg0 := is Arg1 a contract"}
|
, { 'IS_CONTRACT', 16#7b, false, false, true, ?GAS(100), [a,a], is_contract, {address}, bool, "Arg0 := is Arg1 a contract"}
|
||||||
, { 'IS_PAYABLE', 16#7c, false, false, true, ?GAS(100), [a,a], is_payable, {address}, bool, "Arg0 := is Arg1 a payable address"}
|
, { 'IS_PAYABLE', 16#7c, false, false, true, ?GAS(100), [a,a], is_payable, {address}, bool, "Arg0 := is Arg1 a payable address"}
|
||||||
, { 'CREATOR', 16#7d, false, true, true, ?GAS(10), [a], contract_creator, {}, address, "Arg0 := contract creator"}
|
, { 'CREATOR', 16#7d, false, true, true, ?GAS(10), [a], contract_creator, {}, address, "Arg0 := contract creator"}
|
||||||
@@ -214,7 +210,9 @@ ops_defs() ->
|
|||||||
, { 'BLS12_381_FP_TO_INT', 16#98, false, true, true, ?GAS(30), [a,a], bls12_381_fp_to_int, {tuple}, tuple, "Arg0 := from_montgomery(Arg1) - Convert montgomery representation (48 bytes) to integer"}
|
, { 'BLS12_381_FP_TO_INT', 16#98, false, true, true, ?GAS(30), [a,a], bls12_381_fp_to_int, {tuple}, tuple, "Arg0 := from_montgomery(Arg1) - Convert montgomery representation (48 bytes) to integer"}
|
||||||
|
|
||||||
, { 'AENS_LOOKUP', 16#99, false, false, true, ?GAS(2000), [a,a], aens_lookup, {string}, variant, "Lookup the name of Arg0. Returns option(AENS.name)"}
|
, { 'AENS_LOOKUP', 16#99, false, false, true, ?GAS(2000), [a,a], aens_lookup, {string}, variant, "Lookup the name of Arg0. Returns option(AENS.name)"}
|
||||||
, { 'ORACLE_EXPIRY', 16#9a, false, false, true, ?GAS(2000), [a,a], oracle_expiry, {oracle}, int, "Arg0 := expiry block for oracle Arg1"}
|
|
||||||
|
%% Intentional gap (was oracles)
|
||||||
|
|
||||||
, { 'AUTH_TX', 16#9b, false, true, true, ?GAS(100 ), [a], auth_tx, {}, variant, "If in GA authentication context return Some(Tx) otherwise None."}
|
, { 'AUTH_TX', 16#9b, false, true, true, ?GAS(100 ), [a], auth_tx, {}, variant, "If in GA authentication context return Some(Tx) otherwise None."}
|
||||||
|
|
||||||
, { 'STR_TO_LIST', 16#9c, false, true, true, ?GAS(100), [a,a], str_to_list, {string}, list, "Arg0 := string converted to list of characters"}
|
, { 'STR_TO_LIST', 16#9c, false, true, true, ?GAS(100), [a,a], str_to_list, {string}, list, "Arg0 := string converted to list of characters"}
|
||||||
@@ -242,6 +240,17 @@ ops_defs() ->
|
|||||||
, { 'BNOT', 16#ae, false, true, true, ?GAS(10), [a, a], bin_not, {integer}, integer, "Arg0 := ~Arg1"}
|
, { 'BNOT', 16#ae, false, true, true, ?GAS(10), [a, a], bin_not, {integer}, integer, "Arg0 := ~Arg1"}
|
||||||
, { 'BSL', 16#af, false, true, true, ?GAS(10), [a, a, a], bin_sl, {integer, integer}, integer, "Arg0 := Arg1 << Arg2"}
|
, { 'BSL', 16#af, false, true, true, ?GAS(10), [a, a, a], bin_sl, {integer, integer}, integer, "Arg0 := Arg1 << Arg2"}
|
||||||
, { 'BSR', 16#b0, false, true, true, ?GAS(10), [a, a, a], bin_sr, {integer, integer}, integer, "Arg0 := Arg1 >> Arg2"}
|
, { 'BSR', 16#b0, false, true, true, ?GAS(10), [a, a, a], bin_sr, {integer, integer}, integer, "Arg0 := Arg1 >> Arg2"}
|
||||||
|
, { 'BYTES_SPLIT_ANY', 16#b1, false, true, true, ?GAS(10), [a, a, a], bytes_split_any, {bytes, integer}, variant, "Arg0 := bytes_split_any(Arg1, Arg2), where a positive Arg2 is the length of the first chunk, and a negative Arg2 is the length of the second chunk. Returns None if byte array is not long enough."}
|
||||||
|
, { 'BYTES_SIZE', 16#b2, false, true, true, ?GAS(10), [a, a], bytes_size, {bytes}, integer, "Arg0 := bytes_size(Arg1), returns the number of bytes in the byte array."}
|
||||||
|
, { 'BYTES_TO_FIXED_SIZE', 16#b3, false, true, true, ?GAS(10), [a, a, a], bytes_to_fixed_size, {bytes, integer}, variant, "Arg0 := bytes_to_fixed_size(Arg1, Arg2), returns Some(Arg1') if byte_size(Arg1) == Arg2, None otherwise. The type of Arg1' is bytes(Arg2) but the value is unchanged"}
|
||||||
|
, { 'INT_TO_BYTES', 16#b4, false, true, true, ?GAS(10), [a, a, a], int_to_bytes, {integer, integer}, bytes, "Arg0 := turn integer Arg1 into a byte array (big endian) length Arg2 (truncating if not fit)."}
|
||||||
|
, { 'STR_TO_BYTES', 16#b5, false, true, true, ?GAS(10), [a, a], str_to_bytes, {integer}, bytes, "Arg0 := turn string Arg1 into the corresponding byte array."}
|
||||||
|
, { 'NETWORK_ID', 16#b6, false, true, true, ?GAS(10), [a], network_id, {}, string, "Arg0 := The network_id of the chain."}
|
||||||
|
|
||||||
|
, { 'DBG_LOC', 16#f0, false, true, true, ?GAS(0), [a, a], dbg_loc, {string, integer}, none, "Debug Op: Execution location. Args = {file_name, line_num}" }
|
||||||
|
, { 'DBG_DEF', 16#f1, false, true, true, ?GAS(0), [a, a], dbg_def, {string, any}, none, "Debug Op: Define a variable. Args = {var_name, register}" }
|
||||||
|
, { 'DBG_UNDEF', 16#f2, false, true, true, ?GAS(0), [a, a], dbg_undef, {string, any}, none, "Debug Op: Undefine a variable. Args = {var_name, register}" }
|
||||||
|
, { 'DBG_CONTRACT', 16#f3, false, true, true, ?GAS(0), [a], dbg_contract, {string}, none, "Debug Op: Name the current contract. Args: {contract_name}"}
|
||||||
|
|
||||||
, { 'DEACTIVATE', 16#fa, false, true, true, ?GAS(10), [], deactivate, {}, none, "Mark the current contract for deactivation."}
|
, { 'DEACTIVATE', 16#fa, false, true, true, ?GAS(10), [], deactivate, {}, none, "Mark the current contract for deactivation."}
|
||||||
, { 'ABORT', 16#fb, true, true, true, ?GAS(10), [a], abort, {string}, none, "Abort execution (dont use all gas) with error message in Arg0."}
|
, { 'ABORT', 16#fb, true, true, true, ?GAS(10), [a], abort, {string}, none, "Abort execution (dont use all gas) with error message in Arg0."}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
%%% @end
|
%%% @end
|
||||||
%%% -------------------------------------------------------------------
|
%%% -------------------------------------------------------------------
|
||||||
-module(aeb_fate_maps).
|
-module(aeb_fate_maps).
|
||||||
-vsn("3.2.1").
|
|
||||||
|
|
||||||
-include("aeb_fate_data.hrl").
|
-include("aeb_fate_data.hrl").
|
||||||
|
|
||||||
|
|||||||
+2
-3
@@ -1,5 +1,4 @@
|
|||||||
-module(aeb_heap).
|
-module(aeb_heap).
|
||||||
-vsn("3.2.1").
|
|
||||||
|
|
||||||
-export([ to_binary/1
|
-export([ to_binary/1
|
||||||
, to_binary/2
|
, to_binary/2
|
||||||
@@ -23,8 +22,8 @@
|
|||||||
|
|
||||||
-export_type([binary_value/0, heap_value/0, offset/0, heap_fragment/0]).
|
-export_type([binary_value/0, heap_value/0, offset/0, heap_fragment/0]).
|
||||||
|
|
||||||
-include("aeb_typerep_def.hrl").
|
-include_lib("aebytecode/include/aeb_typerep_def.hrl").
|
||||||
-include("aeb_heap.hrl").
|
-include_lib("aebytecode/include/aeb_heap.hrl").
|
||||||
|
|
||||||
-type word() :: non_neg_integer().
|
-type word() :: non_neg_integer().
|
||||||
-type pointer() :: word().
|
-type pointer() :: word().
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
|
|
||||||
-module(aeb_memory).
|
-module(aeb_memory).
|
||||||
-vsn("3.2.1").
|
|
||||||
|
|
||||||
-export([binary_to_words/1]).
|
-export([binary_to_words/1]).
|
||||||
|
|
||||||
|
|||||||
+1
-2
@@ -7,7 +7,6 @@
|
|||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
|
|
||||||
-module(aeb_opcodes).
|
-module(aeb_opcodes).
|
||||||
-vsn("3.2.1").
|
|
||||||
|
|
||||||
-export([ dup/1
|
-export([ dup/1
|
||||||
, mnemonic/1
|
, mnemonic/1
|
||||||
@@ -18,7 +17,7 @@
|
|||||||
, swap/1
|
, swap/1
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-include("aeb_opcodes.hrl").
|
-include_lib("aebytecode/include/aeb_opcodes.hrl").
|
||||||
|
|
||||||
|
|
||||||
%%====================================================================
|
%%====================================================================
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
|
|
||||||
-module(aeb_primops).
|
-module(aeb_primops).
|
||||||
-vsn("3.2.1").
|
|
||||||
-export([ is_local_primop_op/1
|
-export([ is_local_primop_op/1
|
||||||
, op_needs_type_check/1
|
, op_needs_type_check/1
|
||||||
]).
|
]).
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{application, aebytecode,
|
{application, aebytecode,
|
||||||
[{description, "Bytecode definitions, serialization and deserialization for aeternity."},
|
[{description, "Bytecode definitions, serialization and deserialization for aeternity."},
|
||||||
{vsn, "3.2.0"},
|
{vsn, "3.4.0"},
|
||||||
{registered, []},
|
{registered, []},
|
||||||
{applications,
|
{applications,
|
||||||
[kernel,
|
[kernel,
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
-module(aefateasm).
|
-module(aefateasm).
|
||||||
-vsn("3.2.1").
|
|
||||||
|
|
||||||
-export([main/1]).
|
-export([main/1]).
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
{a_email,[]}.
|
|
||||||
{author,"Aeternity Authors"}.
|
|
||||||
{c_email,[]}.
|
|
||||||
{copyright,"Aeternity Authors"}.
|
|
||||||
{deps,[{"otpr","aeserialization",{0,1,0}},
|
|
||||||
{"otpr","eblake2",{1,0,0}},
|
|
||||||
{"otpr","getopt",{1,0,2}}]}.
|
|
||||||
{desc,"A library and stand alone assembler for aeternity bytecode. This version supports AEVM bytecode and FATE bytecode."}.
|
|
||||||
{file_exts,[]}.
|
|
||||||
{key_name,none}.
|
|
||||||
{license,skip}.
|
|
||||||
{modules,[]}.
|
|
||||||
{name,"AE Bytecode"}.
|
|
||||||
{package_id,{"otpr","aebytecode",{3,2,1}}}.
|
|
||||||
{prefix,none}.
|
|
||||||
{repo_url,"https://github.com/aeternity/aebytecode"}.
|
|
||||||
{tags,["aeternity","blockchain","fate","bytecode","crypto","ae"]}.
|
|
||||||
{type,lib}.
|
|
||||||
{ws_url,[]}.
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
#! /bin/bash
|
|
||||||
|
|
||||||
# This is a small pre-packaging source generation and include correction script that should be
|
|
||||||
# run before packaging this project for use with ZX/Zomp.
|
|
||||||
|
|
||||||
rm -rf _build
|
|
||||||
rm -f src/aeb_fate_opcodes.erl src/aeb_fate_ops.erl include/aeb_fate_opcodes.hrl src/aeb_fate_asm_scan.xrl src/aeb_fate_pp.erl
|
|
||||||
make sources
|
|
||||||
cd src
|
|
||||||
for f in $(ls --ignore=aeb_fate_generate_ops.erl | grep erl)
|
|
||||||
do
|
|
||||||
echo "Updating includes in: $f"
|
|
||||||
sed -i 's/aebytecode\/include\///g' "$f"
|
|
||||||
sed -i 's/\.\.\/include\///g' "$f"
|
|
||||||
sed -i 's/include_lib/include/g' "$f"
|
|
||||||
done
|
|
||||||
cd ..
|
|
||||||
rm -f ebin/*.beam
|
|
||||||
rm -f rebar*
|
|
||||||
rm -rf quickcheck
|
|
||||||
Reference in New Issue
Block a user