Contract factories and bytecode introspection #796

Merged
zxq9 merged 34 commits from factories into master 2021-05-18 19:21:57 +09:00
3 changed files with 34 additions and 30 deletions
Showing only changes of commit 614c60f04a - Show all commits

View File

@ -267,16 +267,21 @@ contract_call_type({fun_t, Ann, [], Args, Ret}) ->
bind_contract({Contract, Ann, Id, Contents}, Env) bind_contract({Contract, Ann, Id, Contents}, Env)
when ?IS_CONTRACT_HEAD(Contract) -> when ?IS_CONTRACT_HEAD(Contract) ->
Key = name(Id), Key = name(Id),
io:format("BIND CONTRACT ~p\n", [Id]),
Sys = [{origin, system}], Sys = [{origin, system}],
Fields = Fields =
[ {field_t, AnnF, Entrypoint, contract_call_type(Type)} [ {field_t, AnnF, Entrypoint, contract_call_type(Type)}
|| {fun_decl, AnnF, Entrypoint, Type} <- Contents ] ++ || {fun_decl, AnnF, Entrypoint, Type} <- Contents ] ++
[ {field_t, AnnF, Entrypoint, [ begin
AnnF1 = case {Contract, Name} of
{contract_child, "init"} -> [stateful,payable|AnnF]; %% for create/clone
_ -> AnnF
end,
{field_t, AnnF1, Entrypoint,
contract_call_type( contract_call_type(
{fun_t, AnnF, [], [ArgT || {typed, _, _, ArgT} <- if is_list(Args) -> Args; true -> [Args] end], RetT}) {fun_t, AnnF1, [], [ArgT || {typed, _, _, ArgT} <- if is_list(Args) -> Args; true -> [Args] end], RetT})
} }
|| {letfun, AnnF, Entrypoint, Args, _Type, {typed, _, _, RetT}} <- Contents end
|| {letfun, AnnF, Entrypoint = {id, _, Name}, Args, _Type, {typed, _, _, RetT}} <- Contents
] ++ ] ++
%% Predefined fields %% Predefined fields
[ {field_t, Sys, {id, Sys, "address"}, {id, Sys, "address"}} ], [ {field_t, Sys, {id, Sys, "address"}, {id, Sys, "address"}} ],
@ -439,6 +444,7 @@ global_env() ->
TxFlds = [{"paying_for", Option(PayForTx)}, {"ga_metas", List(GAMetaTx)}, TxFlds = [{"paying_for", Option(PayForTx)}, {"ga_metas", List(GAMetaTx)},
{"actor", Address}, {"fee", Int}, {"ttl", Int}, {"tx", BaseTx}], {"actor", Address}, {"fee", Int}, {"ttl", Int}, {"tx", BaseTx}],
TxType = {record_t, [FldT(N, T) || {N, T} <- TxFlds ]}, TxType = {record_t, [FldT(N, T) || {N, T} <- TxFlds ]},
Stateful = fun(T) -> setelement(2, T, [stateful|element(2, T)]) end,
Fee = Int, Fee = Int,
[A, Q, R, K, V] = lists:map(TVar, ["a", "q", "r", "k", "v"]), [A, Q, R, K, V] = lists:map(TVar, ["a", "q", "r", "k", "v"]),
@ -480,14 +486,16 @@ global_env() ->
{"difficulty", Int}, {"difficulty", Int},
{"gas_limit", Int}, {"gas_limit", Int},
{"bytecode_hash",FunC1(bytecode_hash, A, Option(Hash))}, {"bytecode_hash",FunC1(bytecode_hash, A, Option(Hash))},
{"create", FunN([ {named_arg_t, Ann, {id, Ann, "value"}, Int, {typed, Ann, {int, Ann, 0}, Int}} {"create", Stateful(
], var_args, A)}, FunN([ {named_arg_t, Ann, {id, Ann, "value"}, Int, {typed, Ann, {int, Ann, 0}, Int}}
{"clone", FunN([ {named_arg_t, Ann, {id, Ann, "gas"}, Int, ], var_args, A))},
{"clone", Stateful(
FunN([ {named_arg_t, Ann, {id, Ann, "gas"}, Int,
{qid, Ann, ["Call","gas_left"]}} {qid, Ann, ["Call","gas_left"]}}
, {named_arg_t, Ann, {id, Ann, "value"}, Int, {typed, Ann, {int, Ann, 0}, Int}} , {named_arg_t, Ann, {id, Ann, "value"}, Int, {typed, Ann, {int, Ann, 0}, Int}}
, {named_arg_t, Ann, {id, Ann, "protected"}, Bool, {typed, Ann, {bool, Ann, false}, Bool}} , {named_arg_t, Ann, {id, Ann, "protected"}, Bool, {typed, Ann, {bool, Ann, false}, Bool}}
, {named_arg_t, Ann, {id, Ann, "ref"}, A, undefined} , {named_arg_t, Ann, {id, Ann, "ref"}, A, undefined}
], var_args, A)}, ], var_args, A))},
%% Tx constructors %% Tx constructors
{"GAMetaTx", Fun([Address, Int], GAMetaTx)}, {"GAMetaTx", Fun([Address, Int], GAMetaTx)},
{"PayingForTx", Fun([Address, Int], PayForTx)}, {"PayingForTx", Fun([Address, Int], PayForTx)},
@ -751,9 +759,10 @@ infer1(Env, [{Contract, Ann, ConName, Code} | Rest], Acc, Options)
when ?IS_CONTRACT_HEAD(Contract) -> when ?IS_CONTRACT_HEAD(Contract) ->
%% do type inference on each contract independently. %% do type inference on each contract independently.
check_scope_name_clash(Env, contract, ConName), check_scope_name_clash(Env, contract, ConName),
What = case aeso_syntax:get_ann(interface, Ann, false) of What = case Contract of
true -> contract_interface; contract_main -> contract;
false -> contract contract_child -> contract;
contract_interface -> contract_interface
end, end,
{Env1, Code1} = infer_contract_top(push_scope(contract, ConName, Env), What, Code, Options), {Env1, Code1} = infer_contract_top(push_scope(contract, ConName, Env), What, Code, Options),
Contract1 = {Contract, Ann, ConName, Code1}, Contract1 = {Contract, Ann, ConName, Code1},
@ -769,23 +778,18 @@ infer1(Env, [{pragma, _, _} | Rest], Acc, Options) ->
%% Pragmas are checked in check_modifiers %% Pragmas are checked in check_modifiers
infer1(Env, Rest, Acc, Options). infer1(Env, Rest, Acc, Options).
%% Checks if the main contract is somehow defined. %% Asserts that the main contract is somehow defined.
%% Performs some basic sorting to make the dependencies more happy.
identify_main_contract(Contracts) -> identify_main_contract(Contracts) ->
Childs = [C || C = {contract_child, _, _, _} <- Contracts], Children = [C || C = {contract_child, _, _, _} <- Contracts],
Mains = [C || C = {contract_main, _, _, _} <- Contracts], Mains = [C || C = {contract_main, _, _, _} <- Contracts],
Interfaces = [C || C = {contract_interface, _, _, _} <- Contracts],
Namespaces = [N || N = {namespace, _, _, _} <- Contracts],
case Mains of case Mains of
[] -> case Childs of [] -> case Children of
[] -> type_error({main_contract_undefined}); [] -> type_error({main_contract_undefined});
[{contract_child, Ann, Con, Body}] -> [{contract_child, Ann, Con, Body}] ->
Interfaces ++ Namespaces ++ (Contracts -- Children) ++ [{contract_main, Ann, Con, Body}];
[C || C = {_, _, Con1, _} <- Childs, Con1 /= Con] ++
[{contract_main, Ann, Con, Body}];
_ -> type_error({ambiguous_main_contract}) _ -> type_error({ambiguous_main_contract})
end; end;
[_] -> Interfaces ++ Namespaces ++ Childs ++ Mains; [_] -> Contracts;
_ -> type_error({multiple_main_contracts}) _ -> type_error({multiple_main_contracts})
end. end.

View File

@ -723,7 +723,7 @@ expr_to_fcode(Env, Type, {app, _, Fun = {typed, _, FunE, {fun_t, _, NamedArgsT,
{var_args, _} -> fcode_error({var_args_not_set, FunE}); {var_args, _} -> fcode_error({var_args_not_set, FunE});
{_, {con, _, Contract}} -> {_, {con, _, Contract}} ->
FInitArgsT = {typerep, {tuple, [type_to_fcode(Env, T) || T <- ArgsT]}}, FInitArgsT = {typerep, {tuple, [type_to_fcode(Env, T) || T <- ArgsT]}},
builtin_to_fcode(state_layout(Env), chain_clone, [{lit, {contract_code, Contract}}, {lit, FInitArgsT}|FArgs]); builtin_to_fcode(state_layout(Env), chain_create, [{lit, {contract_code, Contract}}, {lit, FInitArgsT}|FArgs]);
{_, _} -> fcode_error({not_a_contract_type, Type}) {_, _} -> fcode_error({not_a_contract_type, Type})
end; end;
{builtin_u, B, _Ar} -> builtin_to_fcode(state_layout(Env), B, FArgs); {builtin_u, B, _Ar} -> builtin_to_fcode(state_layout(Env), B, FArgs);

View File

@ -585,9 +585,9 @@ builtin_to_scode(Env, chain_clone,
[Contract, TypeRep, Value, GasCap, Prot | InitArgs] [Contract, TypeRep, Value, GasCap, Prot | InitArgs]
); );
builtin_to_scode(Env, chain_create, builtin_to_scode(Env, chain_create,
[ Code, TypeRep | InitArgs]) -> [ Code, TypeRep, Value | InitArgs]) ->
call_to_scode(Env, aeb_fate_ops:create(?a, ?a, ?a), call_to_scode(Env, aeb_fate_ops:create(?a, ?a, ?a),
[Code, TypeRep | InitArgs] [Code, TypeRep, Value | InitArgs]
). ).