Make Contract Calls Great Again #35

Merged
zxq9 merged 37 commits from iface3 into master 2026-05-10 15:39:25 +09:00
Showing only changes of commit 8b390f8d82 - Show all commits
+72 -35
View File
@@ -40,8 +40,8 @@
-type fun_name() :: string(). -type fun_name() :: string().
-type fun_type() :: call | dryr | init. -type fun_ilk() :: call | dryr | init.
-type fun_def() :: {fun_name(), fun_type()}. -type fun_def() :: {fun_name(), fun_ilk()}.
-type param() :: {Label :: string(), Check :: fun(), #w{}}. -type param() :: {Label :: string(), Check :: fun(), #w{}}.
-type status() :: none -type status() :: none
| submitted | submitted
@@ -89,14 +89,14 @@ start_link(Args) ->
wx_object:start_link({local, ?MODULE}, ?MODULE, Args, []). wx_object:start_link({local, ?MODULE}, ?MODULE, Args, []).
init({Prefs, FunDef = {FunName, FunType}, ConID, Build, Selected, Keys}) -> init({Prefs, FunDef = {FunName, FunIlk}, ConID, Build, Selected, Keys}) ->
Lang = maps:get(lang, Prefs, en), Lang = maps:get(lang, Prefs, en),
Trans = gd_jt:read_translations(?MODULE), Trans = gd_jt:read_translations(?MODULE),
J = gd_jt:j(Lang, Trans), J = gd_jt:j(Lang, Trans),
{aaci, ConName, FunSpecs, _} = maps:get(aaci, Build), {aaci, ConName, FunSpecs, _} = maps:get(aaci, Build),
FunSpec = maps:get(FunName, FunSpecs), FunSpec = maps:get(FunName, FunSpecs),
{CallTypeLabel, ActionLabel} = {CallTypeLabel, ActionLabel} =
case FunType of case FunIlk of
call -> {J("Contract Call"), J("Submit Call")}; call -> {J("Contract Call"), J("Submit Call")};
dryr -> {J("Dry Run"), J("Submit Dry Run")}; dryr -> {J("Dry Run"), J("Submit Dry Run")};
init -> {J("Deploy"), J("Deploy")} init -> {J("Deploy"), J("Deploy")}
@@ -115,7 +115,7 @@ init({Prefs, FunDef = {FunName, FunType}, ConID, Build, Selected, Keys}) ->
ok = wxChoice:setSelection(KeyPicker, ZeroBasedSelected), ok = wxChoice:setSelection(KeyPicker, ZeroBasedSelected),
_ = wxStaticBoxSizer:add(KeySz, KeyPicker, zxw:flags(wide)), _ = wxStaticBoxSizer:add(KeySz, KeyPicker, zxw:flags(wide)),
{ArgSz, Args, Return, Copy, HasArgs} = call_arg_sizer(Frame, J, FunType, FunSpec), {ArgSz, Args, Return, Copy, HasArgs} = call_arg_sizer(Frame, J, FunIlk, FunSpec),
{ParamSz, Params} = call_param_sizer(Frame, J), {ParamSz, Params} = call_param_sizer(Frame, J),
Action = #w{wx = ActionBn} = gd_lib:button(Frame, ActionLabel), Action = #w{wx = ActionBn} = gd_lib:button(Frame, ActionLabel),
@@ -157,11 +157,11 @@ init({Prefs, FunDef = {FunName, FunType}, ConID, Build, Selected, Keys}) ->
{Frame, State}. {Frame, State}.
call_arg_sizer(Frame, J, {CallArgs, FunType, ReturnType}) -> call_arg_sizer(Frame, J, FunIlk, {CallArgs, ReturnType}) ->
SpecSz = wxStaticBoxSizer:new(?wxVERTICAL, Frame, [{label, J("Function Spec")}]), SpecSz = wxStaticBoxSizer:new(?wxVERTICAL, Frame, [{label, J("Function Spec")}]),
SpecBox = wxStaticBoxSizer:getStaticBox(SpecSz), SpecBox = wxStaticBoxSizer:getStaticBox(SpecSz),
{CallSz, CallControls, HasArgs} = call_sizer(SpecBox, J, CallArgs), {CallSz, CallControls, HasArgs} = call_sizer(SpecBox, J, CallArgs),
{ReturnSz, Return, Copy} = return_sizer(SpecBox, J, FunType, ReturnType), {ReturnSz, Return, Copy} = return_sizer(SpecBox, J, FunIlk, ReturnType),
_ = wxStaticBoxSizer:add(SpecSz, CallSz, zxw:flags({wide, 5})), _ = wxStaticBoxSizer:add(SpecSz, CallSz, zxw:flags({wide, 5})),
_ = wxStaticBoxSizer:add(SpecSz, ReturnSz, zxw:flags({base, 5})), _ = wxStaticBoxSizer:add(SpecSz, ReturnSz, zxw:flags({base, 5})),
{SpecSz, CallControls, Return, Copy, HasArgs}. {SpecSz, CallControls, Return, Copy, HasArgs}.
@@ -195,21 +195,22 @@ call_sizer(Parent, J, CallArgs) ->
Controls = lists:map(AddArg, CallArgs), Controls = lists:map(AddArg, CallArgs),
{CallSz, Controls, true}. {CallSz, Controls, true}.
return_sizer(Parent, J, FunType, ReturnType) -> return_sizer(Parent, J, FunIlk, ReturnType) ->
TypeLabel = IlkLabel =
case FunType =:= init of case FunIlk =:= init of
false -> textify(ReturnType); false -> textify(ReturnType);
true -> J("Contract Address") true -> J("Contract Address")
end, end,
ReturnSz = wxStaticBoxSizer:new(?wxVERTICAL, Parent, [{label, J("Return Type")}]), ReturnSz = wxStaticBoxSizer:new(?wxVERTICAL, Parent, [{label, J("Return Type")}]),
ReturnSzBox = wxStaticBoxSizer:getStaticBox(ReturnSz), ReturnSzBox = wxStaticBoxSizer:getStaticBox(ReturnSz),
ReturnLabel = wxStaticText:new(ReturnSzBox, ?wxID_ANY, TypeLabel), ReturnLabel = wxStaticText:new(ReturnSzBox, ?wxID_ANY, IlkLabel),
Single = [{style, ?wxTE_READONLY}], Single = [{style, ?wxTE_READONLY}],
Return = #w{wx = ReturnTx} = gd_lib:mono_text(ReturnSzBox, return, "", Single), Return = #w{wx = ReturnTx} = gd_lib:mono_text(ReturnSzBox, return, "", Single),
Copy = #w{wx = CopyBn} = gd_lib:button(ReturnSzBox, J("Copy")), Copy = #w{wx = CopyB} = gd_lib:button(ReturnSzBox, J("Copy")),
_ = wxButton:disable(CopyB),
_ = wxStaticBoxSizer:add(ReturnSz, ReturnLabel, zxw:flags({wide, 5})), _ = wxStaticBoxSizer:add(ReturnSz, ReturnLabel, zxw:flags({wide, 5})),
_ = wxStaticBoxSizer:add(ReturnSz, ReturnTx, zxw:flags({wide, 5})), _ = wxStaticBoxSizer:add(ReturnSz, ReturnTx, zxw:flags({wide, 5})),
_ = wxStaticBoxSizer:add(ReturnSz, CopyBn, zxw:flags({wide, 5})), _ = wxStaticBoxSizer:add(ReturnSz, CopyB, zxw:flags({wide, 5})),
{ReturnSz, Return, Copy}. {ReturnSz, Return, Copy}.
@@ -253,6 +254,9 @@ call_param_sizer(Frame, J) ->
{ParamSz, Params}. {ParamSz, Params}.
%%% Spine
handle_call(tx_hash, _, State) -> handle_call(tx_hash, _, State) ->
TXHash = do_tx_hash(State), TXHash = do_tx_hash(State),
{reply, TXHash, State}; {reply, TXHash, State};
@@ -270,6 +274,8 @@ handle_cast(Unexpected, State) ->
{noreply, State}. {noreply, State}.
handle_info(retire, State) ->
retire(State);
handle_info(Unexpected, State) -> handle_info(Unexpected, State) ->
ok = log(warning, "Unexpected info: ~tp~n", [Unexpected]), ok = log(warning, "Unexpected info: ~tp~n", [Unexpected]),
{noreply, State}. {noreply, State}.
@@ -287,9 +293,8 @@ handle_event(#wx{event = #wxCommand{type = command_button_clicked}, id = ID},
State = #s{copy = #w{id = ID}}) -> State = #s{copy = #w{id = ID}}) ->
ok = copy(State), ok = copy(State),
{noreply, State}; {noreply, State};
handle_event(#wx{event = #wxClose{}}, State = #s{frame = Frame}) -> handle_event(#wx{event = #wxClose{}}, State) ->
ok = wxWindow:destroy(Frame), retire(State);
{noreply, State};
handle_event(Event, State) -> handle_event(Event, State) ->
ok = tell(info, "Unexpected event ~tp State: ~tp~n", [Event, State]), ok = tell(info, "Unexpected event ~tp State: ~tp~n", [Event, State]),
{noreply, State}. {noreply, State}.
@@ -299,11 +304,19 @@ code_change(_, State, _) ->
{ok, State}. {ok, State}.
retire(State = #s{frame = Frame}) ->
ok = wxWindow:destroy(Frame),
{noreply, State}.
terminate(Reason, State) -> terminate(Reason, State) ->
ok = log(info, "Reason: ~tp, State: ~tp", [Reason, State]), ok = log(info, "Reason: ~tp, State: ~tp", [Reason, State]),
wx:destroy(). wx:destroy().
%%% Handlers
handle_troubling(State = #s{frame = Frame}, Info) -> handle_troubling(State = #s{frame = Frame}, Info) ->
ok = wxFrame:raise(Frame), ok = wxFrame:raise(Frame),
ok = zxw:show_message(Frame, Info), ok = zxw:show_message(Frame, Info),
@@ -340,12 +353,12 @@ prep_call4(State = #s{fundef = {"init", init}, build = Build}, ChainID, Params,
{ok, CreateTX} -> deploy(State, ChainID, CallerID, CreateTX); {ok, CreateTX} -> deploy(State, ChainID, CallerID, CreateTX);
Error -> handle_troubling(State, Error) Error -> handle_troubling(State, Error)
end; end;
prep_call4(State = #s{fundef = {Name, Type}, con_id = ConID, build = Build}, ChainID, Params, Args) -> prep_call4(State = #s{fundef = {Name, Ilk}, con_id = ConID, build = Build}, ChainID, Params, Args) ->
{CallerID, Nonce, TTL, Gas, GP, Amount} = Params, {CallerID, Nonce, TTL, Gas, GP, Amount} = Params,
AACI = maps:get(aaci, Build), AACI = maps:get(aaci, Build),
case hz:contract_call(CallerID, Nonce, Gas, GP, Amount, TTL, AACI, ConID, Name, Args) of case hz:contract_call(CallerID, Nonce, Gas, GP, Amount, TTL, AACI, ConID, Name, Args) of
{ok, UnsignedTX} -> {ok, UnsignedTX} ->
case Type of case Ilk of
call -> do_call(State, ChainID, CallerID, UnsignedTX); call -> do_call(State, ChainID, CallerID, UnsignedTX);
dryr -> do_dry_run(State, ConID, UnsignedTX) dryr -> do_dry_run(State, ConID, UnsignedTX)
end; end;
@@ -388,7 +401,7 @@ deploy(State, ChainID, CallerID, CreateTX) ->
Error -> handle_troubling(State, Error) Error -> handle_troubling(State, Error)
end. end.
deploy2(State = #s{hash = #w{wx = HashT}, action = #w{wx = ActionB}}, SignedTX) -> deploy2(State = #s{j = J, hash = #w{wx = HashT}, action = #w{wx = ActionB}}, SignedTX) ->
case hz:post_tx(SignedTX) of case hz:post_tx(SignedTX) of
{ok, Data = #{"tx_hash" := TXHash}} -> {ok, Data = #{"tx_hash" := TXHash}} ->
_ = wxButton:disable(ActionB), _ = wxButton:disable(ActionB),
@@ -411,7 +424,6 @@ do_call(State, ChainID, CallerID, UnsignedTX) ->
do_call2(State = #s{action = #w{wx = ActionB}}, SignedTX) -> do_call2(State = #s{action = #w{wx = ActionB}}, SignedTX) ->
_ = wxButton:disable(ActionB), _ = wxButton:disable(ActionB),
ok = wxButton:setLabel(ActionB, J("Check Transaction Status")),
case hz:post_tx(SignedTX) of case hz:post_tx(SignedTX) of
{ok, Data} -> check_tx(State#s{tx_data = Data, status = submitted}); {ok, Data} -> check_tx(State#s{tx_data = Data, status = submitted});
Error -> handle_troubling(State, Error) Error -> handle_troubling(State, Error)
@@ -425,41 +437,66 @@ do_dry_run(State = #s{action = #w{wx = ActionB}}, ConID, TX) ->
Other -> handle_troubling(State, {error, ConID, Other}) Other -> handle_troubling(State, {error, ConID, Other})
end. end.
check_tx(State = #s{fundef = {_, init}, check_tx(State = #s{frame = Frame,
j = J,
fundef = {_, init},
tx_data = #{"tx_hash" := TXHash}, tx_data = #{"tx_hash" := TXHash},
tx_info = none, tx_info = none,
return = #w{wx = ReturnT},
status = submitted, status = submitted,
action = #w{wx = ActionB}, action = #w{wx = ActionB},
info = #w{wx = InfoT}}) -> info = #w{wx = InfoT}}) ->
case hz:tx_info(TXHash) of case hz:tx_info(TXHash) of
{ok, Info = #{"call_info" := #{"return_type" := "ok", "contract_id" := ConID}}} -> {ok, Info = #{"call_info" := #{"return_type" := "ok", "contract_id" := ConID}}} ->
ok = wxTextCtrl:setValue(ReturnT, ConID), ok = tell(info, "Contract deployed: ~p", [Info]),
ok = gd_v_devman:open_contract(ConID), ok = gd_con:open_contract(ConID),
FormattedInfo = io_lib:fomat("~tw", [Info]), ok = wxWindow:destroy(Frame),
ok = wxTextCtrl:setValue(InfoT, FormattedInfo), exit(0);
Other ->
check_tx(State = #s{tx_data = #{"tx_hash" := TXHash}, FormattedJunk = io_lib:format("~tp", [Other]),
ok = wxTextCtrl:setValue(InfoT, FormattedJunk),
ok = wxButton:setLabel(ActionB, J("Deploy")),
_ = wxButton:enable(ActionB),
State#s{status = none}
end;
check_tx(State = #s{j = J,
con_id = ConID,
tx_data = #{"tx_hash" := TXHash},
tx_info = none, tx_info = none,
status = submitted, status = submitted,
return = #w{wx = ReturnT},
copy = #w{wx = CopyB},
action = #w{wx = ActionB}, action = #w{wx = ActionB},
info = #w{wx = InfoT}}) -> info = #w{wx = InfoT}}) ->
case hz:tx_info(TXHash) of case hz:tx_info(TXHash) of
{ok, Info = #{"call_info" := #{"return_type" := "ok", {ok, Info = #{"call_info" := #{"return_type" := "ok",
"contract_id" := ConID, "contract_id" := ConID,
"return_value" := Value}}} -> "return_value" := Value}}} ->
FormattedInfo = io_lib:fomat("~tw", [Info]), FormattedInfo = io_lib:fomat("~tp", [Info]),
_ = wxButton:enable(CopyB),
_ = wxButton:disable(ActionB),
ok = wxTextCtrl:setValue(ReturnT, Value),
ok = wxTextCtrl:setValue(InfoT, FormattedInfo), ok = wxTextCtrl:setValue(InfoT, FormattedInfo),
ok = gd_v_devman:open_contract(ConID), ok = gd_con:show_call_result(ConID, Info),
update_info(State#s{tx_info = Info}); update_info(State#s{status = included, tx_info = Info});
{error, "Tx not mined"} ->
handle_troubling(State, {error, not_mined});
{ok, Reason = #{"call_info" := #{"return_type" := "revert"}}} -> {ok, Reason = #{"call_info" := #{"return_type" := "revert"}}} ->
handle_troubling(State, {error, Reason}); _ = wxButton:enable(CopyB),
_ = wxButton:disable(ActionB),
FormattedInfo = io_lib:format("~tp", [Reason]),
ok = wxTextCtrl:setValue(ReturnT, FormattedInfo), % FIXME
ok = wxTextCtrl:setValue(InfoT, FormattedInfo),
ok = gd_con:show_call_result(ConID, Reason),
State#s{status = rejected, tx_info = Reason};
{error, "Tx not mined"} ->
ok = wxTextCtrl:setValue(InfoT, J("Transaction not yet mined.")),
ok = wxButton:setLabel(ActionB, J("Check Transaction Status")),
_ = wxButton:enable(ActionB),
State;
Error -> Error ->
handle_troubling(State, Error) handle_troubling(State, Error)
end; end;
check_tx(State = #s{tx_data = TXData}) -> check_tx(State = #s{tx_data = TXData,
action = #w{wx = ActionB}}) ->
_ = wxButton:disable(ActionB),
tell(info, "TXData: ~p", [TXData]), tell(info, "TXData: ~p", [TXData]),
ok = tell("Nothing to check"), ok = tell("Nothing to check"),
State. State.