Merge pull request #86 from aeternity/PT-166602172-create-calldata-fate

Pt 166602172 create calldata fate
This commit is contained in:
Thomas Arts 2019-06-11 15:46:30 +02:00 committed by GitHub
commit 5628cf90b8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 68 additions and 18 deletions

View File

@ -2,7 +2,7 @@
{erl_opts, [debug_info]}.
{deps, [ {aebytecode, {git, "https://github.com/aeternity/aebytecode.git", {ref, "29b5ee3"}}}
{deps, [ {aebytecode, {git, "https://github.com/aeternity/aebytecode.git", {ref, "7dd9c29"}}}
, {getopt, "1.0.1"}
, {jsx, {git, "https://github.com/talentdeficit/jsx.git",
{tag, "2.8.0"}}}

View File

@ -1,7 +1,7 @@
{"1.1.0",
[{<<"aebytecode">>,
{git,"https://github.com/aeternity/aebytecode.git",
{ref,"29b5ee3e68086e0f0170d3c70e92bbfa210cbae6"}},
{ref,"7dd9c29cc075b52c8f966696e88c8a29fc296240"}},
0},
{<<"aeserialization">>,
{git,"https://github.com/aeternity/aeserialization.git",

View File

@ -465,7 +465,7 @@ ast_body({app, _, {typed, _, {proj, _, {typed, _, Addr, {con, _, Contract}}, {id
Gas = proplists:get_value("gas", ArgOpts ++ Defaults),
Value = proplists:get_value("value", ArgOpts ++ Defaults),
OutType = ast_typerep(OutT, Icode),
<<TypeHash:256>> = aeb_abi:function_type_hash(list_to_binary(FunName), ArgType, OutType),
<<TypeHash:256>> = aeb_aevm_abi:function_type_hash(list_to_binary(FunName), ArgType, OutType),
%% The function is represented by its type hash (which includes the name)
Fun = #integer{value = TypeHash},
#prim_call_contract{
@ -679,7 +679,7 @@ prim_call(Prim, Amount, Args, ArgTypes, OutType) ->
true ->
PrimBin = binary:encode_unsigned(Prim),
ArgType = {tuple, ArgTypes},
<<TH:256>> = aeb_abi:function_type_hash(PrimBin, ArgType, OutType),
<<TH:256>> = aeb_aevm_abi:function_type_hash(PrimBin, ArgType, OutType),
TH;
false ->
0

View File

@ -12,7 +12,8 @@
, file/2
, from_string/2
, check_call/4
, create_calldata/3
, create_calldata/3 %% deprecated
, create_calldata/4
, version/0
, sophia_type_to_typerep/1
, to_sophia_value/4
@ -32,6 +33,7 @@
| pp_icode
| pp_assembler
| pp_bytecode
| {backend, aevm | fate}
| {include, {file_system, [string()]} |
{explicit_files, #{string() => binary()}}}
| {src_file, string()}.
@ -137,6 +139,18 @@ string_to_icode(ContractString, Options) ->
type_env => TypeEnv,
icode => Icode }.
-spec string_to_fcode(string(), [option()]) -> map().
string_to_fcode(ContractString, Options) ->
Ast = parse(ContractString, Options),
pp_sophia_code(Ast, Options),
pp_ast(Ast, Options),
{TypeEnv, TypedAst} = aeso_ast_infer_types:infer(Ast, [return_env]),
pp_typed_ast(TypedAst, Options),
Fcode = aeso_ast_to_fcode:ast_to_fcode(TypedAst, Options),
#{ typed_ast => TypedAst,
type_env => TypeEnv,
fcode => Fcode }.
join_errors(Prefix, Errors, Pfun) ->
Ess = [ Pfun(E) || E <- Errors ],
list_to_binary(string:join([Prefix|Ess], "\n")).
@ -150,14 +164,15 @@ join_errors(Prefix, Errors, Pfun) ->
%% terms for the arguments.
%% NOTE: Special treatment for "init" since it might be implicit and has
%% a special return type (typerep, T)
-spec check_call(string(), string(), [string()], options()) -> {ok, string(), {[Type], Type}, [term()]} | {error, term()}
-spec check_call(string(), string(), [string()], options()) -> {ok, string(), {[Type], Type}, [term()]}
| {ok, string(), [term()]}
| {error, term()}
when Type :: term().
check_call(Source, "init" = FunName, Args, Options) ->
PatchFun = fun(T) -> {tuple, [typerep, T]} end,
case check_call(Source, FunName, Args, Options, PatchFun) of
case check_call1(Source, FunName, Args, Options) of
Err = {error, _} when Args == [] ->
%% Try with default init-function
case check_call(insert_init_function(Source, Options), FunName, Args, Options, PatchFun) of
case check_call1(insert_init_function(Source, Options), FunName, Args, Options) of
{error, _} -> Err; %% The first error is most likely better...
Res -> Res
end;
@ -165,11 +180,12 @@ check_call(Source, "init" = FunName, Args, Options) ->
Res
end;
check_call(Source, FunName, Args, Options) ->
PatchFun = fun(T) -> T end,
check_call(Source, FunName, Args, Options, PatchFun).
check_call1(Source, FunName, Args, Options).
check_call(ContractString0, FunName, Args, Options, PatchFun) ->
check_call1(ContractString0, FunName, Args, Options) ->
try
case proplists:get_value(backend, Options, aevm) of
aevm ->
%% First check the contract without the __call function
#{} = string_to_icode(ContractString0, Options),
ContractString = insert_call_function(ContractString0, FunName, Args, Options),
@ -185,7 +201,25 @@ check_call(ContractString0, FunName, Args, Options, PatchFun) ->
ArgIcode = get_arg_icode(Funs),
ArgTerms = [ icode_to_term(T, Arg) ||
{T, Arg} <- lists:zip(ArgVMTypes, ArgIcode) ],
{ok, FunName, {ArgVMTypes, PatchFun(RetVMType)}, ArgTerms}
RetVMType1 =
case FunName of
"init" -> {tuple, [typerep, RetVMType]};
_ -> RetVMType
end,
{ok, FunName, {ArgVMTypes, RetVMType1}, ArgTerms};
fate ->
%% First check the contract without the __call function
#{fcode := OrgFcode} = string_to_fcode(ContractString0, Options),
FateCode = aeso_fcode_to_fate:compile(OrgFcode, []),
_SymbolHashes = maps:keys(aeb_fate_code:symbols(FateCode)),
%% TODO collect all hashes and compute the first name without hash collision to
%% be used as __callX
%% case aeb_fate_code:symbol_identifier(<<"__call">>) of
ContractString = insert_call_function(ContractString0, FunName, Args, Options),
#{fcode := Fcode} = string_to_fcode(ContractString, Options),
#{args := CallArgs} = maps:get({entrypoint, <<"__call">>}, maps:get(functions, Fcode)),
{ok, FunName, CallArgs}
end
catch
error:{parse_errors, Errors} ->
{error, join_errors("Parse errors", Errors, fun (E) -> E end)};
@ -199,6 +233,7 @@ check_call(ContractString0, FunName, Args, Options, PatchFun) ->
fun (E) -> io_lib:format("~p", [E]) end)}
end.
%% Add the __call function to a contract.
-spec insert_call_function(string(), string(), [string()], options()) -> string().
insert_call_function(Code, FunName, Args, Options) ->
@ -337,10 +372,26 @@ translate_vm_value(_VmType, _Type, _Data) ->
{ok, binary(), aeb_aevm_data:type(), aeb_aevm_data:type()}
| {error, term()}.
create_calldata(Code, Fun, Args) ->
case check_call(Code, Fun, Args, []) of
create_calldata(Code, Fun, Args, [{backend, aevm}]).
-spec create_calldata(string(), string(), [string()], [{atom(), any()}]) ->
{ok, binary(), aeb_aevm_data:type(), aeb_aevm_data:type()}
| {ok, binary()}
| {error, term()}.
create_calldata(Code, Fun, Args, Options) ->
case proplists:get_value(backend, Options, aevm) of
aevm ->
case check_call(Code, Fun, Args, Options) of
{ok, FunName, {ArgTypes, RetType}, VMArgs} ->
aeb_abi:create_calldata(FunName, VMArgs, ArgTypes, RetType);
aeb_aevm_abi:create_calldata(FunName, VMArgs, ArgTypes, RetType);
{error, _} = Err -> Err
end;
fate ->
case check_call(Code, Fun, Args, Options) of
{ok, FunName, FateArgs} ->
aeb_fate_abi:create_calldata(FunName, FateArgs);
{error, _} = Err -> Err
end
end.
-spec decode_calldata(string(), string(), binary()) ->
@ -467,7 +518,7 @@ to_bytecode([], _) -> [].
extract_type_info(#{functions := Functions} =_Icode) ->
ArgTypesOnly = fun(As) -> [ T || {_, T} <- As ] end,
TypeInfo = [aeb_abi:function_type_info(list_to_binary(lists:last(Name)),
TypeInfo = [aeb_aevm_abi:function_type_info(list_to_binary(lists:last(Name)),
ArgTypesOnly(Args), TypeRep)
|| {Name, Attrs, Args,_Body, TypeRep} <- Functions,
not is_tuple(Name),
@ -537,4 +588,3 @@ pos_error({no_file, Line, Pos}) ->
pos_error({Line, Pos});
pos_error({File, Line, Pos}) ->
io_lib:format("file ~s, line ~p, column ~p", [File, Line, Pos]).

View File

@ -105,7 +105,7 @@ make_args(Args) ->
fun_hash({FName, _, Args, _, TypeRep}) ->
ArgType = {tuple, [T || {_, T} <- Args]},
<<Hash:256>> = aeb_abi:function_type_hash(list_to_binary(lists:last(FName)), ArgType, TypeRep),
<<Hash:256>> = aeb_aevm_abi:function_type_hash(list_to_binary(lists:last(FName)), ArgType, TypeRep),
{integer, Hash}.
%% Expects two return addresses below N elements on the stack. Picks the top