|
|
|
@ -23,7 +23,7 @@
|
|
|
|
|
%%% @end
|
|
|
|
|
|
|
|
|
|
-module(hz).
|
|
|
|
|
-vsn("0.3.0").
|
|
|
|
|
-vsn("0.2.0").
|
|
|
|
|
-author("Craig Everett <ceverett@tsuriai.jp>").
|
|
|
|
|
-copyright("Craig Everett <ceverett@tsuriai.jp>").
|
|
|
|
|
-license("GPL-3.0-or-later").
|
|
|
|
@ -48,7 +48,7 @@
|
|
|
|
|
dry_run/1, dry_run/2, dry_run/3, dry_run_map/1,
|
|
|
|
|
tx/1, tx_info/1,
|
|
|
|
|
post_tx/1,
|
|
|
|
|
contract/1, contract_code/1, contract_source/1,
|
|
|
|
|
contract/1, contract_code/1,
|
|
|
|
|
contract_poi/1,
|
|
|
|
|
name/1,
|
|
|
|
|
% channel/1,
|
|
|
|
@ -64,7 +64,6 @@
|
|
|
|
|
contract_create_built/3,
|
|
|
|
|
contract_create/8,
|
|
|
|
|
prepare_contract/1,
|
|
|
|
|
prepare_aaci/1,
|
|
|
|
|
aaci_lookup_spec/2,
|
|
|
|
|
contract_call/5,
|
|
|
|
|
contract_call/6,
|
|
|
|
@ -218,7 +217,7 @@
|
|
|
|
|
-spec network_id() -> NetworkID
|
|
|
|
|
when NetworkID :: string() | none.
|
|
|
|
|
%% @doc
|
|
|
|
|
%% Returns the network ID or the atom `none' if it is unset.
|
|
|
|
|
%% Returns the AE network ID or the atom `none' if it is unset.
|
|
|
|
|
%% Checking this is not normally necessary, but if network ID assignment is dynamic
|
|
|
|
|
%% in your system it may be necessary to call this before attempting to form
|
|
|
|
|
%% call data or perform other actions on chain that require a signature.
|
|
|
|
@ -251,8 +250,8 @@ chain_nodes() ->
|
|
|
|
|
when List :: [chain_node()],
|
|
|
|
|
Reason :: {invalid, [term()]}.
|
|
|
|
|
%% @doc
|
|
|
|
|
%% Sets the nodes that are intended to be used as your interface to the peer
|
|
|
|
|
%% network. The common situation is that your project runs a non-mining node as
|
|
|
|
|
%% Sets the AE nodes that are intended to be used as your interface to the AE peer
|
|
|
|
|
%% network. The common situation is that your project runs a non-mining AE node as
|
|
|
|
|
%% part of your backend infrastructure. Typically one or two nodes is plenty, but
|
|
|
|
|
%% this may need to expand depending on how much query load your application generates.
|
|
|
|
|
%% The Hakuzaru manager will load balance by round-robin distribution.
|
|
|
|
@ -306,7 +305,7 @@ timeout(MS) ->
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
%%% JSON query interface functions
|
|
|
|
|
%%% AE node JSON query interface functions
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-spec top_height() -> {ok, Height} | {error, Reason}
|
|
|
|
@ -658,13 +657,13 @@ dry_run_map(Map) ->
|
|
|
|
|
|
|
|
|
|
%% @doc
|
|
|
|
|
%% Decode the "cb_XXXX" string that came out of a tx_info or dry_run, to
|
|
|
|
|
%% the Erlang representation of FATE objects used by gmb_fate_encoding. See
|
|
|
|
|
%% the Erlang representation of FATE objects used by aeb_fate_encoding. See
|
|
|
|
|
%% decode_bytearray/2 for an alternative that provides simpler outputs based on
|
|
|
|
|
%% information provided by an AACI.
|
|
|
|
|
|
|
|
|
|
decode_bytearray_fate(EncodedStr) ->
|
|
|
|
|
Encoded = unicode:characters_to_binary(EncodedStr),
|
|
|
|
|
{contract_bytearray, Binary} = gmser_api_encoder:decode(Encoded),
|
|
|
|
|
{contract_bytearray, Binary} = aeser_api_encoder:decode(Encoded),
|
|
|
|
|
case Binary of
|
|
|
|
|
<<>> -> {ok, none};
|
|
|
|
|
<<"Out of gas">> -> {error, out_of_gas};
|
|
|
|
@ -672,7 +671,7 @@ decode_bytearray_fate(EncodedStr) ->
|
|
|
|
|
% FIXME there may be other errors that are encoded directly into
|
|
|
|
|
% the byte array. We could try and catch to at least return
|
|
|
|
|
% *something* for cases that we don't already detect.
|
|
|
|
|
Object = gmb_fate_encoding:deserialize(Binary),
|
|
|
|
|
Object = aeb_fate_encoding:deserialize(Binary),
|
|
|
|
|
{ok, Object}
|
|
|
|
|
end.
|
|
|
|
|
|
|
|
|
@ -760,21 +759,6 @@ contract_code(ID) ->
|
|
|
|
|
end.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-spec contract_source(ID) -> {ok, Bytecode} | {error, Reason}
|
|
|
|
|
when ID :: contract_id(),
|
|
|
|
|
Bytecode :: contract_byte_array(),
|
|
|
|
|
Reason :: chain_error() | string().
|
|
|
|
|
%% @doc
|
|
|
|
|
%% Retrieve the code of a contract as represented on chain.
|
|
|
|
|
|
|
|
|
|
contract_source(ID) ->
|
|
|
|
|
case request(["/v3/contracts/", ID, "/source"]) of
|
|
|
|
|
{ok, #{"source" := Source}} -> {ok, Source};
|
|
|
|
|
{ok, #{"reason" := Reason}} -> {error, Reason};
|
|
|
|
|
Error -> Error
|
|
|
|
|
end.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-spec contract_poi(ID) -> {ok, Bytecode} | {error, Reason}
|
|
|
|
|
when ID :: contract_id(),
|
|
|
|
|
Bytecode :: contract_byte_array(),
|
|
|
|
@ -969,7 +953,7 @@ contract_create(CreatorID, Path, InitArgs) ->
|
|
|
|
|
%% </li>
|
|
|
|
|
%% <li>
|
|
|
|
|
%% <b>GasPrice:</b>
|
|
|
|
|
%% This is a factor that is used calculate a value in pucks (the smallest unit of
|
|
|
|
|
%% This is a factor that is used calculate a value in aettos (the smallest unit of
|
|
|
|
|
%% Gajumaru's currency value) for the gas consumed. In times of high contention
|
|
|
|
|
%% in the mempool increasing the gas price increases the value of mining a given
|
|
|
|
|
%% transaction, thus making miners more likely to prioritize the high value ones.
|
|
|
|
@ -1012,12 +996,12 @@ contract_create(CreatorID, Nonce, Amount, TTL, Gas, GasPrice, Path, InitArgs) ->
|
|
|
|
|
{ok, Source} ->
|
|
|
|
|
Dir = filename:dirname(Path),
|
|
|
|
|
{ok, CWD} = file:get_cwd(),
|
|
|
|
|
SrcDir = so_utils:canonical_dir(Path),
|
|
|
|
|
SrcDir = aeso_utils:canonical_dir(Path),
|
|
|
|
|
Options =
|
|
|
|
|
[{aci, json},
|
|
|
|
|
{src_file, Path},
|
|
|
|
|
{src_dir, SrcDir},
|
|
|
|
|
{include, {file_system, [CWD, so_utils:canonical_dir(Dir)]}}],
|
|
|
|
|
{include, {file_system, [CWD, aeso_utils:canonical_dir(Dir)]}}],
|
|
|
|
|
contract_create2(CreatorID, Nonce, Amount, TTL, Gas, GasPrice,
|
|
|
|
|
Source, Options, InitArgs);
|
|
|
|
|
Error ->
|
|
|
|
@ -1054,7 +1038,7 @@ contract_create_built(CreatorID, Compiled, InitArgs) ->
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
contract_create2(CreatorID, Nonce, Amount, TTL, Gas, GasPrice, Source, Options, InitArgs) ->
|
|
|
|
|
case so_compiler:from_string(Source, Options) of
|
|
|
|
|
case aeso_compiler:from_string(Source, Options) of
|
|
|
|
|
{ok, Compiled} ->
|
|
|
|
|
contract_create3(CreatorID, Nonce, Amount, TTL, Gas, GasPrice,
|
|
|
|
|
Compiled, InitArgs);
|
|
|
|
@ -1075,22 +1059,22 @@ contract_create3(CreatorID, Nonce, Amount, TTL, Gas, GasPrice, Compiled, InitArg
|
|
|
|
|
contract_create4(CreatorID, Nonce, Amount, TTL, Gas, GasPrice, Compiled, CallData) ->
|
|
|
|
|
PK = unicode:characters_to_binary(CreatorID),
|
|
|
|
|
try
|
|
|
|
|
{account_pubkey, OwnerID} = gmser_api_encoder:decode(PK),
|
|
|
|
|
{account_pubkey, OwnerID} = aeser_api_encoder:decode(PK),
|
|
|
|
|
contract_create5(OwnerID, Nonce, Amount, TTL, Gas, GasPrice, Compiled, CallData)
|
|
|
|
|
catch
|
|
|
|
|
Error:Reason -> {Error, Reason}
|
|
|
|
|
end.
|
|
|
|
|
|
|
|
|
|
contract_create5(OwnerID, Nonce, Amount, TTL, Gas, GasPrice, Compiled, CallData) ->
|
|
|
|
|
Code = gmser_contract_code:serialize(Compiled),
|
|
|
|
|
Source = unicode:characters_to_binary(maps:get(contract_source, Compiled, <<>>)),
|
|
|
|
|
Code = aeser_contract_code:serialize(Compiled),
|
|
|
|
|
Source = maps:get(contract_source, Compiled, <<>>),
|
|
|
|
|
VM = 1,
|
|
|
|
|
ABI = 1,
|
|
|
|
|
<<CTVersion:32>> = <<VM:16, ABI:16>>,
|
|
|
|
|
ContractCreateVersion = 1,
|
|
|
|
|
Type = contract_create_tx,
|
|
|
|
|
Fields =
|
|
|
|
|
[{owner_id, gmser_id:create(account, OwnerID)},
|
|
|
|
|
[{owner_id, aeser_id:create(account, OwnerID)},
|
|
|
|
|
{nonce, Nonce},
|
|
|
|
|
{code, Code},
|
|
|
|
|
{source, Source},
|
|
|
|
@ -1113,9 +1097,9 @@ contract_create5(OwnerID, Nonce, Amount, TTL, Gas, GasPrice, Compiled, CallData)
|
|
|
|
|
{gas_price, int},
|
|
|
|
|
{gas, int},
|
|
|
|
|
{call_data, binary}],
|
|
|
|
|
TXB = gmser_chain_objects:serialize(Type, ContractCreateVersion, Template, Fields),
|
|
|
|
|
TXB = aeser_chain_objects:serialize(Type, ContractCreateVersion, Template, Fields),
|
|
|
|
|
try
|
|
|
|
|
{ok, gmser_api_encoder:encode(transaction, TXB)}
|
|
|
|
|
{ok, aeser_api_encoder:encode(transaction, TXB)}
|
|
|
|
|
catch
|
|
|
|
|
error:Reason -> {error, Reason}
|
|
|
|
|
end.
|
|
|
|
@ -1127,11 +1111,14 @@ contract_create5(OwnerID, Nonce, Amount, TTL, Gas, GasPrice, Compiled, CallData)
|
|
|
|
|
ACI :: tuple(), % FIXME: Change to correct Sophia record
|
|
|
|
|
Reason :: file:posix() | bad_aci.
|
|
|
|
|
%% @doc
|
|
|
|
|
%% This function reads the contents of an .aci file.
|
|
|
|
|
%% ACI data is required for the contract call encoder to function properly.
|
|
|
|
|
%% This function reads the contents of an .aci file produced by AEL (the Gajumaru
|
|
|
|
|
%% Launcher). ACI data is required for the contract call encoder to function properly.
|
|
|
|
|
%% ACI data is can be generated and stored in JSON data, and the Sophia CLI tool
|
|
|
|
|
%% can perform this action. Unfortunately, JSON is not the way that ACI data is
|
|
|
|
|
%% represented internally, and here we need the actual native representation.
|
|
|
|
|
%% represented internally, and here we need the actual native representation. For
|
|
|
|
|
%% that reason Gajumaru's GUI launcher (AEL) has a "Developer's Workbench" tool
|
|
|
|
|
%% that can produce an .aci file from a contract's source code and store it in the
|
|
|
|
|
%% native Erlang format.
|
|
|
|
|
%%
|
|
|
|
|
%% ACI encding/decoding and contract call encoding is significantly complex enough that
|
|
|
|
|
%% this provides for a pretty large savings in complexity for this library, dramatically
|
|
|
|
@ -1285,7 +1272,7 @@ contract_call(CallerID, Gas, AACI, ConID, Fun, Args) ->
|
|
|
|
|
%% </li>
|
|
|
|
|
%% <li>
|
|
|
|
|
%% <b>GasPrice:</b>
|
|
|
|
|
%% This is a factor that is used calculate a value in pucks (the smallest unit of
|
|
|
|
|
%% This is a factor that is used calculate a value in aettos (the smallest unit of
|
|
|
|
|
%% Gajumaru's currency value) for the gas consumed. In times of high contention
|
|
|
|
|
%% in the mempool increasing the gas price increases the value of mining a given
|
|
|
|
|
%% transaction, thus making miners more likely to prioritize the high value ones.
|
|
|
|
@ -1343,7 +1330,7 @@ contract_call(CallerID, Nonce, Gas, GP, Amount, TTL, AACI, ConID, Fun, Args) ->
|
|
|
|
|
contract_call2(CallerID, Nonce, Gas, GasPrice, Amount, TTL, ConID, CallData) ->
|
|
|
|
|
CallerBin = unicode:characters_to_binary(CallerID),
|
|
|
|
|
try
|
|
|
|
|
{account_pubkey, PK} = gmser_api_encoder:decode(CallerBin),
|
|
|
|
|
{account_pubkey, PK} = aeser_api_encoder:decode(CallerBin),
|
|
|
|
|
contract_call3(PK, Nonce, Gas, GasPrice, Amount, TTL, ConID, CallData)
|
|
|
|
|
catch
|
|
|
|
|
Error:Reason -> {Error, Reason}
|
|
|
|
@ -1352,7 +1339,7 @@ contract_call2(CallerID, Nonce, Gas, GasPrice, Amount, TTL, ConID, CallData) ->
|
|
|
|
|
contract_call3(PK, Nonce, Gas, GasPrice, Amount, TTL, ConID, CallData) ->
|
|
|
|
|
ConBin = unicode:characters_to_binary(ConID),
|
|
|
|
|
try
|
|
|
|
|
{contract_pubkey, CK} = gmser_api_encoder:decode(ConBin),
|
|
|
|
|
{contract_pubkey, CK} = aeser_api_encoder:decode(ConBin),
|
|
|
|
|
contract_call4(PK, Nonce, Gas, GasPrice, Amount, TTL, CK, CallData)
|
|
|
|
|
catch
|
|
|
|
|
Error:Reason -> {Error, Reason}
|
|
|
|
@ -1363,9 +1350,9 @@ contract_call4(PK, Nonce, Gas, GasPrice, Amount, TTL, CK, CallData) ->
|
|
|
|
|
CallVersion = 1,
|
|
|
|
|
Type = contract_call_tx,
|
|
|
|
|
Fields =
|
|
|
|
|
[{caller_id, gmser_id:create(account, PK)},
|
|
|
|
|
[{caller_id, aeser_id:create(account, PK)},
|
|
|
|
|
{nonce, Nonce},
|
|
|
|
|
{contract_id, gmser_id:create(contract, CK)},
|
|
|
|
|
{contract_id, aeser_id:create(contract, CK)},
|
|
|
|
|
{abi_version, ABI},
|
|
|
|
|
{ttl, TTL},
|
|
|
|
|
{amount, Amount},
|
|
|
|
@ -1382,9 +1369,9 @@ contract_call4(PK, Nonce, Gas, GasPrice, Amount, TTL, CK, CallData) ->
|
|
|
|
|
{gas_price, int},
|
|
|
|
|
{gas, int},
|
|
|
|
|
{call_data, binary}],
|
|
|
|
|
TXB = gmser_chain_objects:serialize(Type, CallVersion, Template, Fields),
|
|
|
|
|
TXB = aeser_chain_objects:serialize(Type, CallVersion, Template, Fields),
|
|
|
|
|
try
|
|
|
|
|
{ok, gmser_api_encoder:encode(transaction, TXB)}
|
|
|
|
|
{ok, aeser_api_encoder:encode(transaction, TXB)}
|
|
|
|
|
catch
|
|
|
|
|
error:Reason -> {error, Reason}
|
|
|
|
|
end.
|
|
|
|
@ -1399,7 +1386,7 @@ contract_call4(PK, Nonce, Gas, GasPrice, Amount, TTL, CK, CallData) ->
|
|
|
|
|
%% of calldata
|
|
|
|
|
|
|
|
|
|
prepare_contract(File) ->
|
|
|
|
|
case so_compiler:file(File, [{aci, json}]) of
|
|
|
|
|
case aeso_compiler:file(File, [{aci, json}]) of
|
|
|
|
|
{ok, #{aci := ACI}} -> {ok, prepare_aaci(ACI)};
|
|
|
|
|
Error -> Error
|
|
|
|
|
end.
|
|
|
|
@ -1535,7 +1522,7 @@ opaque_type_name(Name) -> binary_to_list(Name).
|
|
|
|
|
|
|
|
|
|
% Type preparation has two goals. First, we need a data structure that can be
|
|
|
|
|
% traversed quickly, to take sophia-esque erlang expressions and turn them into
|
|
|
|
|
% fate-esque erlang expressions that gmbytecode can serialize. Second, we need
|
|
|
|
|
% fate-esque erlang expressions that aebytecode can serialize. Second, we need
|
|
|
|
|
% partially substituted names, so that error messages can be generated for why
|
|
|
|
|
% "foobar" is not valid as the third field of a `bazquux`, because the third
|
|
|
|
|
% field is supposed to be `option(integer)`, not `string`.
|
|
|
|
@ -1549,7 +1536,7 @@ opaque_type_name(Name) -> binary_to_list(Name).
|
|
|
|
|
% {record, [{Name, Type}]} expression that can be used in actual Sophia->FATE
|
|
|
|
|
% coercion. The type sub-expressions in these dereferenced types will each be
|
|
|
|
|
% fully annotated as well, i.e. they will each contain *all three* of the above
|
|
|
|
|
% representations, so that coercion of subexpressions remains fast AND
|
|
|
|
|
% representations, so that coercion of subexpressions remains fast and
|
|
|
|
|
% informative.
|
|
|
|
|
%
|
|
|
|
|
% In a lot of cases the opaque type given will already be normalized, in which
|
|
|
|
@ -1787,7 +1774,7 @@ coerce({O, N, integer}, S, to_fate) when is_list(S) ->
|
|
|
|
|
end;
|
|
|
|
|
coerce({O, N, address}, S, to_fate) ->
|
|
|
|
|
try
|
|
|
|
|
case gmser_api_encoder:decode(unicode:characters_to_binary(S)) of
|
|
|
|
|
case aeser_api_encoder:decode(unicode:characters_to_binary(S)) of
|
|
|
|
|
{account_pubkey, Key} -> {ok, {address, Key}};
|
|
|
|
|
_ -> single_error({invalid, O, N, S})
|
|
|
|
|
end
|
|
|
|
@ -1795,11 +1782,11 @@ coerce({O, N, address}, S, to_fate) ->
|
|
|
|
|
error:_ -> single_error({invalid, O, N, S})
|
|
|
|
|
end;
|
|
|
|
|
coerce({_, _, address}, {address, Bin}, from_fate) ->
|
|
|
|
|
Address = gmser_api_encoder:encode(account_pubkey, Bin),
|
|
|
|
|
Address = aeser_api_encoder:encode(account_pubkey, Bin),
|
|
|
|
|
{ok, unicode:characters_to_list(Address)};
|
|
|
|
|
coerce({O, N, contract}, S, to_fate) ->
|
|
|
|
|
try
|
|
|
|
|
case gmser_api_encoder:decode(unicode:characters_to_binary(S)) of
|
|
|
|
|
case aeser_api_encoder:decode(unicode:characters_to_binary(S)) of
|
|
|
|
|
{contract_pubkey, Key} -> {ok, {contract, Key}};
|
|
|
|
|
_ -> single_error({invalid, O, N, S})
|
|
|
|
|
end
|
|
|
|
@ -1807,7 +1794,7 @@ coerce({O, N, contract}, S, to_fate) ->
|
|
|
|
|
error:_ -> single_error({invalid, O, N, S})
|
|
|
|
|
end;
|
|
|
|
|
coerce({_, _, contract}, {contract, Bin}, from_fate) ->
|
|
|
|
|
Address = gmser_api_encoder:encode(contract_pubkey, Bin),
|
|
|
|
|
Address = aeser_api_encoder:encode(contract_pubkey, Bin),
|
|
|
|
|
{ok, unicode:characters_to_list(Address)};
|
|
|
|
|
coerce({_, _, boolean}, true, _) ->
|
|
|
|
|
{ok, true};
|
|
|
|
@ -2074,7 +2061,8 @@ aaci_lookup_spec({aaci, _, FunDefs, _}, Fun) ->
|
|
|
|
|
%% @doc
|
|
|
|
|
%% This function always returns 1,000,000,000 in the current version.
|
|
|
|
|
%%
|
|
|
|
|
%% This is the minimum gas price returned by aec_tx_pool:minimum_miner_gas_price()
|
|
|
|
|
%% This is the minimum gas price returned by aec_tx_pool:minimum_miner_gas_price(),
|
|
|
|
|
%% (the default set in aeternity_config_schema.json).
|
|
|
|
|
%%
|
|
|
|
|
%% Surely there can be some more nuance to this, but until a "gas station" type
|
|
|
|
|
%% market/chain survey service exists we will use this naive value as a default
|
|
|
|
@ -2088,10 +2076,16 @@ min_gas_price() ->
|
|
|
|
|
|
|
|
|
|
-spec min_gas() -> integer().
|
|
|
|
|
%% @doc
|
|
|
|
|
%% This function always returns 200,000 in the current version.
|
|
|
|
|
%% This function always returns 20,000 in the current version.
|
|
|
|
|
%%
|
|
|
|
|
%% There is no actual minimum gas price, but this figure provides a lower limit toward
|
|
|
|
|
%% successful completion of general contract calls while not too severely limiting the
|
|
|
|
|
%% number of TXs that may appear in a single microblock based on the per-block gas
|
|
|
|
|
%% maximum (6,000,000 / 20,000 = 300 TXs in a microblock -- which at the moment seems
|
|
|
|
|
%% like plenty).
|
|
|
|
|
|
|
|
|
|
min_gas() ->
|
|
|
|
|
200000.
|
|
|
|
|
20000.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
encode_call_data({aaci, _ContractName, FunDefs, _TypeDefs}, Fun, Args) ->
|
|
|
|
@ -2102,7 +2096,7 @@ encode_call_data({aaci, _ContractName, FunDefs, _TypeDefs}, Fun, Args) ->
|
|
|
|
|
|
|
|
|
|
encode_call_data2(ArgDef, Fun, Args) ->
|
|
|
|
|
case coerce_bindings(ArgDef, Args, to_fate) of
|
|
|
|
|
{ok, Coerced} -> gmb_fate_abi:create_calldata(Fun, Coerced);
|
|
|
|
|
{ok, Coerced} -> aeb_fate_abi:create_calldata(Fun, Coerced);
|
|
|
|
|
Errors -> Errors
|
|
|
|
|
end.
|
|
|
|
|
|
|
|
|
@ -2122,7 +2116,7 @@ encode_call_data2(ArgDef, Fun, Args) ->
|
|
|
|
|
%% check failed before verification was able to pass or fail (bad key encoding or similar).
|
|
|
|
|
|
|
|
|
|
verify_signature(Sig, Message, PubKey) ->
|
|
|
|
|
case gmser_api_encoder:decode(PubKey) of
|
|
|
|
|
case aeser_api_encoder:decode(PubKey) of
|
|
|
|
|
{account_pubkey, PK} -> verify_signature2(Sig, Message, PK);
|
|
|
|
|
Other -> {error, {bad_key, Other}}
|
|
|
|
|
end.
|
|
|
|
@ -2132,7 +2126,13 @@ verify_signature2(Sig, Message, PK) ->
|
|
|
|
|
% the hash is what gets signed in order to protect
|
|
|
|
|
% the user from accidentally signing a transaction disguised as a message.
|
|
|
|
|
%
|
|
|
|
|
% Salt the message then hash with blake2b.
|
|
|
|
|
% Salt the message then hash with blake2b. See:
|
|
|
|
|
% 1. Erlang Blake2 blake2b/2 function:
|
|
|
|
|
% https://gitlab.com/ioecs/eblake2/blob/60a079f00d72d1bfcc25de8e6996d28f912db3fd/src/eblake2.erl#L23-L25
|
|
|
|
|
% 2. SDK salting step:
|
|
|
|
|
% https://gitlab.com/ioecs/aepp-sdk-js/blob/370f1e30064ad0239ba59931908d9aba0a2e86b6/src/utils/crypto.ts#L171-L175
|
|
|
|
|
% 3. SDK hashing:
|
|
|
|
|
% https://gitlab.com/ioecs/aepp-sdk-js/blob/370f1e30064ad0239ba59931908d9aba0a2e86b6/src/utils/crypto.ts#L83-L85
|
|
|
|
|
Prefix = <<"Gajumaru Signed Message:\n">>,
|
|
|
|
|
{ok, PSize} = vencode(byte_size(Prefix)),
|
|
|
|
|
{ok, MSize} = vencode(byte_size(Message)),
|
|
|
|
@ -2283,7 +2283,7 @@ coerce_record_test() ->
|
|
|
|
|
%%% Complex AACI paramter and namespace tests
|
|
|
|
|
|
|
|
|
|
aaci_from_string(String) ->
|
|
|
|
|
case so_compiler:from_string(String, [{aci, json}]) of
|
|
|
|
|
case aeso_compiler:from_string(String, [{aci, json}]) of
|
|
|
|
|
{ok, #{aci := ACI}} -> {ok, prepare_aaci(ACI)};
|
|
|
|
|
Error -> Error
|
|
|
|
|
end.
|
|
|
|
|