Updates necessary for the nwe poop
This commit is contained in:
parent
3f80b11d63
commit
dbf4f6bdb2
Binary file not shown.
BIN
ebin/hz.beam
BIN
ebin/hz.beam
Binary file not shown.
Binary file not shown.
@ -6,6 +6,10 @@
|
|||||||
%%% @end
|
%%% @end
|
||||||
|
|
||||||
-module(hakuzaru).
|
-module(hakuzaru).
|
||||||
|
-vsn("0.4.1").
|
||||||
|
-author("Craig Everett <ceverett@tsuriai.jp>").
|
||||||
|
-copyright("Craig Everett <ceverett@tsuriai.jp>").
|
||||||
|
-license("GPL-3.0-or-later").
|
||||||
-behavior(application).
|
-behavior(application).
|
||||||
|
|
||||||
|
|
||||||
|
194
src/hz.erl
194
src/hz.erl
@ -4,24 +4,21 @@
|
|||||||
%%% This module is the high-level interface to the Gajumaru blockchain system.
|
%%% This module is the high-level interface to the Gajumaru blockchain system.
|
||||||
%%% The interface is split into three main sections:
|
%%% The interface is split into three main sections:
|
||||||
%%% - Get/Set admin functions
|
%%% - Get/Set admin functions
|
||||||
%%% - AE node JSON query interface functions
|
%%% - Node JSON query interface functions
|
||||||
%%% - AE contract call and serialization interface functions
|
%%% - Contract call and serialization interface functions
|
||||||
%%%
|
%%%
|
||||||
%%% The get/set admin functions are for setting or checking things like the Gajumaru
|
%%% The get/set admin functions are for setting or checking things like the Gajumaru
|
||||||
%%% "network ID" and list of addresses of AE nodes you want to use for answering
|
%%% "network ID" and list of addresses of nodes you want to use for answering
|
||||||
%%% queries to the blockchain (usually you will run these nodes in your own back end).
|
%%% queries to the blockchain.
|
||||||
%%%
|
%%%
|
||||||
%%% The JSON query interface functions are the blockchain query functions themselves
|
%%% The JSON query interface functions are the blockchain query functions themselves
|
||||||
%%% which are translated to network queries and return Erlang messages as responses.
|
%%% which are translated to network queries and return Erlang messages as responses.
|
||||||
%%%
|
%%%
|
||||||
%%% The contract call and serialization interface are the functions used to convert
|
%%% The contract call and serialization interface are the functions used to convert
|
||||||
%%% a desired call to a smart contract on the chain to call data serialized in a form
|
%%% a desired call to a smart contract on the chain to call data serialized in a form
|
||||||
%%% that an Gajumaru compatible wallet, SDK or (in the case of a web service) in-page
|
%%% that a Gajumaru compatible wallet or library can sign and submit to a Gajumaru node.
|
||||||
%%% code based on a JS library such as Sidekick (another component of Hakuzaru) can
|
|
||||||
%%% use to generate signature requests and signed transaction objects for submission
|
|
||||||
%%% to an Gajumaru network node for inclusion in the transaction mempool.
|
|
||||||
%%%
|
%%%
|
||||||
%%% This module also includes the standard OTP "application" interface and start/stop
|
%%% This module does not implement the OTP application behavior.
|
||||||
%%% helper functions.
|
%%% helper functions.
|
||||||
%%% @end
|
%%% @end
|
||||||
|
|
||||||
@ -37,7 +34,7 @@
|
|||||||
tls/0, tls/1,
|
tls/0, tls/1,
|
||||||
timeout/0, timeout/1]).
|
timeout/0, timeout/1]).
|
||||||
|
|
||||||
% AE node JSON query interface functions
|
% Node JSON query interface functions
|
||||||
-export([top_height/0, top_block/0,
|
-export([top_height/0, top_block/0,
|
||||||
kb_current/0, kb_current_hash/0, kb_current_height/0,
|
kb_current/0, kb_current_hash/0, kb_current_height/0,
|
||||||
kb_pending/0,
|
kb_pending/0,
|
||||||
@ -53,18 +50,16 @@
|
|||||||
post_tx/1,
|
post_tx/1,
|
||||||
contract/1, contract_code/1,
|
contract/1, contract_code/1,
|
||||||
contract_poi/1,
|
contract_poi/1,
|
||||||
% oracle/1, oracle_queries/1, oracle_queries_by_id/2,
|
|
||||||
name/1,
|
name/1,
|
||||||
% channel/1,
|
% channel/1,
|
||||||
peer_pubkey/0,
|
peer_pubkey/0,
|
||||||
status/0,
|
status/0,
|
||||||
status_chainends/0]).
|
status_chainends/0]).
|
||||||
|
|
||||||
% AE contract call and serialization interface functions
|
% Contract call and serialization interface functions
|
||||||
-export([read_aci/1,
|
-export([read_aci/1,
|
||||||
min_gas/0,
|
min_gas/0,
|
||||||
min_gas_price/0,
|
min_gas_price/0,
|
||||||
min_fee/0,
|
|
||||||
contract_create/3,
|
contract_create/3,
|
||||||
contract_create/8,
|
contract_create/8,
|
||||||
prepare_contract/1,
|
prepare_contract/1,
|
||||||
@ -154,7 +149,6 @@
|
|||||||
% "call_data" => contract_byte_array(),
|
% "call_data" => contract_byte_array(),
|
||||||
% "code" => contract_byte_array(),
|
% "code" => contract_byte_array(),
|
||||||
% "deposit" => non_neg_integer(),
|
% "deposit" => non_neg_integer(),
|
||||||
% "fee" => pos_integer(),
|
|
||||||
% "gas" => pos_integer(),
|
% "gas" => pos_integer(),
|
||||||
% "gas_price" => pos_integer(),
|
% "gas_price" => pos_integer(),
|
||||||
% "nonce" => pos_integer(),
|
% "nonce" => pos_integer(),
|
||||||
@ -646,7 +640,7 @@ dry_run(TX, Accounts, KBHash) ->
|
|||||||
txs => [#{tx => TXB}],
|
txs => [#{tx => TXB}],
|
||||||
tx_events => true},
|
tx_events => true},
|
||||||
JSON = zj:binary_encode(DryData),
|
JSON = zj:binary_encode(DryData),
|
||||||
request("/v3/dry-run", JSON).
|
request("/v3/dry_run", JSON).
|
||||||
|
|
||||||
-spec decode_bytearray_fate(EncodedStr) -> {ok, Result} | {error, Reason}
|
-spec decode_bytearray_fate(EncodedStr) -> {ok, Result} | {error, Reason}
|
||||||
when EncodedStr :: binary() | string(),
|
when EncodedStr :: binary() | string(),
|
||||||
@ -718,15 +712,17 @@ tx_info(ID) ->
|
|||||||
result(request(["/v3/transactions/", ID, "/info"])).
|
result(request(["/v3/transactions/", ID, "/info"])).
|
||||||
|
|
||||||
-spec post_tx(Data) -> {ok, Result} | {error, Reason}
|
-spec post_tx(Data) -> {ok, Result} | {error, Reason}
|
||||||
when Data :: term(), % FIXME
|
when Data :: string() | binary(),
|
||||||
Result :: term(), % FIXME
|
Result :: term(), % FIXME
|
||||||
Reason :: chain_error() | string().
|
Reason :: chain_error() | string().
|
||||||
%% @doc
|
%% @doc
|
||||||
%% Post a transaction to the chain.
|
%% Post a transaction to the chain.
|
||||||
|
|
||||||
post_tx(Data) ->
|
post_tx(Data) when is_binary(Data) ->
|
||||||
JSON = zj:binary_encode(#{tx => Data}),
|
JSON = zj:binary_encode(#{tx => Data}),
|
||||||
request("/v3/transactions", JSON).
|
request("/v3/transactions", JSON);
|
||||||
|
post_tx(Data) when is_list(Data) ->
|
||||||
|
post_tx(list_to_binary(Data)).
|
||||||
|
|
||||||
|
|
||||||
-spec contract(ID) -> {ok, ContractData} | {error, Reason}
|
-spec contract(ID) -> {ok, ContractData} | {error, Reason}
|
||||||
@ -864,11 +860,12 @@ contract_create(CreatorID, Path, InitArgs) ->
|
|||||||
case next_nonce(CreatorID) of
|
case next_nonce(CreatorID) of
|
||||||
{ok, Nonce} ->
|
{ok, Nonce} ->
|
||||||
Amount = 0,
|
Amount = 0,
|
||||||
Gas = 100000,
|
{ok, Height} = top_height(),
|
||||||
|
TTL = Height + 262980,
|
||||||
|
Gas = 500000,
|
||||||
GasPrice = min_gas_price(),
|
GasPrice = min_gas_price(),
|
||||||
Fee = min_fee(),
|
|
||||||
contract_create(CreatorID, Nonce,
|
contract_create(CreatorID, Nonce,
|
||||||
Amount, Gas, GasPrice, Fee,
|
Amount, TTL, Gas, GasPrice,
|
||||||
Path, InitArgs);
|
Path, InitArgs);
|
||||||
Error ->
|
Error ->
|
||||||
Error
|
Error
|
||||||
@ -876,14 +873,14 @@ contract_create(CreatorID, Path, InitArgs) ->
|
|||||||
|
|
||||||
|
|
||||||
-spec contract_create(CreatorID, Nonce,
|
-spec contract_create(CreatorID, Nonce,
|
||||||
Amount, Gas, GasPrice, Fee,
|
Amount, TTL, Gas, GasPrice,
|
||||||
Path, InitArgs) -> Result
|
Path, InitArgs) -> Result
|
||||||
when CreatorID :: pubkey(),
|
when CreatorID :: pubkey(),
|
||||||
Nonce :: pos_integer(),
|
Nonce :: pos_integer(),
|
||||||
Amount :: non_neg_integer(),
|
Amount :: non_neg_integer(),
|
||||||
|
TTL :: pos_integer(),
|
||||||
Gas :: pos_integer(),
|
Gas :: pos_integer(),
|
||||||
GasPrice :: pos_integer(),
|
GasPrice :: pos_integer(),
|
||||||
Fee :: non_neg_integer(),
|
|
||||||
Path :: file:filename(),
|
Path :: file:filename(),
|
||||||
InitArgs :: [string()],
|
InitArgs :: [string()],
|
||||||
Result :: {ok, CreateTX} | {error, Reason},
|
Result :: {ok, CreateTX} | {error, Reason},
|
||||||
@ -927,6 +924,12 @@ contract_create(CreatorID, Path, InitArgs) ->
|
|||||||
%% of course there are very good reasons why it should be set to a non-zero value
|
%% of course there are very good reasons why it should be set to a non-zero value
|
||||||
%% in the case of calls related to contract-governed payment systems.
|
%% in the case of calls related to contract-governed payment systems.
|
||||||
%% </li>
|
%% </li>
|
||||||
|
%% <b>TTL:</b>
|
||||||
|
%% This stands for "Time-To-Live", meaning the height beyond which this element is
|
||||||
|
%% considered to be eligible for garbage collection (and therefore inaccessible!).
|
||||||
|
%% The TTL can be extended by a "live extension" transaction (basically pay for the
|
||||||
|
%% data to remain alive longer).
|
||||||
|
%% </li>
|
||||||
%% <li>
|
%% <li>
|
||||||
%% <b>Gas:</b>
|
%% <b>Gas:</b>
|
||||||
%% This number sets a limit on the maximum amount of computation the caller is willing
|
%% This number sets a limit on the maximum amount of computation the caller is willing
|
||||||
@ -960,13 +963,6 @@ contract_create(CreatorID, Path, InitArgs) ->
|
|||||||
%% transaction, thus making miners more likely to prioritize the high value ones.
|
%% transaction, thus making miners more likely to prioritize the high value ones.
|
||||||
%% </li>
|
%% </li>
|
||||||
%% <li>
|
%% <li>
|
||||||
%% <b>Fee:</b>
|
|
||||||
%% This value should really be caled `Bribe' or `Tip'.
|
|
||||||
%% This is a flat fee in aettos that is paid into the block reward, thereby allowing
|
|
||||||
%% an additional way to prioritize a given transaction above others, even if the
|
|
||||||
%% transaction will not consume much gas.
|
|
||||||
%% </li>
|
|
||||||
%% <li>
|
|
||||||
%% <b>ACI:</b>
|
%% <b>ACI:</b>
|
||||||
%% This is the compiled contract's metadata. It provides the information necessary
|
%% This is the compiled contract's metadata. It provides the information necessary
|
||||||
%% for the contract call data to be formed in a way that the Gajumaru runtime will
|
%% for the contract call data to be formed in a way that the Gajumaru runtime will
|
||||||
@ -999,77 +995,81 @@ contract_create(CreatorID, Path, InitArgs) ->
|
|||||||
%% if you do not already have a copy, and can check the spec of a function before
|
%% if you do not already have a copy, and can check the spec of a function before
|
||||||
%% trying to form a contract call.
|
%% trying to form a contract call.
|
||||||
|
|
||||||
contract_create(CreatorID, Nonce,
|
contract_create(CreatorID, Nonce, Amount, TTL, Gas, GasPrice, Path, InitArgs) ->
|
||||||
Amount, Gas, GasPrice, Fee,
|
case file:read_file(Path) of
|
||||||
Path, InitArgs) ->
|
{ok, Source} ->
|
||||||
case aeso_compiler:file(Path, [{aci, json}]) of
|
Dir = filename:dirname(Path),
|
||||||
{ok, Compiled} ->
|
{ok, CWD} = file:get_cwd(),
|
||||||
contract_create2(CreatorID, Nonce,
|
SrcDir = aeso_utils:canonical_dir(Path),
|
||||||
Amount, Gas, GasPrice, Fee,
|
Options =
|
||||||
Compiled, InitArgs);
|
[{aci, json},
|
||||||
|
{src_file, Path},
|
||||||
|
{src_dir, SrcDir},
|
||||||
|
{include, {file_system, [CWD, aeso_utils:canonical_dir(Dir)]}}],
|
||||||
|
contract_create2(CreatorID, Nonce, Amount, TTL, Gas, GasPrice,
|
||||||
|
Source, Options, InitArgs);
|
||||||
Error ->
|
Error ->
|
||||||
Error
|
Error
|
||||||
end.
|
end.
|
||||||
|
|
||||||
contract_create2(CreatorID, Nonce,
|
contract_create2(CreatorID, Nonce, Amount, TTL, Gas, GasPrice, Source, Options, InitArgs) ->
|
||||||
Amount, Gas, GasPrice, Fee,
|
case aeso_compiler:from_string(Source, Options) of
|
||||||
Compiled, InitArgs) ->
|
{ok, Compiled} ->
|
||||||
|
contract_create3(CreatorID, Nonce, Amount, TTL, Gas, GasPrice,
|
||||||
|
Source, Compiled, InitArgs);
|
||||||
|
Error ->
|
||||||
|
Error
|
||||||
|
end.
|
||||||
|
|
||||||
|
contract_create3(CreatorID, Nonce, Amount, TTL, Gas, GasPrice, Source, Compiled, InitArgs) ->
|
||||||
AACI = prepare_aaci(maps:get(aci, Compiled)),
|
AACI = prepare_aaci(maps:get(aci, Compiled)),
|
||||||
case encode_call_data(AACI, "init", InitArgs) of
|
case encode_call_data(AACI, "init", InitArgs) of
|
||||||
{ok, CallData} ->
|
{ok, CallData} ->
|
||||||
contract_create3(CreatorID, Nonce,
|
contract_create4(CreatorID, Nonce, Amount, TTL, Gas, GasPrice,
|
||||||
Amount, Gas, GasPrice, Fee,
|
Source, Compiled, CallData);
|
||||||
Compiled, CallData);
|
|
||||||
Error ->
|
Error ->
|
||||||
Error
|
Error
|
||||||
end.
|
end.
|
||||||
|
|
||||||
contract_create3(CreatorID, Nonce,
|
contract_create4(CreatorID, Nonce, Amount, TTL, Gas, GasPrice, Source, Compiled, CallData) ->
|
||||||
Amount, Gas, GasPrice, Fee,
|
|
||||||
Compiled, CallData) ->
|
|
||||||
PK = unicode:characters_to_binary(CreatorID),
|
PK = unicode:characters_to_binary(CreatorID),
|
||||||
try
|
try
|
||||||
{account_pubkey, OwnerID} = aeser_api_encoder:decode(PK),
|
{account_pubkey, OwnerID} = aeser_api_encoder:decode(PK),
|
||||||
contract_create4(OwnerID, Nonce,
|
contract_create5(OwnerID, Nonce, Amount, TTL, Gas, GasPrice, Source, Compiled, CallData)
|
||||||
Amount, Gas, GasPrice, Fee,
|
|
||||||
Compiled, CallData)
|
|
||||||
catch
|
catch
|
||||||
Error:Reason -> {Error, Reason}
|
Error:Reason -> {Error, Reason}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
contract_create4(OwnerID, Nonce,
|
contract_create5(OwnerID, Nonce, Amount, TTL, Gas, GasPrice, Source, Compiled, CallData) ->
|
||||||
Amount, Gas, GasPrice, Fee,
|
|
||||||
Compiled, CallData) ->
|
|
||||||
Code = aeser_contract_code:serialize(Compiled),
|
Code = aeser_contract_code:serialize(Compiled),
|
||||||
VM = 7,
|
VM = 1,
|
||||||
ABI = 3,
|
ABI = 1,
|
||||||
<<CTVersion:32>> = <<VM:16, ABI:16>>,
|
<<CTVersion:32>> = <<VM:16, ABI:16>>,
|
||||||
ContractCreateVersion = 1,
|
ContractCreateVersion = 1,
|
||||||
TTL = 0,
|
|
||||||
Type = contract_create_tx,
|
Type = contract_create_tx,
|
||||||
Fields =
|
Fields =
|
||||||
[{owner_id, aeser_id:create(account, OwnerID)},
|
[{owner_id, aeser_id:create(account, OwnerID)},
|
||||||
{nonce, Nonce},
|
{nonce, Nonce},
|
||||||
{code, Code},
|
{code, Code},
|
||||||
|
{source, Source},
|
||||||
{ct_version, CTVersion},
|
{ct_version, CTVersion},
|
||||||
{fee, Fee},
|
|
||||||
{ttl, TTL},
|
{ttl, TTL},
|
||||||
{deposit, 0},
|
{deposit, 0},
|
||||||
{amount, Amount},
|
{amount, Amount},
|
||||||
{gas, Gas},
|
|
||||||
{gas_price, GasPrice},
|
{gas_price, GasPrice},
|
||||||
|
{gas, Gas},
|
||||||
{call_data, CallData}],
|
{call_data, CallData}],
|
||||||
Template =
|
Template =
|
||||||
[{owner_id, id},
|
[{owner_id, id},
|
||||||
{nonce, int},
|
{nonce, int},
|
||||||
{code, binary},
|
{code, binary},
|
||||||
|
{source, binary},
|
||||||
{ct_version, int},
|
{ct_version, int},
|
||||||
{fee, int},
|
|
||||||
{ttl, int},
|
{ttl, int},
|
||||||
{deposit, int},
|
{deposit, int},
|
||||||
{amount, int},
|
{amount, int},
|
||||||
{gas, int},
|
|
||||||
{gas_price, int},
|
{gas_price, int},
|
||||||
|
{gas, int},
|
||||||
{call_data, binary}],
|
{call_data, binary}],
|
||||||
TXB = aeser_chain_objects:serialize(Type, ContractCreateVersion, Template, Fields),
|
TXB = aeser_chain_objects:serialize(Type, ContractCreateVersion, Template, Fields),
|
||||||
try
|
try
|
||||||
@ -1121,9 +1121,9 @@ read_aci(Path) ->
|
|||||||
CallTX :: binary(),
|
CallTX :: binary(),
|
||||||
Reason :: term().
|
Reason :: term().
|
||||||
%% @doc
|
%% @doc
|
||||||
%% Form a contract call using hardcoded default values for `Gas', `GasPrice', `Fee',
|
%% Form a contract call using hardcoded default values for `Gas', `GasPrice',
|
||||||
%% and `Amount' to simplify the call (10 args is a bit much for normal calls!).
|
%% and `Amount' to simplify the call (10 args is a bit much for normal calls!).
|
||||||
%% The values used are 20k for `Gas' and `Fee', the `GasPrice' is fixed at 1b (the
|
%% The values used are 20k for `Gas', the `GasPrice' is fixed at 1b (the
|
||||||
%% default "miner minimum" defined in default configs), and the `Amount' is 0.
|
%% default "miner minimum" defined in default configs), and the `Amount' is 0.
|
||||||
%%
|
%%
|
||||||
%% For details on the meaning of these and other argument values see the doc comment
|
%% For details on the meaning of these and other argument values see the doc comment
|
||||||
@ -1134,10 +1134,11 @@ contract_call(CallerID, AACI, ConID, Fun, Args) ->
|
|||||||
{ok, Nonce} ->
|
{ok, Nonce} ->
|
||||||
Gas = min_gas(),
|
Gas = min_gas(),
|
||||||
GasPrice = min_gas_price(),
|
GasPrice = min_gas_price(),
|
||||||
Fee = min_fee(),
|
|
||||||
Amount = 0,
|
Amount = 0,
|
||||||
|
{ok, Height} = top_height(),
|
||||||
|
TTL = Height + 262980,
|
||||||
contract_call(CallerID, Nonce,
|
contract_call(CallerID, Nonce,
|
||||||
Gas, GasPrice, Fee, Amount,
|
Gas, GasPrice, Amount, TTL,
|
||||||
AACI, ConID, Fun, Args);
|
AACI, ConID, Fun, Args);
|
||||||
Error ->
|
Error ->
|
||||||
Error
|
Error
|
||||||
@ -1165,10 +1166,11 @@ contract_call(CallerID, Gas, AACI, ConID, Fun, Args) ->
|
|||||||
case next_nonce(CallerID) of
|
case next_nonce(CallerID) of
|
||||||
{ok, Nonce} ->
|
{ok, Nonce} ->
|
||||||
GasPrice = min_gas_price(),
|
GasPrice = min_gas_price(),
|
||||||
Fee = min_fee(),
|
|
||||||
Amount = 0,
|
Amount = 0,
|
||||||
|
{ok, Height} = top_height(),
|
||||||
|
TTL = Height + 262980,
|
||||||
contract_call(CallerID, Nonce,
|
contract_call(CallerID, Nonce,
|
||||||
Gas, GasPrice, Fee, Amount,
|
Gas, GasPrice, Amount, TTL,
|
||||||
AACI, ConID, Fun, Args);
|
AACI, ConID, Fun, Args);
|
||||||
Error ->
|
Error ->
|
||||||
Error
|
Error
|
||||||
@ -1176,14 +1178,14 @@ contract_call(CallerID, Gas, AACI, ConID, Fun, Args) ->
|
|||||||
|
|
||||||
|
|
||||||
-spec contract_call(CallerID, Nonce,
|
-spec contract_call(CallerID, Nonce,
|
||||||
Gas, GasPrice, Fee, Amount,
|
Gas, GasPrice, Amount, TTL,
|
||||||
AACI, ConID, Fun, Args) -> Result
|
AACI, ConID, Fun, Args) -> Result
|
||||||
when CallerID :: unicode:chardata(),
|
when CallerID :: unicode:chardata(),
|
||||||
Nonce :: pos_integer(),
|
Nonce :: pos_integer(),
|
||||||
Gas :: pos_integer(),
|
Gas :: pos_integer(),
|
||||||
GasPrice :: pos_integer(),
|
GasPrice :: pos_integer(),
|
||||||
Fee :: non_neg_integer(),
|
|
||||||
Amount :: non_neg_integer(),
|
Amount :: non_neg_integer(),
|
||||||
|
TTL :: pos_integer(),
|
||||||
AACI :: map(),
|
AACI :: map(),
|
||||||
ConID :: unicode:chardata(),
|
ConID :: unicode:chardata(),
|
||||||
Fun :: string(),
|
Fun :: string(),
|
||||||
@ -1250,13 +1252,6 @@ contract_call(CallerID, Gas, AACI, ConID, Fun, Args) ->
|
|||||||
%% transaction, thus making miners more likely to prioritize the high value ones.
|
%% transaction, thus making miners more likely to prioritize the high value ones.
|
||||||
%% </li>
|
%% </li>
|
||||||
%% <li>
|
%% <li>
|
||||||
%% <b>Fee:</b>
|
|
||||||
%% This value should really be caled `Bribe' or `Tip'.
|
|
||||||
%% This is a flat fee in aettos that is paid into the block reward, thereby allowing
|
|
||||||
%% an additional way to prioritize a given transaction above others, even if the
|
|
||||||
%% transaction will not consume much gas.
|
|
||||||
%% </li>
|
|
||||||
%% <li>
|
|
||||||
%% <b>Amount:</b>
|
%% <b>Amount:</b>
|
||||||
%% All Gajumaru transactions can carry an "amount" spent from the origin account
|
%% All Gajumaru transactions can carry an "amount" spent from the origin account
|
||||||
%% (in this case the `CallerID') to the destination. In a "Spend" transaction this
|
%% (in this case the `CallerID') to the destination. In a "Spend" transaction this
|
||||||
@ -1300,33 +1295,32 @@ contract_call(CallerID, Gas, AACI, ConID, Fun, Args) ->
|
|||||||
%% if you do not already have a copy, and can check the spec of a function before
|
%% if you do not already have a copy, and can check the spec of a function before
|
||||||
%% trying to form a contract call.
|
%% trying to form a contract call.
|
||||||
|
|
||||||
contract_call(CallerID, Nonce, Gas, GP, Fee, Amount, AACI, ConID, Fun, Args) ->
|
contract_call(CallerID, Nonce, Gas, GP, Amount, TTL, AACI, ConID, Fun, Args) ->
|
||||||
case encode_call_data(AACI, Fun, Args) of
|
case encode_call_data(AACI, Fun, Args) of
|
||||||
{ok, CD} -> contract_call2(CallerID, Nonce, Gas, GP, Fee, Amount, ConID, CD);
|
{ok, CD} -> contract_call2(CallerID, Nonce, Gas, GP, Amount, TTL, ConID, CD);
|
||||||
Error -> Error
|
Error -> Error
|
||||||
end.
|
end.
|
||||||
|
|
||||||
contract_call2(CallerID, Nonce, Gas, GasPrice, Fee, Amount, ConID, CallData) ->
|
contract_call2(CallerID, Nonce, Gas, GasPrice, Amount, TTL, ConID, CallData) ->
|
||||||
CallerBin = unicode:characters_to_binary(CallerID),
|
CallerBin = unicode:characters_to_binary(CallerID),
|
||||||
try
|
try
|
||||||
{account_pubkey, PK} = aeser_api_encoder:decode(CallerBin),
|
{account_pubkey, PK} = aeser_api_encoder:decode(CallerBin),
|
||||||
contract_call3(PK, Nonce, Gas, GasPrice, Fee, Amount, ConID, CallData)
|
contract_call3(PK, Nonce, Gas, GasPrice, Amount, TTL, ConID, CallData)
|
||||||
catch
|
catch
|
||||||
Error:Reason -> {Error, Reason}
|
Error:Reason -> {Error, Reason}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
contract_call3(PK, Nonce, Gas, GasPrice, Fee, Amount, ConID, CallData) ->
|
contract_call3(PK, Nonce, Gas, GasPrice, Amount, TTL, ConID, CallData) ->
|
||||||
ConBin = unicode:characters_to_binary(ConID),
|
ConBin = unicode:characters_to_binary(ConID),
|
||||||
try
|
try
|
||||||
{contract_pubkey, CK} = aeser_api_encoder:decode(ConBin),
|
{contract_pubkey, CK} = aeser_api_encoder:decode(ConBin),
|
||||||
contract_call4(PK, Nonce, Gas, GasPrice, Fee, Amount, CK, CallData)
|
contract_call4(PK, Nonce, Gas, GasPrice, Amount, TTL, CK, CallData)
|
||||||
catch
|
catch
|
||||||
Error:Reason -> {Error, Reason}
|
Error:Reason -> {Error, Reason}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
contract_call4(PK, Nonce, Gas, GasPrice, Fee, Amount, CK, CallData) ->
|
contract_call4(PK, Nonce, Gas, GasPrice, Amount, TTL, CK, CallData) ->
|
||||||
ABI = 3,
|
ABI = 1,
|
||||||
TTL = 0,
|
|
||||||
CallVersion = 1,
|
CallVersion = 1,
|
||||||
Type = contract_call_tx,
|
Type = contract_call_tx,
|
||||||
Fields =
|
Fields =
|
||||||
@ -1334,22 +1328,20 @@ contract_call4(PK, Nonce, Gas, GasPrice, Fee, Amount, CK, CallData) ->
|
|||||||
{nonce, Nonce},
|
{nonce, Nonce},
|
||||||
{contract_id, aeser_id:create(contract, CK)},
|
{contract_id, aeser_id:create(contract, CK)},
|
||||||
{abi_version, ABI},
|
{abi_version, ABI},
|
||||||
{fee, Fee},
|
|
||||||
{ttl, TTL},
|
{ttl, TTL},
|
||||||
{amount, Amount},
|
{amount, Amount},
|
||||||
{gas, Gas},
|
|
||||||
{gas_price, GasPrice},
|
{gas_price, GasPrice},
|
||||||
|
{gas, Gas},
|
||||||
{call_data, CallData}],
|
{call_data, CallData}],
|
||||||
Template =
|
Template =
|
||||||
[{caller_id, id},
|
[{caller_id, id},
|
||||||
{nonce, int},
|
{nonce, int},
|
||||||
{contract_id, id},
|
{contract_id, id},
|
||||||
{abi_version, int},
|
{abi_version, int},
|
||||||
{fee, int},
|
|
||||||
{ttl, int},
|
{ttl, int},
|
||||||
{amount, int},
|
{amount, int},
|
||||||
{gas, int},
|
|
||||||
{gas_price, int},
|
{gas_price, int},
|
||||||
|
{gas, int},
|
||||||
{call_data, binary}],
|
{call_data, binary}],
|
||||||
TXB = aeser_chain_objects:serialize(Type, CallVersion, Template, Fields),
|
TXB = aeser_chain_objects:serialize(Type, CallVersion, Template, Fields),
|
||||||
try
|
try
|
||||||
@ -1988,7 +1980,7 @@ aaci_lookup_spec({aaci, _, FunDefs, _}, Fun) ->
|
|||||||
%% contention becomes an issue.
|
%% contention becomes an issue.
|
||||||
|
|
||||||
min_gas_price() ->
|
min_gas_price() ->
|
||||||
1000000000.
|
1_000_000_000.
|
||||||
|
|
||||||
|
|
||||||
-spec min_gas() -> integer().
|
-spec min_gas() -> integer().
|
||||||
@ -2005,19 +1997,6 @@ min_gas() ->
|
|||||||
20000.
|
20000.
|
||||||
|
|
||||||
|
|
||||||
-spec min_fee() -> integer().
|
|
||||||
%% @doc
|
|
||||||
%% This function always returns 200,000,000,000,000 in the current version.
|
|
||||||
%%
|
|
||||||
%% This is the minimum fee amount currently accepted -- it is up to callers whether
|
|
||||||
%% they want to customize this value higher (or possibly lower, though as things stand
|
|
||||||
%% that would only work on an independent AE-based network, not the actual Gajumaru
|
|
||||||
%% mainnet or testnet).
|
|
||||||
|
|
||||||
min_fee() ->
|
|
||||||
200000000000000.
|
|
||||||
|
|
||||||
|
|
||||||
encode_call_data({aaci, _ContractName, FunDefs, _TypeDefs}, Fun, Args) ->
|
encode_call_data({aaci, _ContractName, FunDefs, _TypeDefs}, Fun, Args) ->
|
||||||
case maps:find(Fun, FunDefs) of
|
case maps:find(Fun, FunDefs) of
|
||||||
{ok, {ArgDef, _ResultDef}} -> encode_call_data2(ArgDef, Fun, Args);
|
{ok, {ArgDef, _ResultDef}} -> encode_call_data2(ArgDef, Fun, Args);
|
||||||
@ -2052,10 +2031,9 @@ verify_signature(Sig, Message, PubKey) ->
|
|||||||
end.
|
end.
|
||||||
|
|
||||||
verify_signature2(Sig, Message, PK) ->
|
verify_signature2(Sig, Message, PK) ->
|
||||||
% Superhero salts/hashes the message before signing it, in order to protect
|
% Gajumaru signatures require messages to be salted and hashed, then
|
||||||
|
% the hash is what gets signed in order to protect
|
||||||
% the user from accidentally signing a transaction disguised as a message.
|
% the user from accidentally signing a transaction disguised as a message.
|
||||||
% In order to verify the signature, we have to duplicate superhero's
|
|
||||||
% salt/hash procedure here.
|
|
||||||
%
|
%
|
||||||
% Salt the message then hash with blake2b. See:
|
% Salt the message then hash with blake2b. See:
|
||||||
% 1. Erlang Blake2 blake2b/2 function:
|
% 1. Erlang Blake2 blake2b/2 function:
|
||||||
@ -2064,13 +2042,13 @@ verify_signature2(Sig, Message, PK) ->
|
|||||||
% https://gitlab.com/ioecs/aepp-sdk-js/blob/370f1e30064ad0239ba59931908d9aba0a2e86b6/src/utils/crypto.ts#L171-L175
|
% https://gitlab.com/ioecs/aepp-sdk-js/blob/370f1e30064ad0239ba59931908d9aba0a2e86b6/src/utils/crypto.ts#L171-L175
|
||||||
% 3. SDK hashing:
|
% 3. SDK hashing:
|
||||||
% https://gitlab.com/ioecs/aepp-sdk-js/blob/370f1e30064ad0239ba59931908d9aba0a2e86b6/src/utils/crypto.ts#L83-L85
|
% https://gitlab.com/ioecs/aepp-sdk-js/blob/370f1e30064ad0239ba59931908d9aba0a2e86b6/src/utils/crypto.ts#L83-L85
|
||||||
Prefix = <<"aeternity Signed Message:\n">>,
|
Prefix = <<"Gajumaru Signed Message:\n">>,
|
||||||
% Prefix = <<"gajumaru Signed Message:\n">>, % TODO: Switch the prefix after we kill Superhero
|
|
||||||
{ok, PSize} = vencode(byte_size(Prefix)),
|
{ok, PSize} = vencode(byte_size(Prefix)),
|
||||||
{ok, MSize} = vencode(byte_size(Message)),
|
{ok, MSize} = vencode(byte_size(Message)),
|
||||||
Smashed = iolist_to_binary([PSize, Prefix, MSize, Message]),
|
Smashed = iolist_to_binary([PSize, Prefix, MSize, Message]),
|
||||||
{ok, Hashed} = eblake2:blake2b(32, Smashed),
|
{ok, Hashed} = eblake2:blake2b(32, Smashed),
|
||||||
Signature = <<(binary_to_integer(Sig, 16)):(64 * 8)>>,
|
% Signature = <<(binary_to_integer(Sig, 16)):(64 * 8)>>,
|
||||||
|
Signature = base64:decode(Sig),
|
||||||
Result = ecu_eddsa:sign_verify_detached(Signature, Hashed, PK),
|
Result = ecu_eddsa:sign_verify_detached(Signature, Hashed, PK),
|
||||||
{ok, Result}.
|
{ok, Result}.
|
||||||
|
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
%%% @private
|
|
||||||
|
|
||||||
-module(hz_fetcher).
|
-module(hz_fetcher).
|
||||||
-vsn("0.4.1").
|
-vsn("0.4.1").
|
||||||
-author("Craig Everett <ceverett@tsuriai.jp>").
|
-author("Craig Everett <ceverett@tsuriai.jp>").
|
||||||
|
Loading…
x
Reference in New Issue
Block a user