Avoid hash collisions in calldata creation
This commit is contained in:
parent
3a6337d8ca
commit
95c41b8eee
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,5 +1,5 @@
|
|||||||
.rebar3
|
.rebar3
|
||||||
_*
|
_[^_]*
|
||||||
.eunit
|
.eunit
|
||||||
*.o
|
*.o
|
||||||
*.beam
|
*.beam
|
||||||
|
@ -186,21 +186,21 @@ check_call1(ContractString0, FunName, Args, Options) ->
|
|||||||
try
|
try
|
||||||
case proplists:get_value(backend, Options, aevm) of
|
case proplists:get_value(backend, Options, aevm) of
|
||||||
aevm ->
|
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, ?CALL_NAME, FunName, Args, Options),
|
||||||
#{typed_ast := TypedAst,
|
#{typed_ast := TypedAst,
|
||||||
icode := Icode} = string_to_icode(ContractString, Options),
|
icode := Icode} = string_to_icode(ContractString, Options),
|
||||||
{ok, {FunName, {fun_t, _, _, ArgTypes, RetType}}} = get_call_type(TypedAst),
|
{ok, {FunName, {fun_t, _, _, ArgTypes, RetType}}} = get_call_type(TypedAst),
|
||||||
ArgVMTypes = [ aeso_ast_to_icode:ast_typerep(T, Icode) || T <- ArgTypes ],
|
ArgVMTypes = [ aeso_ast_to_icode:ast_typerep(T, Icode) || T <- ArgTypes ],
|
||||||
RetVMType = case RetType of
|
RetVMType = case RetType of
|
||||||
{id, _, "_"} -> any;
|
{id, _, "_"} -> any;
|
||||||
_ -> aeso_ast_to_icode:ast_typerep(RetType, Icode)
|
_ -> aeso_ast_to_icode:ast_typerep(RetType, Icode)
|
||||||
end,
|
end,
|
||||||
#{ functions := Funs } = Icode,
|
#{ functions := Funs } = Icode,
|
||||||
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) ],
|
||||||
RetVMType1 =
|
RetVMType1 =
|
||||||
case FunName of
|
case FunName of
|
||||||
"init" -> {tuple, [typerep, RetVMType]};
|
"init" -> {tuple, [typerep, RetVMType]};
|
||||||
@ -211,13 +211,13 @@ check_call1(ContractString0, FunName, Args, Options) ->
|
|||||||
%% First check the contract without the __call function
|
%% First check the contract without the __call function
|
||||||
#{fcode := OrgFcode} = string_to_fcode(ContractString0, Options),
|
#{fcode := OrgFcode} = string_to_fcode(ContractString0, Options),
|
||||||
FateCode = aeso_fcode_to_fate:compile(OrgFcode, []),
|
FateCode = aeso_fcode_to_fate:compile(OrgFcode, []),
|
||||||
_SymbolHashes = maps:keys(aeb_fate_code:symbols(FateCode)),
|
%% collect all hashes and compute the first name without hash collision to
|
||||||
%% TODO collect all hashes and compute the first name without hash collision to
|
SymbolHashes = maps:keys(aeb_fate_code:symbols(FateCode)),
|
||||||
%% be used as __callX
|
CallName = first_none_match(?CALL_NAME, SymbolHashes,
|
||||||
%% case aeb_fate_code:symbol_identifier(<<"__call">>) of
|
lists:seq($1, $9) ++ lists:seq($A, $Z) ++ lists:seq($a, $z)),
|
||||||
ContractString = insert_call_function(ContractString0, FunName, Args, Options),
|
ContractString = insert_call_function(ContractString0, CallName, FunName, Args, Options),
|
||||||
#{fcode := Fcode} = string_to_fcode(ContractString, Options),
|
#{fcode := Fcode} = string_to_fcode(ContractString, Options),
|
||||||
#{args := CallArgs} = maps:get({entrypoint, <<"__call">>}, maps:get(functions, Fcode)),
|
#{args := CallArgs} = maps:get({entrypoint, list_to_binary(CallName)}, maps:get(functions, Fcode)),
|
||||||
{ok, FunName, CallArgs}
|
{ok, FunName, CallArgs}
|
||||||
end
|
end
|
||||||
catch
|
catch
|
||||||
@ -233,17 +233,26 @@ check_call1(ContractString0, FunName, Args, Options) ->
|
|||||||
fun (E) -> io_lib:format("~p", [E]) end)}
|
fun (E) -> io_lib:format("~p", [E]) end)}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
first_none_match(CallName, Hashes, []) ->
|
||||||
|
error(unable_to_find_unique_call_name);
|
||||||
|
first_none_match(CallName, Hashes, [Char|Chars]) ->
|
||||||
|
case not lists:member(aeb_fate_code:symbol_identifier(list_to_binary(CallName)), Hashes) of
|
||||||
|
true ->
|
||||||
|
CallName;
|
||||||
|
false ->
|
||||||
|
first_none_match(?CALL_NAME++[Char], Hashes, Chars)
|
||||||
|
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(), [string()], options()) -> string().
|
||||||
insert_call_function(Code, FunName, Args, Options) ->
|
insert_call_function(Code, Call, FunName, Args, Options) ->
|
||||||
Ast = parse(Code, Options),
|
Ast = parse(Code, Options),
|
||||||
Ind = last_contract_indent(Ast),
|
Ind = last_contract_indent(Ast),
|
||||||
lists:flatten(
|
lists:flatten(
|
||||||
[ Code,
|
[ Code,
|
||||||
"\n\n",
|
"\n\n",
|
||||||
lists:duplicate(Ind, " "),
|
lists:duplicate(Ind, " "),
|
||||||
"stateful function __call() = ", FunName, "(", string:join(Args, ","), ")\n"
|
"stateful function ", Call,"() = ", FunName, "(", string:join(Args, ","), ")\n"
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-spec insert_init_function(string(), options()) -> string().
|
-spec insert_init_function(string(), options()) -> string().
|
||||||
|
5
test/contracts/__call.aes
Normal file
5
test/contracts/__call.aes
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
|
||||||
|
contract Identity =
|
||||||
|
function main (x:int) = x
|
||||||
|
|
||||||
|
function __call() = 12
|
Loading…
x
Reference in New Issue
Block a user