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]}.
|
{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"}
|
, {getopt, "1.0.1"}
|
||||||
, {jsx, {git, "https://github.com/talentdeficit/jsx.git",
|
, {jsx, {git, "https://github.com/talentdeficit/jsx.git",
|
||||||
{tag, "2.8.0"}}}
|
{tag, "2.8.0"}}}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{"1.1.0",
|
{"1.1.0",
|
||||||
[{<<"aebytecode">>,
|
[{<<"aebytecode">>,
|
||||||
{git,"https://github.com/aeternity/aebytecode.git",
|
{git,"https://github.com/aeternity/aebytecode.git",
|
||||||
{ref,"29b5ee3e68086e0f0170d3c70e92bbfa210cbae6"}},
|
{ref,"7dd9c29cc075b52c8f966696e88c8a29fc296240"}},
|
||||||
0},
|
0},
|
||||||
{<<"aeserialization">>,
|
{<<"aeserialization">>,
|
||||||
{git,"https://github.com/aeternity/aeserialization.git",
|
{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),
|
Gas = proplists:get_value("gas", ArgOpts ++ Defaults),
|
||||||
Value = proplists:get_value("value", ArgOpts ++ Defaults),
|
Value = proplists:get_value("value", ArgOpts ++ Defaults),
|
||||||
OutType = ast_typerep(OutT, Icode),
|
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)
|
%% The function is represented by its type hash (which includes the name)
|
||||||
Fun = #integer{value = TypeHash},
|
Fun = #integer{value = TypeHash},
|
||||||
#prim_call_contract{
|
#prim_call_contract{
|
||||||
@ -679,7 +679,7 @@ prim_call(Prim, Amount, Args, ArgTypes, OutType) ->
|
|||||||
true ->
|
true ->
|
||||||
PrimBin = binary:encode_unsigned(Prim),
|
PrimBin = binary:encode_unsigned(Prim),
|
||||||
ArgType = {tuple, ArgTypes},
|
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;
|
TH;
|
||||||
false ->
|
false ->
|
||||||
0
|
0
|
||||||
|
@ -12,7 +12,8 @@
|
|||||||
, file/2
|
, file/2
|
||||||
, from_string/2
|
, from_string/2
|
||||||
, check_call/4
|
, check_call/4
|
||||||
, create_calldata/3
|
, create_calldata/3 %% deprecated
|
||||||
|
, create_calldata/4
|
||||||
, version/0
|
, version/0
|
||||||
, sophia_type_to_typerep/1
|
, sophia_type_to_typerep/1
|
||||||
, to_sophia_value/4
|
, to_sophia_value/4
|
||||||
@ -32,6 +33,7 @@
|
|||||||
| pp_icode
|
| pp_icode
|
||||||
| pp_assembler
|
| pp_assembler
|
||||||
| pp_bytecode
|
| pp_bytecode
|
||||||
|
| {backend, aevm | fate}
|
||||||
| {include, {file_system, [string()]} |
|
| {include, {file_system, [string()]} |
|
||||||
{explicit_files, #{string() => binary()}}}
|
{explicit_files, #{string() => binary()}}}
|
||||||
| {src_file, string()}.
|
| {src_file, string()}.
|
||||||
@ -137,6 +139,18 @@ string_to_icode(ContractString, Options) ->
|
|||||||
type_env => TypeEnv,
|
type_env => TypeEnv,
|
||||||
icode => Icode }.
|
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) ->
|
join_errors(Prefix, Errors, Pfun) ->
|
||||||
Ess = [ Pfun(E) || E <- Errors ],
|
Ess = [ Pfun(E) || E <- Errors ],
|
||||||
list_to_binary(string:join([Prefix|Ess], "\n")).
|
list_to_binary(string:join([Prefix|Ess], "\n")).
|
||||||
@ -150,14 +164,15 @@ join_errors(Prefix, Errors, Pfun) ->
|
|||||||
%% terms for the arguments.
|
%% terms for the arguments.
|
||||||
%% NOTE: Special treatment for "init" since it might be implicit and has
|
%% NOTE: Special treatment for "init" since it might be implicit and has
|
||||||
%% a special return type (typerep, T)
|
%% 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().
|
when Type :: term().
|
||||||
check_call(Source, "init" = FunName, Args, Options) ->
|
check_call(Source, "init" = FunName, Args, Options) ->
|
||||||
PatchFun = fun(T) -> {tuple, [typerep, T]} end,
|
case check_call1(Source, FunName, Args, Options) of
|
||||||
case check_call(Source, FunName, Args, Options, PatchFun) of
|
|
||||||
Err = {error, _} when Args == [] ->
|
Err = {error, _} when Args == [] ->
|
||||||
%% Try with default init-function
|
%% 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...
|
{error, _} -> Err; %% The first error is most likely better...
|
||||||
Res -> Res
|
Res -> Res
|
||||||
end;
|
end;
|
||||||
@ -165,11 +180,12 @@ check_call(Source, "init" = FunName, Args, Options) ->
|
|||||||
Res
|
Res
|
||||||
end;
|
end;
|
||||||
check_call(Source, FunName, Args, Options) ->
|
check_call(Source, FunName, Args, Options) ->
|
||||||
PatchFun = fun(T) -> T end,
|
check_call1(Source, FunName, Args, Options).
|
||||||
check_call(Source, FunName, Args, Options, PatchFun).
|
|
||||||
|
|
||||||
check_call(ContractString0, FunName, Args, Options, PatchFun) ->
|
check_call1(ContractString0, FunName, Args, Options) ->
|
||||||
try
|
try
|
||||||
|
case proplists:get_value(backend, Options, aevm) of
|
||||||
|
aevm ->
|
||||||
%% First check the contract without the __call function
|
%% First check the contract without the __call function
|
||||||
#{} = string_to_icode(ContractString0, Options),
|
#{} = string_to_icode(ContractString0, Options),
|
||||||
ContractString = insert_call_function(ContractString0, FunName, Args, 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),
|
ArgIcode = get_arg_icode(Funs),
|
||||||
ArgTerms = [ icode_to_term(T, Arg) ||
|
ArgTerms = [ icode_to_term(T, Arg) ||
|
||||||
{T, Arg} <- lists:zip(ArgVMTypes, ArgIcode) ],
|
{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
|
catch
|
||||||
error:{parse_errors, Errors} ->
|
error:{parse_errors, Errors} ->
|
||||||
{error, join_errors("Parse errors", Errors, fun (E) -> E end)};
|
{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)}
|
fun (E) -> io_lib:format("~p", [E]) end)}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
|
||||||
%% Add the __call function to a contract.
|
%% Add the __call function to a contract.
|
||||||
-spec insert_call_function(string(), string(), [string()], options()) -> string().
|
-spec insert_call_function(string(), string(), [string()], options()) -> string().
|
||||||
insert_call_function(Code, FunName, Args, Options) ->
|
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()}
|
{ok, binary(), aeb_aevm_data:type(), aeb_aevm_data:type()}
|
||||||
| {error, term()}.
|
| {error, term()}.
|
||||||
create_calldata(Code, Fun, Args) ->
|
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} ->
|
{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
|
{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.
|
end.
|
||||||
|
|
||||||
-spec decode_calldata(string(), string(), binary()) ->
|
-spec decode_calldata(string(), string(), binary()) ->
|
||||||
@ -467,7 +518,7 @@ to_bytecode([], _) -> [].
|
|||||||
|
|
||||||
extract_type_info(#{functions := Functions} =_Icode) ->
|
extract_type_info(#{functions := Functions} =_Icode) ->
|
||||||
ArgTypesOnly = fun(As) -> [ T || {_, T} <- As ] end,
|
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)
|
ArgTypesOnly(Args), TypeRep)
|
||||||
|| {Name, Attrs, Args,_Body, TypeRep} <- Functions,
|
|| {Name, Attrs, Args,_Body, TypeRep} <- Functions,
|
||||||
not is_tuple(Name),
|
not is_tuple(Name),
|
||||||
@ -537,4 +588,3 @@ pos_error({no_file, Line, Pos}) ->
|
|||||||
pos_error({Line, Pos});
|
pos_error({Line, Pos});
|
||||||
pos_error({File, Line, Pos}) ->
|
pos_error({File, Line, Pos}) ->
|
||||||
io_lib:format("file ~s, line ~p, column ~p", [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}) ->
|
fun_hash({FName, _, Args, _, TypeRep}) ->
|
||||||
ArgType = {tuple, [T || {_, T} <- Args]},
|
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}.
|
{integer, Hash}.
|
||||||
|
|
||||||
%% Expects two return addresses below N elements on the stack. Picks the top
|
%% Expects two return addresses below N elements on the stack. Picks the top
|
||||||
|
Loading…
x
Reference in New Issue
Block a user