From 4fd4ab3f54289e1ac4bf7effea0b80de789b8ecf Mon Sep 17 00:00:00 2001 From: Craig Everett Date: Wed, 5 Mar 2025 22:35:18 +0900 Subject: [PATCH] Move common functionality to the Hakuzaru library --- src/gd_con.erl | 110 ++++++++++++++----------------------------------- src/gd_gui.erl | 41 ++++++------------ 2 files changed, 45 insertions(+), 106 deletions(-) diff --git a/src/gd_con.erl b/src/gd_con.erl index 0ab0b76..d68ae4b 100644 --- a/src/gd_con.erl +++ b/src/gd_con.erl @@ -14,7 +14,7 @@ selected/1, password/2, refresh/0, - nonce/1, spend/2, chain/1, grids/1, sign_mess/1, sign_tx/1, sign_call/3, dry_run/2, + nonce/1, spend/1, chain/1, grids/1, sign_mess/1, sign_tx/1, sign_call/3, dry_run/2, deploy/3, make_key/6, recover_key/1, mnemonic/1, rename_key/2, drop_key/1, list_keys/0, add_node/1, set_sole_node/1]). @@ -135,12 +135,11 @@ nonce(ID) -> gen_server:call(?MODULE, {nonce, ID}). --spec spend(KeyID, TX) -> ok - when KeyID :: gajudesk:id(), - TX :: #spend_tx{}. +-spec spend(TX) -> ok + when TX :: #spend_tx{}. -spend(KeyID, TX) -> - gen_server:cast(?MODULE, {spend, KeyID, TX}). +spend(TX) -> + gen_server:cast(?MODULE, {spend, TX}). -spec chain(ID) -> ok @@ -400,8 +399,8 @@ handle_cast({password, Old, New}, State) -> handle_cast(refresh, State) -> NewState = do_refresh(State), {noreply, NewState}; -handle_cast({spend, KeyID, TX}, State) -> - ok = do_spend(KeyID, TX, State), +handle_cast({spend, TX}, State) -> + ok = do_spend(TX, State), {noreply, State}; handle_cast({chain, ID}, State) -> NewState = do_chain(ID, State), @@ -589,7 +588,6 @@ ensure_hz_set(Node = #node{ip = IP, external = Port}) -> [{IP, Port}] -> case hz:status() of {ok, #{"network_id" := ChainID}} -> - ok = hz:network_id(ChainID), ok = gd_gui:chain(ChainID, Node), {ok, list_to_binary(ChainID)}; {error, no_nodes} -> @@ -714,7 +712,7 @@ do_sign_tx(Request = #{"public_id" := ID, "payload" := CallData, "network_id" := case lists:keyfind(ID, #key.id, Keys) of #key{pair = #{secret := SecKey}} -> BinaryTX = list_to_binary(CallData), - SignedTX = sign_tx_hash(BinaryTX, SecKey, BinNID), + SignedTX = hz:sign_tx(BinaryTX, SecKey, BinNID), do_sign_tx2(Request#{"signed" => true, "payload" := SignedTX}); false -> gd_gui:trouble({bad_key, ID}) @@ -736,29 +734,13 @@ do_sign_tx2(Request = #{"url" := URL}) -> Error -> gd_gui:trouble(Error) end. -sign_tx_hash(Unsigned, SecKey, NetworkID) -> - {ok, TX_Data} = gmser_api_encoder:safe_decode(transaction, Unsigned), - {ok, Hash} = eblake2:blake2b(32, TX_Data), - NetworkHash = <>, - Signature = ecu_eddsa:sign_detached(NetworkHash, SecKey), - SigTxType = signed_tx, - SigTxVsn = 1, - SigTemplate = - [{signatures, [binary]}, - {transaction, binary}], - TX = - [{signatures, [Signature]}, - {transaction, TX_Data}], - SignedTX = gmser_chain_objects:serialize(SigTxType, SigTxVsn, SigTemplate, TX), - gmser_api_encoder:encode(transaction, SignedTX). - do_sign_call(#s{wallet = #wallet{keys = Keys, chain_id = ChainID}}, ConID, PubKey, TX) -> #key{pair = #{secret := SecKey}} = lists:keyfind(PubKey, #key.id, Keys), - SignedTX = sign_tx_hash(TX, SecKey, ChainID), + SignedTX = hz:sign_tx(TX, SecKey, ChainID), case hz:post_tx(SignedTX) of {ok, Data = #{"tx_hash" := TXHash}} -> ok = tell("TX succeded with: ~p", [TXHash]), @@ -791,60 +773,32 @@ do_dry_run(ConID, TX) -> end. -do_spend(KeyID, TX, State = #s{wallet = #wallet{keys = Keys}}) -> - case lists:keyfind(KeyID, #key.id, Keys) of +do_spend(#spend_tx{sender_id = SenderID, + recipient_id = RecipientID, + amount = Amount, + gas_price = GasPrice, + gas = Gas, + ttl = TTL, + nonce = Nonce, + payload = Payload}, + #s{wallet = #wallet{keys = Keys, chain_id = NetworkID}}) -> + case lists:keyfind(SenderID, #key.id, Keys) of #key{pair = #{secret := SecKey}} -> - do_spend2(SecKey, TX, State); + Outcome = hz:spend(SenderID, + SecKey, + RecipientID, + Amount, + GasPrice, + Gas, + TTL, + Nonce, + Payload, + NetworkID), + tell(info, "Outcome: ~p", [Outcome]); false -> - log(warning, "Tried do_spend with a bad key: ~p", [KeyID]) + log(warning, "Tried do_spend with a bad key: ~p", [SenderID]) end. -do_spend2(SecKey, - #spend_tx{sender_id = SenderID, - recipient_id = RecipientID, - amount = Amount, - gas_price = GasPrice, - gas = Gas, - ttl = TTL, - nonce = Nonce, - payload = Payload}, - #s{wallet = #wallet{chain_id = ChainID}}) -> - Type = spend_tx, - Vsn = 1, - Fields = - [{sender_id, SenderID}, - {recipient_id, RecipientID}, - {amount, Amount}, - {gas_price, GasPrice}, - {gas, Gas}, - {ttl, TTL}, - {nonce, Nonce}, - {payload, Payload}], - Template = - [{sender_id, id}, - {recipient_id, id}, - {amount, int}, - {gas_price, int}, - {gas, int}, - {ttl, int}, - {nonce, int}, - {payload, binary}], - BinaryTX = gmser_chain_objects:serialize(Type, Vsn, Template, Fields), - NetworkTX = <>, - Signature = ecu_eddsa:sign_detached(NetworkTX, SecKey), - SigTxType = signed_tx, - SigTxVsn = 1, - SigTemplate = - [{signatures, [binary]}, - {transaction, binary}], - TX_Data = - [{signatures, [Signature]}, - {transaction, BinaryTX}], - SignedTX = gmser_chain_objects:serialize(SigTxType, SigTxVsn, SigTemplate, TX_Data), - Encoded = gmser_api_encoder:encode(transaction, SignedTX), - Outcome = hz:post_tx(Encoded), - tell("Outcome: ~p", [Outcome]). - do_list_keys(#s{selected = Selected, wallet = #wallet{poas = POAs}}) -> {ok, Selected, [ID || #poa{id = ID} <- POAs]}; @@ -996,7 +950,7 @@ do_deploy(Build, end. do_deploy2(SecKey, CreateTX, ChainID) -> - SignedTX = sign_tx_hash(CreateTX, SecKey, ChainID), + SignedTX = hz:sign_tx(CreateTX, SecKey, ChainID), tell(info, "SignedTX: ~p", [SignedTX]), case hz:post_tx(SignedTX) of {ok, Data = #{"tx_hash" := TXHash}} -> diff --git a/src/gd_gui.erl b/src/gd_gui.erl index 8553694..8d90e36 100644 --- a/src/gd_gui.erl +++ b/src/gd_gui.erl @@ -773,9 +773,8 @@ spend2(#poa{id = ID, name = Name}, Nonce, Height, State = #s{frame = Frame, j = ok = case wxDialog:showModal(Dialog) of ?wxID_OK -> - {ok, PK} = decode_account_id(ID), TX = - #spend_tx{sender_id = gmser_id:create(account, PK), + #spend_tx{sender_id = ID, recipient_id = wxTextCtrl:getValue(ToTx), amount = wxTextCtrl:getValue(AmtTx), gas_price = wxSlider:getValue(GasSl), @@ -783,49 +782,35 @@ spend2(#poa{id = ID, name = Name}, Nonce, Height, State = #s{frame = Frame, j = ttl = Height + wxSlider:getValue(TTL_Sl), nonce = Nonce, payload = wxTextCtrl:getValue(DataTx)}, - clean_spend(ID, TX); + clean_spend(TX); ?wxID_CANCEL -> ok end, ok = wxDialog:destroy(Dialog), State. -clean_spend(_, #spend_tx{recipient_id = ""}) -> +clean_spend(#spend_tx{recipient_id = ""}) -> ok; -clean_spend(ID, TX = #spend_tx{recipient_id = S}) when is_list(S) -> - case decode_account_id(S) of - {ok, PK} -> clean_spend(ID, TX#spend_tx{recipient_id = gmser_id:create(account, PK)}); - Error -> tell("Decode recipient_id failed with: ~tp", [Error]) - end; -clean_spend(ID, TX = #spend_tx{amount = S}) when is_list(S) -> +clean_spend( TX = #spend_tx{amount = S}) when is_list(S) -> case string_to_price(S) of - {ok, Amount} -> clean_spend(ID, TX#spend_tx{amount = Amount}); + {ok, Amount} -> clean_spend(TX#spend_tx{amount = Amount}); {error, _} -> ok end; -clean_spend(ID, TX = #spend_tx{gas_price = S}) when is_list(S) -> +clean_spend(TX = #spend_tx{gas_price = S}) when is_list(S) -> case is_int(S) of - true -> clean_spend(ID, TX#spend_tx{gas_price = list_to_integer(S)}); + true -> clean_spend(TX#spend_tx{gas_price = list_to_integer(S)}); false -> ok end; -clean_spend(ID, TX = #spend_tx{gas = S}) when is_list(S) -> +clean_spend(TX = #spend_tx{gas = S}) when is_list(S) -> case is_int(S) of - true -> clean_spend(ID, TX#spend_tx{gas = list_to_integer(S)}); + true -> clean_spend(TX#spend_tx{gas = list_to_integer(S)}); false -> ok end; -clean_spend(ID, TX = #spend_tx{payload = S}) when is_list(S) -> - clean_spend(ID, TX#spend_tx{payload = list_to_binary(S)}); -clean_spend(ID, TX) -> - gd_con:spend(ID, TX). +clean_spend(TX = #spend_tx{payload = S}) when is_list(S) -> + clean_spend(TX#spend_tx{payload = list_to_binary(S)}); +clean_spend(TX) -> + gd_con:spend(TX). -decode_account_id(S) when is_list(S) -> - decode_account_id(list_to_binary(S)); -decode_account_id(B) -> - try - {account_pubkey, PK} = gmser_api_encoder:decode(B), - {ok, PK} - catch - E:R -> {E, R} - end. is_int(S) -> lists:all(fun(C) -> $0 =< C andalso C =< $9 end, S).