diff --git a/bindings/erlang/src/vanillae.erl b/bindings/erlang/src/vanillae.erl index 5a2a3f0..6703a2f 100644 --- a/bindings/erlang/src/vanillae.erl +++ b/bindings/erlang/src/vanillae.erl @@ -69,7 +69,10 @@ contract_create/8, prepare_contract/1, contract_call/5, - contract_call/10]). + contract_call/6, + contract_call/10, + verify_signature/3]). + % OTP Application Interface %-export([start/0, stop/0]). @@ -78,7 +81,7 @@ %%% Types --export_type([ae_node/0, network_id/0]). +-export_type([ae_node/0, network_id/0, ae_error/0]). -type ae_node() :: {inet:ip_address(), inet:port_number()}. @@ -530,8 +533,14 @@ acc_pending_txs(AccountID) -> %% Retrieve the next nonce for the given account next_nonce(AccountID) -> - case request(["/v2/accounts/", AccountID, "/next-nonce"]) of - {ok, #{"next_nonce" := Nonce}} -> {ok, Nonce}; +% case request(["/v2/accounts/", AccountID, "/next-nonce"]) of +% {ok, #{"next_nonce" := Nonce}} -> {ok, Nonce}; +% {ok, #{"reason" := "Account not found"}} -> {ok, 1}; +% {ok, #{"reason" := Reason}} -> {error, Reason}; +% Error -> Error +% end. + case request(["/v2/accounts/", AccountID]) of + {ok, #{"nonce" := Nonce}} -> {ok, Nonce + 1}; {ok, #{"reason" := "Account not found"}} -> {ok, 1}; {ok, #{"reason" := Reason}} -> {error, Reason}; Error -> Error @@ -753,7 +762,7 @@ result(Received) -> Received. %% @doc %% This function reads the source of a Sophia contract (an .aes file) %% and returns the unsigned create contract call data with default values. -%% For more control over exactly what those values are, use create_contract/9. +%% For more control over exactly what those values are, use create_contract/8. contract_create(CreatorID, Path, InitArgs) -> case next_nonce(CreatorID) of @@ -935,7 +944,9 @@ contract_create4(OwnerID, Nonce, Amount, Gas, GasPrice, Fee, Compiled, CallData) -> Code = aeser_contract_code:serialize(Compiled), - CTVersion = 2, + VM = 7, + ABI = 3, + <> = <>, ContractCreateVersion = 1, TTL = 0, Type = contract_create_tx, @@ -1032,6 +1043,33 @@ contract_call(CallerID, AACI, ConID, Fun, Args) -> AACI, ConID, Fun, Args). +-spec contract_call(CallerID, Gas, AACI, ConID, Fun, Args) -> Result + when CallerID :: unicode:chardata(), + Gas :: pos_integer(), + AACI :: map(), + ConID :: unicode:chardata(), + Fun :: string(), + Args :: [string()], + Result :: {ok, CallTX} | {error, Reason}, + CallTX :: binary(), + Reason :: term(). +%% @doc +%% Just like contract_call/5, but allows you to specify the amount of gas +%% without getting into a major adventure with the other arguments. +%% +%% For details on the meaning of these and other argument values see the doc comment +%% for contract_call/10. + +contract_call(CallerID, Gas, AACI, ConID, Fun, Args) -> + {ok, Nonce} = next_nonce(CallerID), + GasPrice = min_gas_price(), + Fee = min_fee(), + Amount = 0, + contract_call(CallerID, Nonce, + Gas, GasPrice, Fee, Amount, + AACI, ConID, Fun, Args). + + -spec contract_call(CallerID, Nonce, Gas, GasPrice, Fee, Amount, AACI, ConID, Fun, Args) -> Result @@ -1364,6 +1402,43 @@ encode_call_data3(ArgDef, Fun, Args) -> end. +verify_signature(Sig, Message, PubKey) -> + case aeser_api_encoder:decode(PubKey) of + {account_pubkey, PK} -> verify_signature2(Sig, Message, PK); + Other -> {error, {bad_key, Other}} + end. + +verify_signature2(Sig, Message, PK) -> + Prefix = <<"aeternity Signed Message:\n">>, + {ok, PSize} = vencode(byte_size(Prefix)), + {ok, MSize} = vencode(byte_size(Message)), + Smashed = iolist_to_binary([PSize, Prefix, MSize, Message]), + {ok, Hashed} = eblake2:blake2b(32, Smashed), + Signature = <<(binary_to_integer(Sig, 16)):(64 * 8)>>, + Result = enacl:sign_verify_detached(Signature, Hashed, PK), + {ok, Result}. + + +vencode(N) when N < 0 -> + {error, {negative_N, N}}; +vencode(N) when N < 16#FD -> + {ok, <>}; +vencode(N) when N =< 16#FFFF -> + NBytes = eu(N, 2), + {ok, <<16#FD, NBytes/binary>>}; +vencode(N) when N =< 16#FFFF_FFFF -> + NBytes = eu(N, 4), + {ok, <<16#FE, NBytes/binary>>}; +vencode(N) when N < (2 bsl 64) -> + NBytes = eu(N, 8), + {ok, <<16#FF, NBytes/binary>>}. + +eu(N, Size) -> + Bytes = binary:encode_unsigned(N, little), + NExtraZeros = Size - byte_size(Bytes), + ExtraZeros = << <<0>> || _ <- lists:seq(1, NExtraZeros) >>, + <>. + %%% Debug functionality diff --git a/bindings/erlang/src/vanillae_man.erl b/bindings/erlang/src/vanillae_man.erl index a090b35..53a6e68 100644 --- a/bindings/erlang/src/vanillae_man.erl +++ b/bindings/erlang/src/vanillae_man.erl @@ -37,7 +37,7 @@ -record(fetcher, {pid = none :: none | pid(), mon = none :: none | reference(), - time = none :: none | erlang:timestamp(), + time = none :: none | integer(), % nanosecond timestamp node = none :: none | vanilae:ae_node(), from = none :: none | gen_server:from(), req = none :: none | binary()}).