From 7b0e6a99889945a6001ebf8b8dcc9c3d98e8b875 Mon Sep 17 00:00:00 2001 From: Craig Everett Date: Wed, 9 Nov 2022 16:42:25 +0900 Subject: [PATCH] Adding contract_create, along with some minor fixes and additions --- bindings/erlang/src/vanillae.erl | 367 +++++++++++++++++++++++++++---- 1 file changed, 322 insertions(+), 45 deletions(-) diff --git a/bindings/erlang/src/vanillae.erl b/bindings/erlang/src/vanillae.erl index 4c5612c..2ed9c4f 100644 --- a/bindings/erlang/src/vanillae.erl +++ b/bindings/erlang/src/vanillae.erl @@ -40,28 +40,31 @@ % AE node JSON query interface functions -export([top_height/0, top_block/0, kb_current/0, kb_current_hash/0, kb_current_height/0, -% kb_pending/0, + kb_pending/0, kb_by_hash/1, kb_by_height/1, % kb_insert/1, mb_header/1, mb_txs/1, mb_tx_index/2, mb_tx_count/1, gen_current/0, gen_by_id/1, gen_by_height/1, acc/1, acc_at_height/2, acc_at_block_id/2, -% acc_pending_txs/1, + acc_pending_txs/1, next_nonce/1, dry_run/1, dry_run/2, dry_run/3, tx/1, tx_info/1, post_tx/1, contract/1, contract_code/1, -% contract_poi/1, + contract_poi/1, % oracle/1, oracle_queries/1, oracle_queries_by_id/2, name/1, % channel/1, peer_pubkey/0, - status/0]). -% status_chainends/0]). + status/0, + status_chainends/0]). % AE contract call and serialization interface functions -export([read_aci/1, + min_gas/0, + min_gas_price/0, + min_fee/0, prepare_contract/1, contract_call/5, contract_call/10]). @@ -134,7 +137,20 @@ % "block_height" => pos_integer(), % "hash" => tx_hash(), % "signatures" => [signature()], -% "tx" => map()}. % FIXME +% "tx" => +% #{"abi_version" => pos_integer(), +% "amount" => non_neg_integer(), +% "call_data" => contract_byte_array(), +% "code" => contract_byte_array(), +% "deposit" => non_neg_integer(), +% "fee" => pos_integer(), +% "gas" => pos_integer(), +% "gas_price" => pos_integer(), +% "nonce" => pos_integer(), +% "owner_id" => account_id(), +% "type" => string(), +% "version" => pos_integer(), +% "vm_version" => pos_integer()}} -type generation() :: #{string() => term()}. % #{"key_block" => keyblock(), % "micro_blocks" => [microblock_hash()]}. @@ -321,10 +337,15 @@ kb_current_height() -> end. -%-spec kb_pending() -> -% -%kb_pending() -> -% request("/v2/key-blocks/pending"). +-spec kb_pending() -> {ok, keyblock_hash()} | {error, Reason} + when Reason :: string(). +%% @doc +%% Request the hash of the pending keyblock of a mining node's beneficiary. +%% If the node queried is not configured for mining it will return +%% `{error, "Beneficiary not configured"}' + +kb_pending() -> + result(request("/v2/key-blocks/pending")). -spec kb_by_hash(ID) -> {ok, KeyBlock} | {error, Reason} @@ -488,16 +509,15 @@ acc_at_block_id(AccountID, BlockID) -> end. -% TODO -%-spec acc_pending_txs(AccountID) -> {ok, TXs} | {error, Reason} -% when AccountID :: account_id(), -% TXs :: -% Reason :: -%%% @doc -%%% Retrieve a list of transactions pending for the given account. -% -%acc_pending_txs(AccountID) -> -% request(["/v2/accounts/", AccountID, "/transactions/pending"]). +-spec acc_pending_txs(AccountID) -> {ok, TXs} | {error, Reason} + when AccountID :: account_id(), + TXs :: [tx_hash()], + Reason :: ae_error() | string(). +%% @doc +%% Retrieve a list of transactions pending for the given account. + +acc_pending_txs(AccountID) -> + request(["/v2/accounts/", AccountID, "/transactions/pending"]). -spec next_nonce(AccountID) -> {ok, Nonce} | {error, Reason} @@ -630,11 +650,13 @@ contract_code(ID) -> end. -% FIXME: Is this broken? Seems to just stall -% -spec conract_poi(ID) -> -% -%contract_poi(ID) -> -% request(["/v2/contracts/", ID, "/poi"]). +-spec contract_poi(ID) -> {ok, Bytecode} | {error, Reason} + when ID :: contract_id(), + Bytecode :: contract_byte_array(), + Reason :: ae_error() | string(). + +contract_poi(ID) -> + request(["/v2/contracts/", ID, "/poi"]). % TODO %oracle(ID) -> @@ -694,24 +716,23 @@ status() -> request("/v2/status"). -% TODO -%-spec status_chainends() -> {ok, ChainEnds} | {error, Reason} -% when ChainEnds :: [keyblock_hash()], -% Reason :: ae_error(). -%%% @doc -%%% Retrieve the latest keyblock hashes -% -%status_chainends() -> -% request("/v2/status/chain-ends"). +-spec status_chainends() -> {ok, ChainEnds} | {error, Reason} + when ChainEnds :: [keyblock_hash()], + Reason :: ae_error(). +%% @doc +%% Retrieve the latest keyblock hashes + +status_chainends() -> + request("/v2/status/chain-ends"). request(Path) -> - vanillae_man:request(Path). + vanillae_man:request(unicode:characters_to_list(Path)). request(Path, Payload) -> - vanillae_man:request(Path, Payload). - + vanillae_man:request(unicode:characters_to_list(Path), Payload). + result({ok, #{"reason" := Reason}}) -> {error, Reason}; result(Received) -> Received. @@ -720,6 +741,235 @@ result(Received) -> Received. %%% Contract calls +-spec contract_create(CreatorID, Path, InitArgs) -> Result + when CreatorID :: binary(), + Path :: file:filename(), + InitArgs :: [string()], + Result :: {ok, CallTX} | {error, Reason}, + CreateTX :: binary(), + Reason :: file:posix() | term(). +%% @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. + +contract_create(CreatorID, Path, InitArgs) -> + case next_nonce(CreatorID) of + {ok, Nonce} -> + Deposit = 0, + Amount = 0, + Gas = 100000, + GasPrice = min_gas_price(), + Fee = fee(), + contract_create(CreatorID, Nonce, + Deposit, Amount, + Gas, GasPrice, Fee, + Path, InitArgs); + Error -> + Error + end. + + +-spec create_contract(CreatorID, Nonce, + Deposit, Amount, + Gas, GasPrice, Fee, + Path, InitArgs) -> Result + when CreatorID :: binary(), + Nonce :: pos_integer(), + Deposit :: non_neg_integer(), + Amount :: non_neg_integer(), + Gas :: pos_integer(), + GasPrice :: pos_integer(), + Fee :: non_neg_integer(), + Path :: file:filename(), + InitArgs :: [string()], + Result :: {ok, CreateTX} | {error, Reason}, + CreateTX :: binary(), + Reason :: term(). +%% @doc +%% Create a "create contract" call using the supplied values. +%% +%% Contract creation is an even more opaque process than contract calls if you're new +%% to Aeternity. +%% +%% The meaning of each argument is as follows: +%%