Merge pull request #86 from aeternity/PT-166602172-create-calldata-fate
Pt 166602172 create calldata fate
This commit is contained in:
commit
5628cf90b8
@ -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"}}}
|
||||
|
@ -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",
|
||||
|
@ -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
|
||||
|
@ -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]).
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user