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
|
||||
|
||||
-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).
|
||||
|
||||
|
||||
|
194
src/hz.erl
194
src/hz.erl
@ -4,24 +4,21 @@
|
||||
%%% This module is the high-level interface to the Gajumaru blockchain system.
|
||||
%%% The interface is split into three main sections:
|
||||
%%% - Get/Set admin functions
|
||||
%%% - AE node JSON query interface functions
|
||||
%%% - AE contract call and serialization interface functions
|
||||
%%% - Node JSON query interface functions
|
||||
%%% - Contract call and serialization interface functions
|
||||
%%%
|
||||
%%% 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
|
||||
%%% queries to the blockchain (usually you will run these nodes in your own back end).
|
||||
%%% "network ID" and list of addresses of nodes you want to use for answering
|
||||
%%% queries to the blockchain.
|
||||
%%%
|
||||
%%% The JSON query interface functions are the blockchain query functions themselves
|
||||
%%% which are translated to network queries and return Erlang messages as responses.
|
||||
%%%
|
||||
%%% 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
|
||||
%%% that an Gajumaru compatible wallet, SDK or (in the case of a web service) in-page
|
||||
%%% 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.
|
||||
%%% that a Gajumaru compatible wallet or library can sign and submit to a Gajumaru node.
|
||||
%%%
|
||||
%%% This module also includes the standard OTP "application" interface and start/stop
|
||||
%%% This module does not implement the OTP application behavior.
|
||||
%%% helper functions.
|
||||
%%% @end
|
||||
|
||||
@ -37,7 +34,7 @@
|
||||
tls/0, tls/1,
|
||||
timeout/0, timeout/1]).
|
||||
|
||||
% AE node JSON query interface functions
|
||||
% 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,
|
||||
@ -53,18 +50,16 @@
|
||||
post_tx/1,
|
||||
contract/1, contract_code/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]).
|
||||
|
||||
% AE contract call and serialization interface functions
|
||||
% Contract call and serialization interface functions
|
||||
-export([read_aci/1,
|
||||
min_gas/0,
|
||||
min_gas_price/0,
|
||||
min_fee/0,
|
||||
contract_create/3,
|
||||
contract_create/8,
|
||||
prepare_contract/1,
|
||||
@ -154,7 +149,6 @@
|
||||
% "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(),
|
||||
@ -646,7 +640,7 @@ dry_run(TX, Accounts, KBHash) ->
|
||||
txs => [#{tx => TXB}],
|
||||
tx_events => true},
|
||||
JSON = zj:binary_encode(DryData),
|
||||
request("/v3/dry-run", JSON).
|
||||
request("/v3/dry_run", JSON).
|
||||
|
||||
-spec decode_bytearray_fate(EncodedStr) -> {ok, Result} | {error, Reason}
|
||||
when EncodedStr :: binary() | string(),
|
||||
@ -718,15 +712,17 @@ tx_info(ID) ->
|
||||
result(request(["/v3/transactions/", ID, "/info"])).
|
||||
|
||||
-spec post_tx(Data) -> {ok, Result} | {error, Reason}
|
||||
when Data :: term(), % FIXME
|
||||
when Data :: string() | binary(),
|
||||
Result :: term(), % FIXME
|
||||
Reason :: chain_error() | string().
|
||||
%% @doc
|
||||
%% Post a transaction to the chain.
|
||||
|
||||
post_tx(Data) ->
|
||||
post_tx(Data) when is_binary(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}
|
||||
@ -864,11 +860,12 @@ contract_create(CreatorID, Path, InitArgs) ->
|
||||
case next_nonce(CreatorID) of
|
||||
{ok, Nonce} ->
|
||||
Amount = 0,
|
||||
Gas = 100000,
|
||||
{ok, Height} = top_height(),
|
||||
TTL = Height + 262980,
|
||||
Gas = 500000,
|
||||
GasPrice = min_gas_price(),
|
||||
Fee = min_fee(),
|
||||
contract_create(CreatorID, Nonce,
|
||||
Amount, Gas, GasPrice, Fee,
|
||||
Amount, TTL, Gas, GasPrice,
|
||||
Path, InitArgs);
|
||||
Error ->
|
||||
Error
|
||||
@ -876,14 +873,14 @@ contract_create(CreatorID, Path, InitArgs) ->
|
||||
|
||||
|
||||
-spec contract_create(CreatorID, Nonce,
|
||||
Amount, Gas, GasPrice, Fee,
|
||||
Amount, TTL, Gas, GasPrice,
|
||||
Path, InitArgs) -> Result
|
||||
when CreatorID :: pubkey(),
|
||||
Nonce :: pos_integer(),
|
||||
Amount :: non_neg_integer(),
|
||||
TTL :: pos_integer(),
|
||||
Gas :: pos_integer(),
|
||||
GasPrice :: pos_integer(),
|
||||
Fee :: non_neg_integer(),
|
||||
Path :: file:filename(),
|
||||
InitArgs :: [string()],
|
||||
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
|
||||
%% in the case of calls related to contract-governed payment systems.
|
||||
%% </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>
|
||||
%% <b>Gas:</b>
|
||||
%% 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.
|
||||
%% </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>
|
||||
%% 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
|
||||
@ -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
|
||||
%% trying to form a contract call.
|
||||
|
||||
contract_create(CreatorID, Nonce,
|
||||
Amount, Gas, GasPrice, Fee,
|
||||
Path, InitArgs) ->
|
||||
case aeso_compiler:file(Path, [{aci, json}]) of
|
||||
{ok, Compiled} ->
|
||||
contract_create2(CreatorID, Nonce,
|
||||
Amount, Gas, GasPrice, Fee,
|
||||
Compiled, InitArgs);
|
||||
contract_create(CreatorID, Nonce, Amount, TTL, Gas, GasPrice, Path, InitArgs) ->
|
||||
case file:read_file(Path) of
|
||||
{ok, Source} ->
|
||||
Dir = filename:dirname(Path),
|
||||
{ok, CWD} = file:get_cwd(),
|
||||
SrcDir = aeso_utils:canonical_dir(Path),
|
||||
Options =
|
||||
[{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
|
||||
end.
|
||||
|
||||
contract_create2(CreatorID, Nonce,
|
||||
Amount, Gas, GasPrice, Fee,
|
||||
Compiled, InitArgs) ->
|
||||
contract_create2(CreatorID, Nonce, Amount, TTL, Gas, GasPrice, Source, Options, InitArgs) ->
|
||||
case aeso_compiler:from_string(Source, Options) of
|
||||
{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)),
|
||||
case encode_call_data(AACI, "init", InitArgs) of
|
||||
{ok, CallData} ->
|
||||
contract_create3(CreatorID, Nonce,
|
||||
Amount, Gas, GasPrice, Fee,
|
||||
Compiled, CallData);
|
||||
contract_create4(CreatorID, Nonce, Amount, TTL, Gas, GasPrice,
|
||||
Source, Compiled, CallData);
|
||||
Error ->
|
||||
Error
|
||||
end.
|
||||
|
||||
contract_create3(CreatorID, Nonce,
|
||||
Amount, Gas, GasPrice, Fee,
|
||||
Compiled, CallData) ->
|
||||
contract_create4(CreatorID, Nonce, Amount, TTL, Gas, GasPrice, Source, Compiled, CallData) ->
|
||||
PK = unicode:characters_to_binary(CreatorID),
|
||||
try
|
||||
{account_pubkey, OwnerID} = aeser_api_encoder:decode(PK),
|
||||
contract_create4(OwnerID, Nonce,
|
||||
Amount, Gas, GasPrice, Fee,
|
||||
Compiled, CallData)
|
||||
contract_create5(OwnerID, Nonce, Amount, TTL, Gas, GasPrice, Source, Compiled, CallData)
|
||||
catch
|
||||
Error:Reason -> {Error, Reason}
|
||||
end.
|
||||
|
||||
contract_create4(OwnerID, Nonce,
|
||||
Amount, Gas, GasPrice, Fee,
|
||||
Compiled, CallData) ->
|
||||
contract_create5(OwnerID, Nonce, Amount, TTL, Gas, GasPrice, Source, Compiled, CallData) ->
|
||||
Code = aeser_contract_code:serialize(Compiled),
|
||||
VM = 7,
|
||||
ABI = 3,
|
||||
VM = 1,
|
||||
ABI = 1,
|
||||
<<CTVersion:32>> = <<VM:16, ABI:16>>,
|
||||
ContractCreateVersion = 1,
|
||||
TTL = 0,
|
||||
Type = contract_create_tx,
|
||||
Fields =
|
||||
[{owner_id, aeser_id:create(account, OwnerID)},
|
||||
{nonce, Nonce},
|
||||
{code, Code},
|
||||
{source, Source},
|
||||
{ct_version, CTVersion},
|
||||
{fee, Fee},
|
||||
{ttl, TTL},
|
||||
{deposit, 0},
|
||||
{amount, Amount},
|
||||
{gas, Gas},
|
||||
{gas_price, GasPrice},
|
||||
{gas, Gas},
|
||||
{call_data, CallData}],
|
||||
Template =
|
||||
[{owner_id, id},
|
||||
{nonce, int},
|
||||
{code, binary},
|
||||
{source, binary},
|
||||
{ct_version, int},
|
||||
{fee, int},
|
||||
{ttl, int},
|
||||
{deposit, int},
|
||||
{amount, int},
|
||||
{gas, int},
|
||||
{gas_price, int},
|
||||
{gas, int},
|
||||
{call_data, binary}],
|
||||
TXB = aeser_chain_objects:serialize(Type, ContractCreateVersion, Template, Fields),
|
||||
try
|
||||
@ -1121,9 +1121,9 @@ read_aci(Path) ->
|
||||
CallTX :: binary(),
|
||||
Reason :: term().
|
||||
%% @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!).
|
||||
%% 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.
|
||||
%%
|
||||
%% 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} ->
|
||||
Gas = min_gas(),
|
||||
GasPrice = min_gas_price(),
|
||||
Fee = min_fee(),
|
||||
Amount = 0,
|
||||
{ok, Height} = top_height(),
|
||||
TTL = Height + 262980,
|
||||
contract_call(CallerID, Nonce,
|
||||
Gas, GasPrice, Fee, Amount,
|
||||
Gas, GasPrice, Amount, TTL,
|
||||
AACI, ConID, Fun, Args);
|
||||
Error ->
|
||||
Error
|
||||
@ -1165,10 +1166,11 @@ contract_call(CallerID, Gas, AACI, ConID, Fun, Args) ->
|
||||
case next_nonce(CallerID) of
|
||||
{ok, Nonce} ->
|
||||
GasPrice = min_gas_price(),
|
||||
Fee = min_fee(),
|
||||
Amount = 0,
|
||||
{ok, Height} = top_height(),
|
||||
TTL = Height + 262980,
|
||||
contract_call(CallerID, Nonce,
|
||||
Gas, GasPrice, Fee, Amount,
|
||||
Gas, GasPrice, Amount, TTL,
|
||||
AACI, ConID, Fun, Args);
|
||||
Error ->
|
||||
Error
|
||||
@ -1176,14 +1178,14 @@ contract_call(CallerID, Gas, AACI, ConID, Fun, Args) ->
|
||||
|
||||
|
||||
-spec contract_call(CallerID, Nonce,
|
||||
Gas, GasPrice, Fee, Amount,
|
||||
Gas, GasPrice, Amount, TTL,
|
||||
AACI, ConID, Fun, Args) -> Result
|
||||
when CallerID :: unicode:chardata(),
|
||||
Nonce :: pos_integer(),
|
||||
Gas :: pos_integer(),
|
||||
GasPrice :: pos_integer(),
|
||||
Fee :: non_neg_integer(),
|
||||
Amount :: non_neg_integer(),
|
||||
TTL :: pos_integer(),
|
||||
AACI :: map(),
|
||||
ConID :: unicode:chardata(),
|
||||
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.
|
||||
%% </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>
|
||||
%% 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
|
||||
@ -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
|
||||
%% 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
|
||||
{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
|
||||
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),
|
||||
try
|
||||
{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
|
||||
Error:Reason -> {Error, Reason}
|
||||
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),
|
||||
try
|
||||
{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
|
||||
Error:Reason -> {Error, Reason}
|
||||
end.
|
||||
|
||||
contract_call4(PK, Nonce, Gas, GasPrice, Fee, Amount, CK, CallData) ->
|
||||
ABI = 3,
|
||||
TTL = 0,
|
||||
contract_call4(PK, Nonce, Gas, GasPrice, Amount, TTL, CK, CallData) ->
|
||||
ABI = 1,
|
||||
CallVersion = 1,
|
||||
Type = contract_call_tx,
|
||||
Fields =
|
||||
@ -1334,22 +1328,20 @@ contract_call4(PK, Nonce, Gas, GasPrice, Fee, Amount, CK, CallData) ->
|
||||
{nonce, Nonce},
|
||||
{contract_id, aeser_id:create(contract, CK)},
|
||||
{abi_version, ABI},
|
||||
{fee, Fee},
|
||||
{ttl, TTL},
|
||||
{amount, Amount},
|
||||
{gas, Gas},
|
||||
{gas_price, GasPrice},
|
||||
{gas, Gas},
|
||||
{call_data, CallData}],
|
||||
Template =
|
||||
[{caller_id, id},
|
||||
{nonce, int},
|
||||
{contract_id, id},
|
||||
{abi_version, int},
|
||||
{fee, int},
|
||||
{ttl, int},
|
||||
{amount, int},
|
||||
{gas, int},
|
||||
{gas_price, int},
|
||||
{gas, int},
|
||||
{call_data, binary}],
|
||||
TXB = aeser_chain_objects:serialize(Type, CallVersion, Template, Fields),
|
||||
try
|
||||
@ -1988,7 +1980,7 @@ aaci_lookup_spec({aaci, _, FunDefs, _}, Fun) ->
|
||||
%% contention becomes an issue.
|
||||
|
||||
min_gas_price() ->
|
||||
1000000000.
|
||||
1_000_000_000.
|
||||
|
||||
|
||||
-spec min_gas() -> integer().
|
||||
@ -2005,19 +1997,6 @@ min_gas() ->
|
||||
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) ->
|
||||
case maps:find(Fun, FunDefs) of
|
||||
{ok, {ArgDef, _ResultDef}} -> encode_call_data2(ArgDef, Fun, Args);
|
||||
@ -2052,10 +2031,9 @@ verify_signature(Sig, Message, PubKey) ->
|
||||
end.
|
||||
|
||||
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.
|
||||
% In order to verify the signature, we have to duplicate superhero's
|
||||
% salt/hash procedure here.
|
||||
%
|
||||
% Salt the message then hash with blake2b. See:
|
||||
% 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
|
||||
% 3. SDK hashing:
|
||||
% 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">>, % TODO: Switch the prefix after we kill Superhero
|
||||
Prefix = <<"Gajumaru 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)>>,
|
||||
% Signature = <<(binary_to_integer(Sig, 16)):(64 * 8)>>,
|
||||
Signature = base64:decode(Sig),
|
||||
Result = ecu_eddsa:sign_verify_detached(Signature, Hashed, PK),
|
||||
{ok, Result}.
|
||||
|
||||
|
@ -1,5 +1,3 @@
|
||||
%%% @private
|
||||
|
||||
-module(hz_fetcher).
|
||||
-vsn("0.4.1").
|
||||
-author("Craig Everett <ceverett@tsuriai.jp>").
|
||||
|
Loading…
x
Reference in New Issue
Block a user